  /* ---- work gallery ----
     A shared component, loaded after a page's own stylesheet. Any section that
     wants a strip of job photos gets the same markup and the same behaviour:
     copper today, gutters and stairs and floors when their photos arrive.

     The track is a real scroll container with snap points, so it works with a
     finger, a trackpad, the arrow keys and the two buttons - and it still works
     with JavaScript switched off, which is the reason it is not a transform
     slider. js/gallery.js only adds the buttons' behaviour and the lightbox.

     It depends on the page stylesheet for the tokens (--navy-lift, --navy-edge,
     --steel, --sign, --shield, --stripe, --display, --data) and for .shell. */

  .gal{position:relative}

  /* Scroll padding, not padding: the gutter has to come off the SNAP position
     too, or the first card snaps flush to the edge of the screen while every
     other one sits inside the shell. */
  .gal-track{
    /* One frame size for the whole row, declared once. The cards are different
       shapes - a landscape photograph, a portrait phone clip - and what keeps
       the row level is that they share a HEIGHT, not an aspect ratio. */
    --gal-w:clamp(260px,32vw,420px);
    --gal-h:calc(var(--gal-w) * 3 / 4);
    display:flex;gap:clamp(12px,1.6vw,20px);
    overflow-x:auto;overscroll-behavior-x:contain;
    scroll-snap-type:x mandatory;
    scroll-padding-left:2px;
    padding-bottom:6px;
    /* A thin bar, kept rather than hidden: on a phone it is the only thing that
       shows how much of the row is left. Chrome supports scrollbar-width now, so
       one declaration covers every engine and the old ::-webkit-scrollbar
       override would only have made the two disagree. */
    scrollbar-width:thin;scrollbar-color:var(--navy-edge) transparent;
  }

  .gal-item{
    margin:0;flex:0 0 auto;scroll-snap-align:start;
    width:var(--gal-w);
    background:var(--navy-lift);border:1px solid var(--navy-edge);
    border-radius:4px;overflow:hidden;
  }

  /* A fixed frame, because these are phone photos from a dozen different jobs
     and no two will share an aspect ratio. Left to themselves they would make
     the row lurch card by card. 4:3 is the shape most of them arrive in.

     The height is set outright rather than through aspect-ratio. The generator
     writes the real width and height onto the tag so the row does not jump
     while the photos load, and those attributes arrive as a presentational
     height that silently beats aspect-ratio - the first build rendered every
     card at the photo's full 1200px height because of it. An explicit height in
     the stylesheet wins, and it is the same value a video card uses. */
  .gal-item img{
    display:block;width:100%;height:var(--gal-h);object-fit:cover;
    background:var(--navy);
    transition:transform .4s cubic-bezier(.16,1,.3,1);
  }
  /* ---- a video card ----
     Same frame as a photograph, so the row does not lurch when one lands in the
     middle of it. The clip plays where it sits: a video already carries its own
     controls, and lifting it into the lightbox would mean rebuilding every one
     of them. object-fit:cover on a video needs the height pinned the same way
     the image does - without it the element falls back to its intrinsic size. */
  .gal-video{width:auto}
  .gal-video video{
    display:block;height:var(--gal-h);width:auto;max-width:var(--gal-w);
    background:#000;
  }

  .gal-shot{display:block;width:100%;padding:0;border:0;background:none;cursor:zoom-in}
  .gal-shot:hover img{transform:scale(1.03)}

  .gal-item figcaption{
    padding:14px 16px 16px;
    font-family:var(--data);font-size:14px;letter-spacing:.06em;
    text-transform:uppercase;color:var(--steel);
  }

  /* ---- the controls ---- */
  .gal-bar{
    display:flex;align-items:center;gap:14px;
    margin-top:clamp(16px,2vw,22px);
  }
  .gal-btn{
    width:46px;height:46px;flex:none;
    display:inline-flex;align-items:center;justify-content:center;
    border:1px solid var(--navy-edge);border-radius:999px;
    background:transparent;color:var(--sign);cursor:pointer;
    transition:border-color .2s ease,background-color .2s ease,opacity .2s ease;
  }
  .gal-btn:hover:not(:disabled){border-color:var(--steel);background:var(--navy-lift)}
  .gal-btn:disabled{opacity:.32;cursor:default}
  .gal-btn svg{width:19px;height:19px}
  .gal-count{
    font-family:var(--data);font-size:13px;font-weight:600;
    letter-spacing:.16em;text-transform:uppercase;color:var(--steel);
  }

  /* ---- no photos yet ----
     The empty state is the DEFAULT, not something JavaScript switches on: the
     track ships empty and fills up when photos land in img/work/<section>/.
     :has keeps it in CSS; js/gallery.js sets .is-empty as well for anything
     that does not support it. */
  .gal-empty{
    display:none;
    padding:clamp(26px,4vw,38px);
    border:1px dashed var(--navy-edge);border-radius:4px;
    background:var(--navy-lift);color:#A6B0C6;font-size:15.5px;
  }
  .gal:has(.gal-track:empty) .gal-empty,
  .gal.is-empty .gal-empty{display:block}
  .gal:has(.gal-track:empty) .gal-track,
  .gal:has(.gal-track:empty) .gal-bar,
  .gal.is-empty .gal-track,
  .gal.is-empty .gal-bar{display:none}

  /* ---- lightbox ----
     Built by js/gallery.js, so everything here is for a dialog that only exists
     once the script has run. ::backdrop is the browser's own layer - no extra
     element, and it cannot be scrolled behind. */
  .gal-lb{
    border:0;padding:0;background:transparent;
    max-width:min(1200px,94vw);max-height:92vh;
    color:var(--sign);
  }
  .gal-lb::backdrop{background:rgba(6,11,26,.92)}
  .gal-lb img{
    display:block;max-width:100%;max-height:78vh;
    width:auto;height:auto;margin:0 auto;border-radius:3px;
  }
  .gal-lb-cap{
    margin-top:14px;text-align:center;
    font-family:var(--data);font-size:14px;letter-spacing:.08em;
    text-transform:uppercase;color:var(--steel);
  }
  .gal-lb-bar{display:flex;justify-content:center;align-items:center;gap:14px;margin-top:12px}
  .gal-lb-close{
    position:absolute;top:10px;right:10px;
    width:44px;height:44px;border-radius:999px;
    border:1px solid rgba(255,255,255,.22);background:rgba(12,21,48,.7);
    color:var(--sign);cursor:pointer;display:inline-flex;
    align-items:center;justify-content:center;
  }
  .gal-lb-close svg{width:18px;height:18px}

  @media (max-width:640px){
    .gal-track{--gal-w:min(82vw,340px)}
    .gal-lb img{max-height:66vh}
  }

  /* The zoom on hover is decoration; the scroll itself is the content moving
     and stays. */
  @media (prefers-reduced-motion:reduce){
    .gal-item img,.gal-shot:hover img{transition:none;transform:none}
  }

  /* The hint sits at the far end of the bar, and goes away on a phone where
     there is no room for it beside the counter and no hover to explain. */
  .gal-hint{margin-left:auto;text-align:right}
  @media (max-width:640px){ .gal-hint{display:none} }
