/* =====================================================================
   STORY CRAFT — /projects/
   ---------------------------------------------------------------------
   Read in order. Sections are numbered and each does one job.

   01  Route base + the scroll system
   02  Header + shared utilities
   03  Gateway — shared
   04  Gateway — desktop (12-col editorial)
   05  Gateway — mobile (full-viewport chapter index)
   06  Scenes — shared
   07  Scenes — desktop
   08  Scenes — mobile
   09  Progress rail + scroll hint
   10  Category switcher + navigation sheet
   11  All Work index
   12  Reduced motion, no-JS, forced colours

   THE ONE RULE THIS FILE KEEPS: the browser owns scrolling. There is no
   wheel, touchmove or keydown interception anywhere in this route, no
   body locking outside the modal sheet, and no horizontal swipe
   dependency. Everything below is CSS Scroll Snap plus transforms and
   opacity — the same motion vocabulary the homepage already uses.
   ===================================================================== */


/* =====================================================================
   01  ROUTE BASE + SCROLL SYSTEM
   ---------------------------------------------------------------------
   Same architecture as the homepage: the ROOT element is the snap
   container. A wrapper with overflow-y:scroll would become the
   scrolling ancestor and silently break every position:sticky in here.

   Desktop is `proximity` deliberately — the brief asks for it and it is
   right: a trackpad flick across a long All Work index should not be
   yanked, and desktop scenes carry more reading than a phone screen.
   Mobile is `mandatory` + `scroll-snap-stop:always`, so one committed
   swipe is exactly one project and momentum can never skip a scene.

   Both are written by JS through the same overflow guard the homepage
   uses (see projects.js `guard`): if any scene ever measures taller
   than the viewport — long Lithuanian strings, 200% text — snapping
   relaxes so the middle of a scene can never become unreachable.
   ===================================================================== */
html{
  scroll-snap-type:y proximity;
  overscroll-behavior-y:none;
  -webkit-text-size-adjust:100%;
}
@media (max-width:860px){
  html{ scroll-snap-type:y mandatory; }
}

/* svh, and it must stay svh. dvh tracks the URL bar, so every scene
   would grow mid-swipe and the snap point would run away from the
   gesture that was aiming at it. */
.pj{
  min-block-size:100svh;
  scroll-snap-align:start;
  position:relative;
  display:flex;
  flex-direction:column;
}
@media (max-width:860px){
  .pj{ scroll-snap-stop:always; overflow-x:clip; }
}

/* The index is a reading surface, not a scene: it must never snap a
   half-read list off the screen. */
#allwork{ scroll-snap-align:none; scroll-snap-stop:normal; }

body{
  min-height:100svh;
  background:var(--powder-white);
  color:var(--serene-navy);
  font-family:var(--font-ui);
  font-weight:400;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
}


/* =====================================================================
   02  HEADER + SHARED UTILITIES  —  MOVED TO base.css
   ---------------------------------------------------------------------
   The header, .t-label, .vh, .skip and the focus rules are chrome for
   EVERY route outside the homepage, not just this one. They lived here
   until the first case-study route rendered completely unstyled, which
   is what a shared style sitting in a route-specific file looks like.
   ===================================================================== */


/* =====================================================================
   03  GATEWAY — SHARED
   ---------------------------------------------------------------------
   An editorial chapter index. Explicitly NOT a filter drawer, an
   accordion, a dashboard or a stack of cards: five typographic choices
   on the page's own background, separated by hairlines, numbered like
   chapters in a book.
   ===================================================================== */
.gw{
  padding-block:calc(var(--hdr) + clamp(1rem, 3vh, 2.4rem)) clamp(1.2rem, 4vh, 2.4rem);
  padding-inline:max(var(--pad), env(safe-area-inset-left)) max(var(--pad), env(safe-area-inset-right));
  justify-content:center;
}
.gw__eyebrow{ color:var(--navy-70); }

/* The proposition carries both visitor modes at once: "know what you
   need" and "want the mixed picture". Two sentences, not two UI modes. */
.gw__prop{
  font-family:var(--font-display); font-weight:400;
  font-size:clamp(1.65rem, 3.6vw, 3.1rem);
  line-height:1.06; letter-spacing:-.015em;
  margin-block:clamp(.7rem, 1.8vh, 1.1rem) 0;
  text-wrap:balance;
}
.gw__prop em{ font-style:italic; color:var(--caspian-blue); }
.gw__lede{
  color:var(--navy-70);
  font-size:clamp(.9rem, 1.05vw, 1rem);
  line-height:1.5;
  max-inline-size:34ch;
  margin-block:clamp(.6rem, 1.4vh, .9rem) 0;
}

/* -- the index ------------------------------------------------------- */
.gw__list{ list-style:none; margin:0; padding:0; }
.gw__item{ border-top:1px solid var(--rule); }
.gw__item:last-child{ border-bottom:1px solid var(--rule); }

.gw__link{
  display:grid;
  grid-template-columns:auto minmax(0,1fr) auto;
  align-items:baseline;
  column-gap:clamp(.75rem, 1.6vw, 1.4rem);
  padding-block:clamp(.8rem, 1.9vh, 1.25rem);
  min-height:44px;
  position:relative;
}
/* The wash is a pseudo-element so the hairlines above stay hairlines. */
.gw__link::before{
  content:''; position:absolute; inset:0 calc(-1 * clamp(.5rem, 1vw, 1rem));
  background:color-mix(in srgb, var(--serene-navy) 4%, transparent);
  opacity:0; transition:opacity .4s var(--ease-out-quart);
  pointer-events:none;
}
.gw__link:hover::before,
.gw__link:focus-visible::before{ opacity:1; }

.gw__n{ color:var(--navy-45); font-variant-numeric:tabular-nums; }
.gw__label{
  font-family:var(--font-display); font-weight:400;
  font-size:clamp(1.5rem, 2.9vw, 2.5rem);
  line-height:1.02; letter-spacing:-.015em;
  transition:transform .5s var(--ease-out-expo);
  transform-origin:left;
}
.gw__link:hover .gw__label,
.gw__link:focus-visible .gw__label{ transform:translateX(6px); }
.gw__sub{
  grid-column:2; grid-row:2;
  color:var(--navy-70);
  font-size:clamp(.78rem, .9vw, .88rem);
  line-height:1.4;
  margin-block:.3rem 0;
}
.gw__count{
  color:var(--navy-45);
  font-variant-numeric:tabular-nums;
  white-space:nowrap;
}
/* A chapter with nothing publishable in it must say so rather than
   spend a click. It stays visible — the scope is still information. */
.gw__link[aria-disabled="true"]{ pointer-events:none; }
.gw__link[aria-disabled="true"] .gw__label{ color:var(--navy-50); }
.gw__link[aria-disabled="true"] .gw__count{ font-style:italic; }


/* =====================================================================
   04  GATEWAY — DESKTOP (861px and up)
   ---------------------------------------------------------------------
   12-column editorial: proposition and index left, ONE large preview
   right. Focusing or hovering a chapter re-points the preview; only
   click/Enter commits the category. Hover must never navigate and must
   never leave the category changed behind the pointer.
   ===================================================================== */
@media (min-width:861px){
  .gw{
    display:grid;
    grid-template-columns:repeat(12, minmax(0,1fr));
    column-gap:var(--gap);
    align-content:center;
  }
  .gw__copy{ grid-column:1 / span 5; align-self:end; }
  .gw__nav { grid-column:1 / span 5; align-self:start; margin-top:clamp(1.2rem, 3vh, 2.2rem); }
  .gw__stage{
    grid-column:7 / span 6;
    grid-row:1 / span 2;
    align-self:center;
    position:relative;
  }

  /* One frame, fixed geometry. The picture inside changes; the box
     never moves, so re-pointing the preview cannot reflow the page. */
  /* 16:9, because every desktop poster is 16:9. A 4:3 frame cropped a
     quarter of the width off each preview. */
  .gw__frame{
    position:relative;
    aspect-ratio:16/9;
    border-radius:clamp(14px, 1vw, 20px);
    overflow:hidden;
    background:color-mix(in srgb, var(--serene-navy) 6%, var(--powder-white));
  }
  .gw__shot{
    position:absolute; inset:0;
    opacity:0;
    transition:opacity .5s var(--ease-out-quart), transform .6s var(--ease-out-expo);
    transform:scale(1.012);
  }
  .gw__shot[data-on]{ opacity:1; transform:none; }
  .gw__shot img{ width:100%; height:100%; object-fit:cover; }

  .gw__cap{
    display:flex; gap:.6rem; align-items:baseline;
    margin-top:.75rem;
    color:var(--navy-70);
    min-height:1.2em;                 /* reserved: no reflow on change */
  }
  .gw__capC{ color:var(--serene-navy); }
}

/* Wide desktop: hold the measure rather than letting the type sprawl. */
@media (min-width:1600px){
  .gw__copy, .gw__nav{ grid-column:1 / span 4; }
  .gw__stage{ grid-column:6 / span 7; }
}


/* =====================================================================
   05  GATEWAY — MOBILE (860px and below)
   ---------------------------------------------------------------------
   One viewport, type-led. No preview media here at all: five moving
   thumbnails is exactly the "load five videos" failure the brief warns
   about, and five still thumbnails turns the chapter index into the
   card stack it must not be. The evidence is one screen away.
   ===================================================================== */
@media (max-width:860px){
  .gw{ padding-bottom:max(clamp(1rem,3vh,1.6rem), env(safe-area-inset-bottom)); }
  .gw__stage{ display:none; }
  .gw__prop{ font-size:clamp(1.75rem, 8.2vw, 2.5rem); }
  .gw__lede{ max-inline-size:32ch; }
  .gw__nav{ margin-top:clamp(1rem, 3.2vh, 1.8rem); }
  .gw__link{
    grid-template-columns:auto minmax(0,1fr);
    padding-block:clamp(.55rem, 1.4vh, .8rem);
  }
  .gw__label{ font-size:clamp(1.35rem, 6.4vw, 1.85rem); }
  .gw__sub{ font-size:.78rem; margin-top:.22rem; }
  /* The count would push the label into two lines on a 360px screen,
     so on mobile it moves under the subline as part of the same row. */
  .gw__count{
    grid-column:2; grid-row:3;
    font-size:.66rem; letter-spacing:.1em; text-transform:uppercase;
    margin-top:.35rem;
  }
}
@media (max-width:380px){
  .gw__link{ column-gap:.6rem; }
  .gw__n{ font-size:.58rem; }
}

/* Short phones (360x640 and friends). The gateway overflowing is not
   just an aesthetic problem here: a snap section taller than the
   viewport forces the overflow guard to relax snapping for the WHOLE
   route, so every project scene downstream loses `mandatory` and the
   one-swipe-one-project rhythm goes with it. Tightening this section is
   what keeps the scenes crisp on small screens.

   The COUNT is what gets dropped, not the subline. The subline tells
   you what a chapter contains — without it nobody learns that "Tęstinis
   turinys" holds social and design work — while the count is secondary
   and is still shown on every row of the chapter sheet. */
@media (max-width:860px) and (max-height:730px){
  .gw{ padding-block:calc(var(--hdr) + .5rem) .8rem; }
  .gw__prop{ font-size:clamp(1.45rem, 6.6vw, 1.9rem); }
  .gw__lede{ font-size:.82rem; line-height:1.4; max-inline-size:38ch; }
  .gw__nav{ margin-top:.7rem; }
  .gw__link{ padding-block:.5rem; }
  .gw__label{ font-size:clamp(1.2rem, 5.4vw, 1.55rem); }
  .gw__sub{ font-size:.72rem; margin-top:.16rem; }
  .gw__count{ display:none; }
}
/* Shorter still: the lede's guidance is folded into the Featured row's
   own subline rather than dropped, so both visitor paths survive. */
@media (max-width:860px) and (max-height:600px){
  .gw__lede{ display:none; }
  .gw__prop{ font-size:1.35rem; }
  .gw__link{ padding-block:.42rem; }
}


/* =====================================================================
   06  SCENES — SHARED
   ---------------------------------------------------------------------
   One project owns one viewport. The whole visual surface is ONE link
   with no nested controls, so touch, mouse, Enter and a screen reader
   all reach the project the same way.

   Scenes are rendered ONCE per category into stable layers and toggled
   by attribute. Rebuilding DOM on a category change would flash empty
   content mid-transition; toggling cannot.
   ===================================================================== */
.pj__seq{ position:relative; }

.pj__scene{
  position:relative;
  overflow:hidden;
  isolation:isolate;
  background:color-mix(in srgb, var(--serene-navy) 8%, var(--powder-white));
}
.pj__link{
  position:absolute; inset:0;
  display:block;
  z-index:2;
}
/* Media --------------------------------------------------------------
   The poster and the teaser share geometry exactly, so the swap is
   invisible and there is no layout shift when the video arrives. */
.pj__media{ position:absolute; inset:0; z-index:0; }
.pj__media img,
.pj__media video{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover;
  object-position:var(--focal, 50% 50%);
}
.pj__media video{
  opacity:0;
  transition:opacity .55s var(--ease-out-quart);
  pointer-events:none;                  /* the anchor above owns input */
}
.pj__media video.is-live{ opacity:1; }

/* The gradient protects the copy from whatever the footage does. It is
   sized in svh rather than % so it does not grow with the scene. */
.pj__shade{
  position:absolute; inset:auto 0 0 0; z-index:1;
  block-size:min(62svh, 70%);
  background:linear-gradient(to top,
    color-mix(in srgb, var(--midnight-blue) 82%, transparent) 0%,
    color-mix(in srgb, var(--midnight-blue) 60%, transparent) 26%,
    color-mix(in srgb, var(--midnight-blue) 22%, transparent) 58%,
    transparent 100%);
  pointer-events:none;
}

.pj__copy{ position:relative; z-index:3; pointer-events:none; color:var(--powder-white); }
.pj__chapter{ color:color-mix(in srgb, var(--powder-white) 76%, transparent); }
.pj__title{
  font-family:var(--font-display); font-weight:400;
  line-height:1.02; letter-spacing:-.02em;
  margin-block:.35rem 0;
  text-wrap:balance;
}
.pj__meta{
  color:color-mix(in srgb, var(--powder-white) 80%, transparent);
  margin-block:.5rem 0;
  font-size:clamp(.8rem, .95vw, .92rem);
}
.pj__sum{
  color:color-mix(in srgb, var(--powder-white) 88%, transparent);
  margin-block:.55rem 0;
  line-height:1.45;
  font-size:clamp(.86rem, 1vw, .98rem);
}
/* The cue is decoration for a link that already covers the scene, so it
   is not a control and takes no pointer events or tab stop. */
.pj__cue{
  display:inline-flex; align-items:center; gap:.5rem;
  margin-block:clamp(.7rem, 1.6vh, 1rem) 0;
  color:var(--powder-white);
}
.pj__cueA{ width:16px; height:10px; overflow:visible; transition:transform .45s var(--ease-out-expo); }
.pj__link:hover ~ .pj__copy .pj__cueA,
.pj__link:focus-visible ~ .pj__copy .pj__cueA{ transform:translateX(5px); }
.pj__cue::after{
  content:''; position:absolute; left:0; bottom:-2px; height:1px; width:100%;
  background:currentColor; opacity:.35;
}
.pj__cue{ position:relative; }

/* Entrance: transforms and opacity only, small and directional. */
.pj__copy > *{
  opacity:0; transform:translateY(10px);
  transition:opacity .55s var(--ease-out-quart) calc(var(--i, 0) * 55ms),
             transform .6s var(--ease-out-expo)  calc(var(--i, 0) * 55ms);
}
.pj__scene[data-seen] .pj__copy > *{ opacity:1; transform:none; }


/* =====================================================================
   07  SCENES — DESKTOP (861px and up)
   ---------------------------------------------------------------------
   Deliberately NOT the slide-04 composition. Slide 04 is identity-left,
   rail-centre, media-right; this is media-left and dominant with a
   narrow reading column opposite. Same studio, different room.

   The media takes ~66% of the inline axis — inside the 60-72% the
   brief asks for — and is a real link to the case study.
   ===================================================================== */
@media (min-width:861px){
  .pj__scene{
    display:grid;
    grid-template-columns:minmax(0, 70fr) minmax(0, 30fr);
    column-gap:clamp(1.25rem, 2.4vw, 2.6rem);
    align-items:center;
    padding-block:calc(var(--hdr) + clamp(.6rem, 1.6vh, 1.2rem)) clamp(3rem, 7vh, 4.4rem);
    padding-inline:max(var(--pad), env(safe-area-inset-left))
                  calc(max(var(--pad), env(safe-area-inset-right)) + clamp(1.4rem, 2.6vw, 2.8rem));
    background:var(--powder-white);
    overflow:visible;
  }
  /* The media is a framed object on the page, not a full bleed: the
     light canvas is the brand, and a dark edge-to-edge scene would make
     this route look like somebody else's film portfolio.

     It keeps the FOOTAGE'S OWN ratio. Stretching a 16:9 teaser to fill
     a tall grid row cropped it to roughly 10:9 and threw away the sides
     of every frame — which is exactly the cinematography the scene is
     supposed to be evidence of. The box follows the media, never the
     other way round, and the height cap is what keeps the whole scene
     inside one viewport at short desktop heights. */
  .pj__media{
    position:relative; inset:auto;
    grid-column:1;
    aspect-ratio:var(--ar, 16/9);
    /* Width is capped by the HEIGHT budget times the ratio, not by a
       max-block-size: capping height alone lets the box stay full width,
       which silently breaks the aspect ratio and re-introduces the crop
       this whole rule exists to remove. `--arn` is the numeric ratio,
       written per scene from the media's own dimensions. */
    inline-size:min(100%, calc(min(74svh, 720px) * var(--arn, 1.7778)));
    margin-inline:auto;
    border-radius:clamp(14px, 1vw, 20px);
    overflow:hidden;
    background:color-mix(in srgb, var(--serene-navy) 6%, var(--powder-white));
  }
  .pj__link{ border-radius:clamp(14px, 1vw, 20px); }
  /* Copy sits on the page, so it returns to navy. The shade is only for
     copy that lies ON footage — here it would be decoration. */
  .pj__shade{ display:none; }
  .pj__copy{
    grid-column:2;
    color:var(--serene-navy);
    display:flex; flex-direction:column;
  }
  /* A hairline over the chapter label ties the column to the media's
     top edge, so the text block reads as placed rather than floating. */
  .pj__chapter{
    padding-top:clamp(.7rem, 1.6vh, 1rem);
    border-top:1px solid var(--rule);
  }
  .pj__chapter{ color:var(--navy-70); }
  .pj__title{ font-size:clamp(1.9rem, 3vw, 3rem); }
  .pj__meta,
  .pj__sum{ color:var(--navy-70); }
  .pj__sum{ max-inline-size:34ch; }
  .pj__cue{ color:var(--caspian-blue); align-self:flex-start; }

  /* The whole media surface is the link, so it carries the hover. */
  .pj__media img,
  .pj__media video{ transition:transform .7s var(--ease-out-expo); }
  .pj__scene:has(.pj__link:hover) .pj__media img,
  .pj__scene:has(.pj__link:hover) .pj__media video{ transform:scale(1.018); }
}

/* Between tablet and laptop the 34% column gets too narrow for the
   title, so the split relaxes before it breaks. */
@media (min-width:861px) and (max-width:1180px){
  .pj__scene{ grid-template-columns:minmax(0, 60fr) minmax(0, 40fr); }
  .pj__title{ font-size:clamp(1.6rem, 3.2vw, 2.2rem); }
}


/* =====================================================================
   08  SCENES — MOBILE (860px and below)
   ---------------------------------------------------------------------
   The reference rhythm, in Story Craft's identity: media owns the
   viewport, compact metadata sits low, position is shown on a rail.
   Full bleed here is right — a phone screen IS the frame.
   ===================================================================== */
@media (max-width:860px){
  .pj__scene{ display:block; }
  .pj__copy{
    position:absolute; z-index:3;
    inset:auto 0 0 0;
    padding-inline:max(var(--pad), env(safe-area-inset-left)) calc(max(var(--pad), env(safe-area-inset-right)) + 1.6rem);
    /* Clears the fixed switcher pill, which lives in the same bottom-left
       corner. Without this the summary and the pill overlap on every
       scene. 44px control + breathing room. */
    padding-bottom:calc(max(clamp(1.5rem, 5vh, 2.6rem), calc(env(safe-area-inset-bottom) + 1.1rem)) + 3.4rem);
  }
  .pj__title{ font-size:clamp(1.7rem, 8vw, 2.4rem); max-inline-size:14ch; }
  .pj__sum{ max-inline-size:30ch; }
  /* One line only on a phone: the summary is the case study's job. */
  .pj__sum{
    display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2;
    overflow:hidden;
  }
}
@media (max-width:360px){
  .pj__title{ font-size:1.55rem; }
  .pj__sum{ -webkit-line-clamp:1; }
}
/* Short landscape phone: there is no room for a summary at all. */
@media (max-width:860px) and (max-height:520px){
  .pj__sum{ display:none; }
  .pj__title{ font-size:1.5rem; }
}


/* =====================================================================
   09  PROGRESS RAIL + SCROLL HINT
   ---------------------------------------------------------------------
   Position, not decoration. It is aria-hidden because the same
   information is already carried by the scene count in the switcher,
   which IS announced.
   ===================================================================== */
.rail{
  position:fixed; z-index:30;
  /* A real inset. It used to sit ~5px inside the page padding, which at
     1440 and 2048 read as pinned to the bezel and clipped at some
     widths. It now keeps a full gutter of its own, and the scene's
     right padding reserves the same space so text never runs under it. */
  right:calc(max(var(--pad), env(safe-area-inset-right)) * .55 + .35rem);
  top:50%; translate:0 -50%;
  display:flex; flex-direction:column; gap:.55rem; align-items:center;
  pointer-events:none;
  opacity:0; transition:opacity .45s var(--ease-out-quart);
}
/* Position stated as a number, not only as a coloured line. A 2px tint
   difference is not a status indicator. */
.rail__n{
  margin-top:.5rem;
  font-family:var(--font-ui); font-weight:500;
  font-size:.58rem; letter-spacing:.1em;
  font-variant-numeric:tabular-nums;
  color:var(--navy-50);
  writing-mode:vertical-rl;
  line-height:1.2;
}
.rail__n b{ font-weight:500; color:var(--serene-navy); }
@media (max-width:860px){
  .rail__n{ color:color-mix(in srgb, var(--powder-white) 62%, transparent); }
  .rail__n b{ color:var(--powder-white); }
}
html[data-in-seq="1"] .rail{ opacity:1; }
.rail__i{
  inline-size:2px; block-size:14px;
  border-radius:1px;
  background:var(--navy-45);
  opacity:.5;
  transition:opacity .4s var(--ease-out-quart), block-size .5s var(--ease-out-expo),
             background-color .4s var(--ease-out-quart);
}
.rail__i[data-on]{ opacity:1; block-size:26px; background:var(--caspian-blue); }
/* Over full-bleed footage the navy rail vanishes, so it inverts. */
@media (max-width:860px){
  .rail__i{ background:color-mix(in srgb, var(--powder-white) 70%, transparent); }
  .rail__i[data-on]{ background:var(--powder-white); }
}

/* Shown once, on the first scene only, and gone for good after the
   first scroll. No pulsing and no repeat — an instruction that keeps
   animating is an instruction that was not understood the first time. */
.hint{
  position:absolute; z-index:4;
  left:50%; translate:-50% 0;
  bottom:max(clamp(.5rem, 1.6vh, .9rem), env(safe-area-inset-bottom));
  display:flex; flex-direction:column; align-items:center; gap:.4rem;
  color:color-mix(in srgb, var(--powder-white) 78%, transparent);
  pointer-events:none;
  opacity:0; transition:opacity .6s var(--ease-out-quart);
}
html[data-hint="1"] .hint{ opacity:1; }
.hint__l{ inline-size:1px; block-size:22px; background:currentColor; opacity:.6; }
/* Desktop: `left:auto; right:auto` dropped the hint back to its static
   position in the bottom-left corner, straight under the chapter
   switcher. It belongs under the media instead. */
@media (min-width:861px){
  .hint{
    color:var(--navy-50);
    left:auto;
    right:max(var(--pad), env(safe-area-inset-right));
    translate:none;
    bottom:clamp(1rem, 3vh, 1.8rem);
  }
}


/* =====================================================================
   10  CATEGORY SWITCHER + NAVIGATION SHEET
   ---------------------------------------------------------------------
   ONE compact labelled control, never five permanent chips over the
   footage. It opens a real modal sheet containing the same five
   typographic choices plus All Work.

   This is navigation. It is not a filter, and it is not a tablist —
   the panels are documents you scroll, not tab panels, so ARIA tabs
   would describe behaviour that does not exist.
   ===================================================================== */
.switch{
  position:fixed; z-index:36;
  left:max(var(--pad), env(safe-area-inset-left));
  bottom:max(clamp(1rem, 3vh, 1.6rem), calc(env(safe-area-inset-bottom) + .6rem));
  display:inline-flex; align-items:center; gap:.5rem;
  min-height:44px; padding-inline:.9rem;
  border-radius:999px;
  background:color-mix(in srgb, var(--midnight-blue) 70%, transparent);
  -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
  color:var(--powder-white);
  opacity:0; transform:translateY(8px);
  transition:opacity .45s var(--ease-out-quart), transform .5s var(--ease-out-expo),
             background-color .4s var(--ease-out-quart);
  pointer-events:none;
}
html[data-in-seq="1"] .switch{ opacity:1; transform:none; pointer-events:auto; }
.switch:hover{ background:color-mix(in srgb, var(--midnight-blue) 84%, transparent); }
.switch__n{ color:color-mix(in srgb, var(--powder-white) 72%, transparent); font-variant-numeric:tabular-nums; }
.switch__c{ transition:transform .4s var(--ease-out-quart); }
.switch[aria-expanded="true"] .switch__c{ transform:rotate(180deg); }
@media (min-width:861px){
  .switch{
    background:var(--serene-navy);
    -webkit-backdrop-filter:none; backdrop-filter:none;
  }
  .switch:hover{ background:var(--caspian-blue); }
}

/* -- the sheet -------------------------------------------------------- */
.sheet{
  position:fixed; inset:0; z-index:60;
  display:grid; align-content:center;
  padding-block:calc(var(--hdr) + 1rem) max(2rem, env(safe-area-inset-bottom));
  padding-inline:max(var(--pad), env(safe-area-inset-left)) max(var(--pad), env(safe-area-inset-right));
  background:var(--midnight-blue);
  color:var(--powder-white);
  visibility:hidden; opacity:0;
  transition:opacity .32s var(--ease-out-quart), visibility 0s linear .32s;
}
.sheet[data-open]{ visibility:visible; opacity:1; transition-delay:0s; }
.sheet__head{
  display:flex; align-items:center; justify-content:space-between;
  gap:1rem; margin-bottom:clamp(1rem, 3vh, 2rem);
  color:color-mix(in srgb, var(--powder-white) 70%, transparent);
}
.sheet__x{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:44px; min-height:44px;
  color:var(--powder-white);
}
.sheet__list{ list-style:none; margin:0; padding:0; }
.sheet__item{ border-top:1px solid color-mix(in srgb, var(--powder-white) 18%, transparent); }
.sheet__item:last-child{ border-bottom:1px solid color-mix(in srgb, var(--powder-white) 18%, transparent); }
.sheet__b{
  display:grid; grid-template-columns:auto minmax(0,1fr) auto;
  align-items:baseline; column-gap:clamp(.75rem, 1.6vw, 1.4rem);
  inline-size:100%; text-align:left;
  padding-block:clamp(.6rem, 1.7vh, 1rem);
  min-height:44px;
  color:inherit;
}
.sheet__n{ color:color-mix(in srgb, var(--powder-white) 55%, transparent); font-variant-numeric:tabular-nums; }
.sheet__label{
  font-family:var(--font-display); font-weight:400;
  font-size:clamp(1.5rem, 5.6vw, 2.4rem);
  line-height:1.04; letter-spacing:-.015em;
}
.sheet__sub{
  grid-column:2; grid-row:2;
  color:color-mix(in srgb, var(--powder-white) 66%, transparent);
  font-size:.8rem; line-height:1.4; margin-top:.25rem;
}
/* Current chapter is stated in text (a "current" word for screen
   readers, a visible mark here) — never colour alone. */
/* The accent means ONE thing here: "this is the chapter you are in".
   Counts share this slot, so they stay muted — colouring them too made
   every row look current. */
.sheet__mark{ color:color-mix(in srgb, var(--powder-white) 52%, transparent); }
.sheet__b[aria-current="true"] .sheet__label,
.sheet__b[aria-current="true"] .sheet__mark{ color:var(--celestial-blue); }
.sheet__b:hover .sheet__label{ text-decoration:underline; text-underline-offset:.18em; }
.sheet__b[aria-disabled="true"]{ pointer-events:none; }
.sheet__b[aria-disabled="true"] .sheet__label{ color:color-mix(in srgb, var(--powder-white) 42%, transparent); }
@media (min-width:861px){
  .sheet{ align-content:center; }
  .sheet__list{ max-inline-size:min(58rem, 100%); }
  .sheet__sub{ font-size:.85rem; }
}

/* The scroll lock is scoped to the modal ONLY, and uses overflow on the
   root rather than position:fixed on the body — fixing the body scrolls
   the page to the top and loses the reader's place. */
html[data-sheet="1"]{ overflow:hidden; scroll-snap-type:none; }


/* =====================================================================
   11  ALL WORK INDEX
   ---------------------------------------------------------------------
   Fast scanning, one clear link per row. A disciplined list on desktop,
   a single-column visual list on mobile. Not masonry, not a filter tray.
   ===================================================================== */
/* No forced 100svh. Five rows in a viewport-height box read as an
   unfinished table with a void under it; the list should be exactly as
   tall as it is and then end properly. */
.aw{
  padding-block:calc(var(--hdr) + clamp(1.6rem, 5vh, 3.4rem)) clamp(2rem, 5vh, 3.5rem);
  padding-inline:max(var(--pad), env(safe-area-inset-left)) max(var(--pad), env(safe-area-inset-right));
  min-block-size:0;
}
.aw__head{ display:flex; align-items:baseline; gap:1rem; justify-content:space-between; }
.aw__h{
  font-family:var(--font-display); font-weight:400;
  font-size:clamp(1.5rem, 3vw, 2.4rem);
  line-height:1.04; letter-spacing:-.015em;
}
.aw__list{ list-style:none; margin:clamp(1.2rem, 3vh, 2rem) 0 0; padding:0; }
.aw__item{ border-top:1px solid var(--rule); }
.aw__item:last-child{ border-bottom:1px solid var(--rule); }
.aw__link{
  display:grid;
  /* Scales with the viewport. At 2048 a 104px thumbnail made the index
     read like a spreadsheet with a void under it. */
  grid-template-columns:clamp(96px, 11vw, 200px) minmax(0,1fr) auto;
  align-items:center;
  column-gap:clamp(1rem, 2.2vw, 2rem);
  padding-block:clamp(.7rem, 1.6vh, 1.15rem);
  min-height:44px;
  position:relative;
}
.aw__link::before{
  content:''; position:absolute; inset:0 calc(-1 * clamp(.5rem, 1vw, 1rem));
  background:color-mix(in srgb, var(--serene-navy) 4%, transparent);
  opacity:0; transition:opacity .35s var(--ease-out-quart);
}
.aw__link:hover::before,
.aw__link:focus-visible::before{ opacity:1; }
.aw__thumb{
  aspect-ratio:16/10; border-radius:6px; overflow:hidden;
  background:color-mix(in srgb, var(--serene-navy) 8%, var(--powder-white));
}
.aw__thumb img{ width:100%; height:100%; object-fit:cover; }
.aw__t{ display:flex; flex-direction:column; gap:.18rem; min-inline-size:0; }
.aw__client{ color:var(--navy-70); }
.aw__name{
  font-family:var(--font-display); font-weight:400;
  font-size:clamp(1.1rem, 1.9vw, 1.75rem); line-height:1.12;
  letter-spacing:-.012em;
  transition:transform .5s var(--ease-out-expo); transform-origin:left;
}
/* Feedback that does not depend on a pointer existing. */
.aw__link:hover .aw__name,
.aw__link:focus-visible .aw__name{ transform:translateX(6px); }
.aw__thumb img{ transition:transform .6s var(--ease-out-expo); }
.aw__link:hover .aw__thumb img{ transform:scale(1.04); }
.aw__tags{ display:flex; gap:.55rem; align-items:center; color:var(--navy-45); white-space:nowrap; }
@media (max-width:860px){
  .aw__link{ grid-template-columns:clamp(84px, 24vw, 120px) minmax(0,1fr); }
  .aw__tags{ grid-column:2; margin-top:.25rem; white-space:normal; }
}


/* =====================================================================
   12  REDUCED MOTION, NO-JS, FORCED COLOURS
   ===================================================================== */
@media (prefers-reduced-motion: reduce){
  html{ scroll-snap-type:none; }
  *,*::before,*::after{
    animation-duration:.001ms !important; animation-iteration-count:1 !important;
    transition-duration:.001ms !important; scroll-behavior:auto !important;
  }
  /* Content is never gated behind a transition that no longer runs. */
  .pj__copy > *{ opacity:1; transform:none; }
  .gw__shot[data-on]{ opacity:1; }
  .hint{ display:none; }
}

/* Be honest about this one: scenes and the index are BUILT in JS, from
   the single content source, so without JS this route renders its
   <noscript> fallback and nothing else. That is the same trade the
   homepage already makes (slide 04, the look list and the service
   options are all JS-built) — the alternative is a second hand-written
   copy of every project, which is exactly the duplication the shared
   data file exists to prevent. The WordPress build renders these
   server-side from the same records and the dependency disappears. */
html.no-js .switch,
html.no-js .rail,
html.no-js .hint,
html.no-js .gw__stage{ display:none; }
html.no-js .pj__copy > *{ opacity:1; transform:none; }

@media (forced-colors: active){
  .pj__shade{ display:none; }
  .pj__copy{ color:CanvasText; background:Canvas; }
  .gw__item, .aw__item, .sheet__item{ border-color:CanvasText; }
  .rail__i[data-on]{ background:Highlight; }
}


/* =====================================================================
   13  END OF PAGE
   ---------------------------------------------------------------------
   The index used to stop dead at the last row. The route now closes on
   the same contact invitation the case studies use, so /projects/ has an
   ending rather than a bottom edge.
   ===================================================================== */
.pend{
  padding-inline:max(var(--pad), env(safe-area-inset-left)) max(var(--pad), env(safe-area-inset-right));
  padding-block:clamp(1.6rem, 4vh, 2.6rem) clamp(3rem, 9vh, 6rem);
}
.pend__in{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between;
  gap:1rem;
  padding-top:clamp(1.4rem, 4vh, 2.4rem);
  border-top:1px solid var(--rule);
}
.pend__h{
  font-family:var(--font-display); font-weight:400;
  font-size:clamp(1.3rem, 2.8vw, 2.1rem); line-height:1.1; letter-spacing:-.018em;
  text-wrap:balance;
}

.rail__marks{ display:flex; flex-direction:column; gap:.55rem; align-items:center; }

/* At 2048 the row spanned ~1930px, putting the title and its category
   1500px apart — technically aligned, unreadable in practice. The index
   holds a scanning measure and centres instead. */
.aw__head, .aw__list, .pend__in{ max-inline-size:90rem; margin-inline:auto; }


/* =====================================================================
   14  GATEWAY MEDIA — the Featured reel
   ---------------------------------------------------------------------
   One moving surface. The chapter previews beside it are decoded stills,
   so hovering the list can never start a second video.
   ===================================================================== */
.gw__shot{ position:absolute; inset:0; }
.gw__shot img,
.gw__vid{
  position:absolute; inset:0;
  inline-size:100%; block-size:100%;
  object-fit:cover;
}
.gw__vid{
  opacity:0;
  transition:opacity .5s var(--ease-out-quart);
  pointer-events:none;
}
.gw__vid.is-live{ opacity:1; }

/* ---------------------------------------------------------------------
   MOBILE GATEWAY — full-bleed band, with the chapter sheet rising over it
   ---------------------------------------------------------------------
   The band used to be an inset rounded rectangle floating on a white
   page, which read as a thumbnail pasted above a list rather than one
   composition. Now the media runs edge to edge and the light sheet
   carrying the eyebrow, proposition and chapters lifts over its lower
   edge — so the two are physically joined and the page has a front door.

   The media is PORTRAIT (3:4) here. The landscape edit centre-cropped
   into a shallow strip threw away most of every frame.
   ===================================================================== */
@media (max-width:860px){
  .gw{
    display:block;
    padding:0;                        /* the band is full bleed */
    justify-content:flex-start;
  }

  .gw__stage{
    display:block;
    position:relative;
    margin:0;
    /* Sits under the fixed header rather than starting below it: the
       header has its own scrim over media, so the composition reads as
       one image with navigation on top. */
    block-size:clamp(300px, 43svh, 430px);
    overflow:hidden;
  }
  .gw__frame{
    position:absolute; inset:0;
    aspect-ratio:auto;                /* the band's height rules here */
    border-radius:0;
    overflow:hidden;
    background:color-mix(in srgb, var(--midnight-blue) 88%, var(--powder-white));
  }
  /* Just enough darkening at the very top for the inverted header. */
  .gw__stage::after{
    content:''; position:absolute; inset:0 0 auto 0; block-size:var(--hdr);
    background:linear-gradient(to bottom,
      color-mix(in srgb, var(--midnight-blue) 42%, transparent), transparent);
    pointer-events:none;
  }
  .gw__cap{ display:none; }

  /* The sheet. Only the top corners are rounded, and it overlaps the
     media so the join is deliberate rather than a seam. */
  .gw__sheet{
    position:relative;
    z-index:2;
    margin-top:-28px;
    border-radius:var(--wk-r, 20px) var(--wk-r, 20px) 0 0;
    background:var(--powder-white);
    padding:clamp(1.1rem, 3.4vh, 1.6rem)
            max(var(--pad), env(safe-area-inset-left))
            max(clamp(1.4rem, 4vh, 2.2rem), calc(env(safe-area-inset-bottom) + 1rem))
            max(var(--pad), env(safe-area-inset-right));
  }
  .gw__prop{ font-size:clamp(1.5rem, 7.2vw, 2.1rem); }
  .gw__lede{ display:none; }          /* its job is done by the Featured subline */
  .gw__nav{ margin-top:clamp(.8rem, 2.4vh, 1.2rem); }
  .gw__link{
    grid-template-columns:auto minmax(0,1fr);
    padding-block:clamp(.6rem, 1.6vh, .9rem);
  }
  .gw__label{ font-size:clamp(1.35rem, 6.2vw, 1.8rem); }
  .gw__sub{ font-size:.78rem; margin-top:.2rem; }
  .gw__count{
    grid-column:2; grid-row:3;
    font-size:.66rem; letter-spacing:.1em; text-transform:uppercase;
    margin-top:.3rem;
  }

  /* The chapters are not the whole archive, so the way to the whole
     archive is stated rather than left to be discovered. */
  .gw__all{
    display:inline-flex; align-items:center;
    min-height:44px; margin-top:.9rem;
    color:var(--caspian-blue);
  }
}

/* The band earns its height; on a short screen the list matters more, so
   the band shrinks rather than pushing chapters off the screen. It is
   never removed — a gateway with no evidence is the problem we started
   with. */
@media (max-width:860px) and (max-height:700px){
  .gw__stage{ block-size:clamp(220px, 34svh, 300px); }
  .gw__sheet{ margin-top:-22px; }
}
@media (max-width:860px) and (max-height:560px){
  .gw__stage{ block-size:190px; }
}

/* Desktop keeps the 12-column grid, so the sheet is not a box there. */
@media (min-width:861px){
  .gw__sheet{ display:contents; }
  .gw__all{
    display:inline-flex; align-items:center; min-height:44px;
    margin-top:1rem; color:var(--caspian-blue);
  }
  .gw__all:hover{ text-decoration:underline; text-underline-offset:.2em; }
}

/* The manual-play control. Restrained, and only ever present when
   autoplay was actually refused. */
.gw__play{
  position:absolute; z-index:3;
  left:50%; translate:-50% 0; bottom:clamp(2.4rem, 8vh, 4rem);
  display:inline-flex; align-items:center; gap:.5rem;
  min-height:44px; padding-inline:1rem;
  border-radius:999px; cursor:pointer;
  background:color-mix(in srgb, var(--midnight-blue) 74%, transparent);
  -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
  color:var(--powder-white);
}
.gw__play[hidden]{ display:none; }
.gw__play:hover{ background:var(--midnight-blue); }
@media (min-width:861px){
  .gw__play{ bottom:1rem; left:1rem; translate:none; }
}
