/* ================================================================
   EPWA — PORTFOLIO STYLESHEET
   Grungy editorial / documentary print.
   ================================================================
   TABLE OF CONTENTS
     0. Design tokens (edit colors here)
     1. Reset & base
     2. Grain overlay
     3. Utilities (stamps, mono, rules)
     4. Masthead & folder tabs
     5. Sheets (tab panels + pull transition)
     6. Hero (video + difference logo)
     7. Description (EPWA cycler)
     8. Selector (2×2 index)
     8.5 Dispatch (archived) · 8.6 Achievements (trophy log)
     9. Stage (3D carousel)
    10. Board (grid paper)
    11. Theater (video)
    12. Stubs
    13. Colophon
    14. Lightbox
    15. Responsive
    16. Reduced motion
   ================================================================
   HOUSE RULES (do not break):
     · no border-radius        · no gradients
     · no box-shadow           · no glassmorphism
     · hard rectangles only    · thick ink rules over whitespace
   ================================================================ */


/* ─── 0. DESIGN TOKENS ──────────────────────────────────────────── */
:root {
  /* ══ ORIGINAL PAPER COLORWAY — the permanent backup. ══
     This is the canonical light theme; the toggle in the masthead
     brings it back at any time. Do not overwrite these — the dark
     colorway lives in its own block right below. */
  --paper:      #E8E0D0;   /* off-white newsprint            */
  --paper-deep: #D9CDB4;   /* yellowed paper                 */
  --ink:        #1A1208;   /* near-black ink                 */
  --red:        #B5271E;   /* faded signal red               */
  --olive:      #7A7A52;   /* washed olive/khaki             */

  /* UNIVERSAL manilla — folder icons keep these exact colors in BOTH
     colorways (deliberately NOT overridden in the dark block) */
  --manilla:      #D9C68F;
  --manilla-dark: #C3AC66;   /* front pocket, for depth */

  /* Rules & structure */
  --rule: 3px solid var(--ink);
  --rule-heavy: 6px solid var(--ink);
  --masthead-h: 76px;      /* updated live by js/main.js     */

  /* Motion: sheets ease in — start slow, then accelerate. Raise
     --pull-lag above 0 for a hard pause before the motion starts. */
  --pull-lag: 0ms;
  --pull-speed: 500ms;
}

/* ══ DARK COLORWAY: "DECLASSIFIED" (work in progress) ══
   Near black-and-white, a tad warm — a declassified technical
   document / darkroom negative. Active when <html data-theme="dark">;
   the masthead toggle swaps it. Previous colorways are archived in
   css/COLORWAYS-BACKUP.css. */
html[data-theme="dark"] {
  --paper:      #0F0E0C;   /* near-black, a whisper of warmth */
  --paper-deep: #1B1A17;   /* raised surface — panels, mattes */
  --ink:        #E7E4DC;   /* off-white, warm gray            */
  --olive:      #8B887C;   /* labels: warm gray (olive reads
                              muddy on black)                 */
}

/* The baked background: Texturelabs scratches + fine noise, screen
   blended (light marks lift off the black; the texture's own black
   disappears). The master intensity knob for the dark theme. */
html[data-theme="dark"] .grain {
  /* PRE-BAKED: dots + noise + scratch plate flattened into one alpha
     PNG (light marks only — the plate's black is baked away, so no
     blending is needed and nothing can composite as a dark veil). */
  background-image: url("../assets/textures/baked-grain-dark.png?v=2");
}


/* ─── 1. RESET & BASE ───────────────────────────────────────────── */
*, *::before, *::after {
  box-sizing: border-box;
  border-radius: 0 !important;   /* house rule enforced */
  margin: 0;
  padding: 0;
}

html {
  scroll-behavior: smooth;
  /* Always reserve the scrollbar lane. Sheets leave/enter the
     document flow during tab transitions, which otherwise makes the
     scrollbar blink out and re-widen the page ~17px — a visible
     sideways shift of everything behind the animation. */
  overflow-y: scroll;
  scrollbar-gutter: stable;
}

body {
  position: relative;   /* anchors the document-level grain overlay */
  min-height: 100svh;   /* keeps texture overlays viewport-sized even
                           while both sheets are pinned mid-transition */
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.55;
  overflow-x: hidden;
}

img, video, iframe { display: block; max-width: 100%; }

[hidden] { display: none !important; }

button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
}

a { color: inherit; text-decoration: none; }

::selection { background: var(--red); color: var(--paper); }

:focus-visible { outline: 3px solid var(--red); outline-offset: 2px; }

code {
  font-family: var(--font-mono);
  font-size: .92em;
  background: var(--paper-deep);
  padding: 0 .3em;
  border: 1px solid var(--olive);
}


/* ─── 2. GRAIN OVERLAY ──────────────────────────────────────────── */
/* Every surface gets tooth. Three layers baked into one element:
   fine photocopy grain + coarse grit + large-scale paper mottle
   (the blotchy unevenness of old stock). Multiply, no pointer hits. */
.grain {
  /* absolute (not fixed): the texture is IN the paper, so it scrolls
     with the page instead of floating over it like a screen door */
  position: absolute;
  inset: 0;
  z-index: 9990;
  pointer-events: none;
  /* PRE-BAKED: dots + fine grain + grit + mottle + dust flattened into
     one alpha PNG (tools/bake-grain.ps1 regenerates). Plain alpha
     compositing — NO blend modes, nothing for a loaded GPU to drop
     or rasterize per-frame. Master dimmer: opacity below. */
  background-image: url("../assets/textures/baked-grain-paper.png?v=2");
  background-size: 1728px 1152px;
  opacity: 1;
}

/* ─── CUSTOM TEXTURE SLOT ───────────────────────────────────────────
   Drop your own texture files (scans, grain, paper, halftone) into
   assets/textures/ and layer them here. Copy this block, uncomment,
   and it stacks ON TOP of the procedural grain above:

.grain {
  background-image:
    url("../assets/textures/YOUR-TEXTURE.png"),   <- first = topmost
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='280' height='280'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='720' height='720'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.11' numOctaves='2' seed='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size: 900px auto, 280px 280px, 720px 720px;   <- size per layer, same order
  background-blend-mode: multiply, multiply, normal;
}

   Notes:
   · paths are relative to this css/ folder, hence the ../
   · seamless/tileable textures work best (they repeat)
   · light-on-dark textures want mix-blend-mode: screen instead
   · to texture ONE section only, put the url on that section's
     background-image instead (e.g. .hero, .board, .theater)
   · DARK COLORWAY ONLY (the usual case for your drops): scope the
     block to the theme —
       html[data-theme="dark"] .grain { background-image: url("../assets/textures/YOUR-TEXTURE.png"); background-size: 900px auto; }
     (dark grain is already screen-blended, so light/chalky scans
     read correctly; the paper colorway stays untouched)
   ─────────────────────────────────────────────────────────────────── */

/* ── THE OVERLAY LADDER ─────────────────────────────────────────
   grain (incl. dots) 9990 < frozen under-sheet 9991 <
   CLEAN ZONES 9992 < stage chips + headered movers 9993 <
   masthead 9994 < home movers 9996 < lightbox 10000.
   "Clean zones" are regions lifted ABOVE the texture overlays so
   artwork/brand/footage surfaces stay untextured: the product
   split, the carousel, the hero video, the signal interlude, and
   the board's pinned photos (backgrounds beneath them stay
   textured). The signal is here so it reads IDENTICAL in both
   colorways: the dark colorway's light scratches would otherwise
   show all over its black. It re-textures itself with a local copy
   of the PAPER grain (see 6b) so the print look survives. */
.duo,
.carousel,
.hero,
.signal,
.b-item {
  position: relative;
  z-index: 9992;
}

/* Universal halftone dot grid — now baked INTO the .grain stacks
   below (one composited full-screen layer instead of two: less GPU
   load, and transitions have half as much to rasterize). NOTE: the
   dot color is baked per colorway in the data-URIs — if a palette's
   ink changes, update the fill in that theme's .grain dots layer. */


/* ─── 3. UTILITIES ──────────────────────────────────────────────── */
.mono {
  font-family: var(--font-mono);
  font-size: .8rem;
  letter-spacing: .04em;
}

/* Rubber-stamp label */
.stamp {
  display: inline-block;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: .8rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink);
  border: 3px solid currentColor;
  padding: .3em .7em;
  transform: rotate(-1.5deg);
}
.stamp--red { color: var(--red); }
.stamp--big {
  font-size: 1.3rem;
  border-width: 4px;
  transform: rotate(-4deg);
}

/* hide the inline SVG filter defs without display:none (Safari) */
.fx-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

/* Custom cursor: white ink with the same difference-blend behavior as
   the landing down-arrow. Enabled only for fine pointers by JS. */
@media (hover: hover) and (pointer: fine) {
  html.has-custom-cursor,
  html.has-custom-cursor * {
    cursor: none !important;
  }

  .custom-cursor {
    position: fixed;
    left: 0;
    top: 0;
    z-index: 10050;
    width: 18px;
    height: 18px;
    border: 0 solid #fff;
    border-radius: 50% !important;
    background: #fff;
    mix-blend-mode: difference;
    pointer-events: none;
    opacity: 0;
    transform: translate3d(-50px, -50px, 0) translate(-50%, -50%);
    transition:
      width 140ms ease,
      height 140ms ease,
      border-width 140ms ease,
      background-color 140ms ease,
      opacity 120ms ease;
    will-change: transform, width, height;
  }

  .custom-cursor.is-visible { opacity: 1; }

  .custom-cursor.is-interactive {
    width: 34px;
    height: 34px;
    border-width: 5px;
    background: transparent;
  }
}


/* ─── 3.5 TEXTURE PACK — the grunge lives here ──────────────────── */

/* Worn screen-print edges: displacement filters chew up the type.
   (Filters are defined inline at the top of index.html.) */
.stub__title, .board__title, .desc__cycler,
.dispatch__title, .achieve__title, .p-seg__title {
  filter: url(#rough-ink-heavy);
}
/* lighter wear for THE INDEX heading (per EPWA: less distortion);
   the masthead brand runs clean — no filter at all */
.stamp, .stage__counter, .desc__lede, .selector__title {
  filter: url(#rough-ink);
}

/* Misregistration: the second ink pass didn't quite line up. */
.stub__title, .selector__title, .dispatch__title,
.achieve__title, .p-seg__title {
  text-shadow: .03em .025em 0 rgba(181, 39, 30, .32);
}
.desc__cycler { text-shadow: .028em .024em 0 rgba(122, 122, 82, .35); }

/* (Section-header dot beds retired — the dot grid is universal now,
   see body::before in section 2.) */

/* ─── 3.6 DECLASSIFIED KIT — dark-colorway scatter furniture ────── */
/* White-on-black blueprint ephemera (assets/textures/) ghosted over
   sections. Screen blend melts the sheets' black away, so only the
   stamps, codes and schematics float on the page. Dark theme only —
   the paper colorway never sees these. */
html[data-theme="dark"] .desc,
html[data-theme="dark"] .dispatch,
html[data-theme="dark"] .achieve,
html[data-theme="dark"] .board { position: relative; }

html[data-theme="dark"] .desc::after,
html[data-theme="dark"] .dispatch::after,
html[data-theme="dark"] .achieve::after,
html[data-theme="dark"] .stub::after,
html[data-theme="dark"] .board::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  mix-blend-mode: screen;
  background-repeat: no-repeat;
}
/* wiring schematic behind the description copy */
html[data-theme="dark"] .desc::after {
  background-image: url("../assets/textures/Texturelabs_Details_182M.jpg");
  background-size: 1500px auto;
  background-position: right -180px top -60px;
  opacity: .14;
}
/* DECLASSIFIED / INFORMATION ONLY stamps around the dispatch log */
html[data-theme="dark"] .dispatch::after {
  background-image: url("../assets/textures/Texturelabs_Details_183M.jpg");
  background-size: 1400px auto;
  background-position: right -140px center;
  opacity: .11;
}
/* same declassified sheet behind the trophy log */
html[data-theme="dark"] .achieve::after {
  background-image: url("../assets/textures/Texturelabs_Details_183M.jpg");
  background-size: 1400px auto;
  background-position: right -140px center;
  opacity: .11;
}
/* darkroom margin notes across the in-development stubs */
html[data-theme="dark"] .stub::after {
  background-image: url("../assets/textures/Texturelabs_Details_185M.jpg");
  background-size: 1500px auto;
  background-position: center;
  opacity: .17;
}
/* stencil codes on the board's flat file */
html[data-theme="dark"] .board::after {
  background-image: url("../assets/textures/Texturelabs_Details_178M.jpg");
  background-size: 1300px auto;
  background-position: left -120px bottom -80px;
  opacity: .10;
}

/* glyphs on the index tiles — a different crop of the ephemera per
   button (tiles are position:relative + overflow:hidden already) */
html[data-theme="dark"] .sel-tile::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  mix-blend-mode: screen;
  background-repeat: no-repeat;
  opacity: .12;
}
html[data-theme="dark"] .sel-tile:nth-child(1)::after {  /* DECLASSIFIED */
  background-image: url("../assets/textures/Texturelabs_Details_183M.jpg");
  background-size: 1200px auto;
  background-position: -300px -40px;
}
html[data-theme="dark"] .sel-tile:nth-child(2)::after {  /* COPY / legend */
  background-image: url("../assets/textures/Texturelabs_Details_185M.jpg");
  background-size: 1300px auto;
  background-position: -260px -380px;
}
html[data-theme="dark"] .sel-tile:nth-child(3)::after {  /* stencil codes */
  background-image: url("../assets/textures/Texturelabs_Details_178M.jpg");
  background-size: 1300px auto;
  background-position: -40px -260px;
}
html[data-theme="dark"] .sel-tile:nth-child(4)::after {  /* AS BUILT */
  background-image: url("../assets/textures/Texturelabs_Details_183M.jpg");
  background-size: 1200px auto;
  background-position: -700px -420px;
}

/* glyphs around the carousel: stencil codes low-left, darkroom
   margin notes high-right. They sit on the STAGE background — the
   carousel itself is a lifted clean zone, so panels float above
   both the glyphs and the grain, untextured. */
html[data-theme="dark"] .stage::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  mix-blend-mode: screen;
  background-image:
    url("../assets/textures/Texturelabs_Details_178M.jpg"),
    url("../assets/textures/Texturelabs_Details_185M.jpg");
  background-repeat: no-repeat, no-repeat;
  background-size: 1250px auto, 1500px auto;
  background-position: left -140px bottom -60px, right -260px top -140px;
  opacity: .13;
}


/* Ink blot + coffee ring — desk-wear furniture for quiet corners */
.desc, .stub {
  background-repeat: no-repeat;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 220 220'%3E%3Cpath d='M108 22c26-9 58 2 72 26 13 23 2 47 12 72 10 26-8 52-36 58-27 6-46-12-74-15-28-3-56-18-56-47 0-28 22-38 32-62 9-23 26-24 50-32z' fill='%231A1208' fill-opacity='.03'/%3E%3Ccircle cx='112' cy='112' r='86' fill='none' stroke='%237A7A52' stroke-opacity='.11' stroke-width='9' stroke-dasharray='150 34 80 22 60 30'/%3E%3C/svg%3E");
}
.desc { background-position: right -70px bottom -90px; background-size: 400px; }
.stub { background-position: left -80px bottom -70px; background-size: 460px; }


/* ─── 4. MASTHEAD & FOLDER TABS ─────────────────────────────────── */
/* Hidden on the landing (home) sheet — the hero owns the screen.
   Everywhere else the tabs are smushed flush: shared 3px borders,
   zero gaps, red active indicator hard against the top of the page. */
body.on-home .masthead { display: none; }

.masthead {
  position: sticky;
  top: 0;
  z-index: 9994;   /* above the clean zones (9992) so scrolling
                      content slides under the header, and above the
                      texture overlays — see THE OVERLAY LADDER */
  display: flex;
  align-items: stretch;
  gap: 1.5rem;
  background: var(--paper);
  border-bottom: var(--rule);
  padding: 0 1.25rem;
}

/* Hamburger page-picker — hidden on desktop; the folder tabs handle
   navigation there. Revealed at ≤760px (section 15), where it drops
   the tab row down as a menu so the bar fits on one line. */
.masthead__menu {
  display: none;
  align-self: center;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 34px;
  height: 34px;
  padding: 0;
}
.masthead__menu-bar {
  display: block;
  height: 3px;
  width: 100%;
  background: var(--ink);
}
.masthead__menu:hover .masthead__menu-bar { background: var(--red); }
/* open state: middle bar hides, outer bars cross into an X */
.masthead.menu-open .masthead__menu-bar:nth-child(2) { opacity: 0; }
.masthead.menu-open .masthead__menu-bar:nth-child(1) { transform: translateY(8px) rotate(45deg); }
.masthead.menu-open .masthead__menu-bar:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }

.masthead__brand {
  /* Franklin Gothic Heavy (registered in css/fonts.css; loads from
     the local machine, falls back to Arial Black) — undistorted */
  font-family: "Franklin Gothic Heavy", "Arial Black", var(--font-poster);
  font-weight: 400;   /* FGH is heavy by design — no faux bold */
  font-size: 2.1rem;
  line-height: 1;
  letter-spacing: -0.02em;
  align-self: center;
  padding: .6rem 0;
}
.masthead__brand:hover { color: var(--red); }

.masthead__meta {
  margin-left: auto;
  text-align: right;
  color: var(--olive);
  font-size: .68rem;
  line-height: 1.4;
  align-self: center;
  white-space: nowrap;
}

/* colorway toggle — far top-right, beside (not over) the meta text */
.masthead__theme {
  align-self: center;
  margin-left: 1.1rem;
  border: 2px solid var(--ink);
  padding: .4rem .65rem;
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .18em;
  color: var(--ink);
  white-space: nowrap;
}
.masthead__theme:hover { background: var(--red); border-color: var(--red); color: var(--paper); }

/* Folder tabs: hard border on three sides, bottom opens into content.
   Adjacent tabs share one 3px border (negative margin collapse). */
.tabs {
  display: flex;
  align-items: stretch;
  overflow-x: auto;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }

.tab {
  display: flex;
  align-items: center;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 1.05rem;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  white-space: nowrap;
  background: var(--paper-deep);
  border: var(--rule);
  border-bottom: none;
  padding: .55rem 1.1rem;
  color: var(--ink);
}
.tab + .tab { margin-left: -3px; }   /* smush: share the border */
.tab:hover { background: var(--red); color: var(--paper); position: relative; z-index: 1; }

.tab.is-active {
  background: var(--paper);
  border-top: 6px solid var(--red);   /* touches the top of the page */
  margin-bottom: -3px;                /* covers the masthead rule → open bottom */
  position: relative;
  z-index: 2;
}
.tab.is-active:hover { color: var(--ink); }

.tab__num {
  font-family: var(--font-mono);
  font-weight: 400;
  font-size: .6rem;
  vertical-align: super;
  margin-right: .45em;
  color: var(--red);
}
.tab:hover .tab__num { color: inherit; }
.tab.is-active:hover .tab__num { color: var(--red); }


/* ─── 5. SHEETS — panel stack + pull transition ─────────────────── */
.sheets {
  position: relative;
  overflow: clip;             /* hides the sheet as it's pulled out  */
  background: var(--paper);
}

.sheet { display: none; }
.sheet.is-active { display: block; }

/* Direction-aware, one sheet moves at a time (binder logic).
   In BOTH directions the non-moving sheet is frozen as a fixed layer
   showing exactly what was on screen (js/main.js copies the scroll
   position into it and sets its inline top) — nothing flashes or
   jumps while the moving sheet does its thing:
   · FORWARD (higher tab number): the frozen current view peels up
     and off, revealing the new tab with the masthead already placed.
   · BACKWARD (lower tab number): the target sheet drops down from
     the top and covers the frozen current view.
   Both movers hold their start position during --pull-lag (the grip
   before the pull) via animation-fill-mode: both. */
/* Pinning is PURE GEOMETRY — no scrollers. The frozen sheets sit at
   a negative inline top (their scrolled position) with an inline
   clip-path marking the visible band. Unlike element scrollTop —
   which browsers latch asynchronously and can leave the sheet
   showing its TOP (home's dark hero) for the first frames — top and
   clip-path apply atomically in the same frame. */
.sheet.is-leaving,
.sheet.is-under {
  display: block;
  position: fixed;
  left: 0; right: 0;              /* top + clip-path set inline by js */
  background: var(--paper);
}
.sheet.is-covering {
  display: block;
  position: fixed;
  left: 0; right: 0; bottom: 0;   /* top set inline; shows its own top */
  overflow: hidden;
  background: var(--paper);
}
.sheet.is-leaving,
.sheet.is-covering {
  z-index: 9996;   /* home transitions: the sheet covers/reveals the
                      header as it passes (home has no header) */
  border-bottom: var(--rule-heavy);
}
/* between two HEADERED tabs the mover slides UNDER the masthead —
   the header stays in front the whole way through (js/main.js adds
   the class for non-home transitions) */
.sheet.is-leaving.under-header,
.sheet.is-covering.under-header {
  z-index: 9993;   /* above clean zones (9992), below masthead (9994) */
}
.sheet.is-under {
  z-index: 9991;   /* above the global overlays — as a stacking
                      context it would otherwise trap its clean
                      zones and let the grain flood light over
                      them; it re-prints its own texture below */
}

/* Chrome can't composite SVG reference filters (the rough-ink type
   edges): elements carrying them inside a transform-animated layer
   fail to paint and blink out mid-flight. Strip all filters from the
   MOVING sheet for the duration — the motion hides the momentarily
   clean edges, and the static sheets keep their grunge. */
.sheet.is-leaving *,
.sheet.is-covering * {
  filter: none !important;
}

/* ramp curves: moving from the first frame, then accelerating —
   no dead time at the start */
.sheet.is-leaving {
  animation: sheet-pull var(--pull-speed) cubic-bezier(.35, .08, .75, .25) var(--pull-lag) both;
}
.sheet.is-covering {
  animation: sheet-cover var(--pull-speed) cubic-bezier(.35, .08, .7, .8) var(--pull-lag) both;
}

/* Movers fly ABOVE the global texture overlays (see THE OVERLAY
   LADDER), which would leave their surface flat — noticeably darker
   in the dark colorway, where the screen-blend texture adds light.
   Re-print the texture onto the moving sheet itself so it matches
   the settled page. (Clean zones inside the sheet still float above
   this pseudo, exactly like the settled state.) */
/* (the dot grid rides inside the same stacks below — one pseudo per
   sheet instead of two, matching the consolidated .grain layers) */
.sheet.is-under::after,
.sheet.is-leaving::after,
.sheet.is-covering::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  /* align the pattern with the document-anchored global grain: the
     pinned sheet sits at its natural document offset now, so only
     the masthead origin shift is needed — the pattern rides with
     the content automatically */
  background-position: 0 calc(var(--masthead-h) * -1);
  /* the SAME pre-baked tile the page uses — identical pixels, plain
     alpha compositing, nothing to rasterize or blend at flight start */
  background-image: url("../assets/textures/baked-grain-paper.png?v=2");
  background-size: 1728px 1152px;
}
/* Dark colorway mover texture — the same pre-baked tile as the page */
html[data-theme="dark"] .sheet.is-under::after,
html[data-theme="dark"] .sheet.is-leaving::after,
html[data-theme="dark"] .sheet.is-covering::after {
  background-image: url("../assets/textures/baked-grain-dark.png?v=2");
}

@keyframes sheet-pull {
  /* viewport-based: the leaving sheet is full document height now,
     so % would travel absurdly far — 110vh clears the screen */
  to { transform: translateY(-110vh); }
}
@keyframes sheet-cover {
  from { transform: translateY(-104%); }
  to   { transform: translateY(0); }
}


/* ─── 6. HERO ───────────────────────────────────────────────────── */
.hero {
  position: relative;
  height: calc(100svh - var(--masthead-h));
  min-height: 420px;
  background: var(--ink);
  overflow: hidden;
}

.hero__media, .hero__video { position: absolute; inset: 0; }
.hero__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* The blurred fill copy is a MOBILE-ONLY affair — see section 15.
   Off entirely on desktop, where the single reel fills the screen. */
.hero__video--bg { display: none; }

/* Shown only when assets/video/hero.mp4 is missing */
.hero__fallback {
  position: absolute;
  inset: 0;
  background: var(--paper-deep);
  display: grid;
  place-content: start center;   /* note sits up top; logo owns the center */
  justify-items: center;
  gap: 1.2rem;
  text-align: center;
  padding-top: clamp(2rem, 10vh, 5rem);
}
.hero__fallback-note { color: var(--ink); font-size: .85rem; line-height: 1.7; }

/* THE DIFFERENCE LAYER — white logo inverts against whatever is
   behind it. Your white embossed logo goes to assets/logo/. */
.hero__logo-wrap {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  mix-blend-mode: difference;
  pointer-events: none;
}
.hero__logo {
  width: min(52vw, 560px);
  max-height: 55vh;
  object-fit: contain;
}
.hero__logo-fallback {
  font-family: var(--font-poster);
  font-size: clamp(4rem, 20vw, 15rem);
  letter-spacing: -0.02em;
  color: #fff;             /* white → full inversion via difference */
  line-height: 1;
}

/* Hollow square ↓ — difference-blended so it inverts against the
   footage behind it. The hero's drops to THE SIGNAL; the signal's
   drops to THE INDEX — same square, same behavior. */
.hero__down,
.signal__down {
  position: absolute;
  bottom: 1.25rem;
  right: 1.25rem;
  z-index: 2;
  width: 58px;
  height: 58px;
  display: grid;
  place-items: center;
  border: 3px solid #fff;
  background: transparent;
  color: #fff;
  font-family: var(--font-poster);
  font-size: 1.7rem;
  line-height: 1;
  mix-blend-mode: difference;
}
.hero__down:hover,
.signal__down:hover { background: #fff; color: #000; }

/* Bottom ticker strip — ARCHIVED: markup is commented out in
   index.html; styles kept so it can be revived in one move. */
.hero__ticker {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  background: var(--paper);
  border-top: var(--rule);
  padding: .45rem 0;
  overflow: hidden;
  white-space: nowrap;
  font-size: .72rem;
  letter-spacing: .18em;
}
.hero__ticker span {
  display: inline-block;
  animation: ticker 22s linear infinite;
}
@keyframes ticker {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}


/* ─── 6b. SIGNAL — black interlude: logo + socials ──────────────── */
/* A deliberate break from the paper: literal #000 / #FFF, harsh on
   purpose — no warm tones, no theme vars. One full screen, split 3:1
   between the logo stage and the socials row by a slim white rule. */
.signal {
  position: relative;
  height: calc(100svh - var(--masthead-h));
  min-height: 560px;
  background: #000;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Local texture: the signal is lifted above the document grain (see
   the clean-zone ladder) and carries its OWN copy of the PAPER
   colorway's grain instead — same in both themes. The dark dots +
   mottle vanish over its black but halftone the white marks (logo,
   rule, icons), exactly the paper colorway's print look. Sits above
   every child (↓ button peaks at z-index 2), never blocks hovers. */
.signal::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 10;
  pointer-events: none;
  background-image: url("../assets/textures/baked-grain-paper.png?v=2");
  background-size: 1728px 1152px;
}

/* the logo stage — a reel can play behind it (config → signal.video);
   until one is set, it's pure black */
.signal__stage {
  position: relative;
  flex: 3 1 0;
  min-height: 0;
}
.signal__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* difference layer — same trick as the hero: white artwork inverts
   against whatever plays behind; over plain black it stays white */
.signal__logo-wrap {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  mix-blend-mode: difference;
  pointer-events: none;
}
.signal__logo {
  width: min(48vw, 520px);
  max-height: 52vh;
  object-fit: contain;
}

/* SOCIALS ROW — icons rest white; hovering crossfades in the
   network's TRUE brand artwork (layered by js/main.js), lifts the
   icon into a slow drift, and breathes out a soft colored halo.
   NOTE: the halo (drop-shadow) is a USER-SANCTIONED exception to the
   no-shadow house rule, scoped to this row only. */
.signal__social {
  flex: 1 1 0;
  min-height: 150px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(2.5rem, 9vw, 7rem);
}
/* The drift's reach is a REGISTERED length so it can transition:
   the bob loop runs permanently (invisible at 0px) and hover just
   fades its amplitude up — so un-hovering glides the icon home from
   wherever it was mid-bob instead of snapping it back. */
@property --drift-amp {
  syntax: "<length>";
  inherits: true;
  initial-value: 0px;
}

.social-link {
  /* per-network halo colors set inline by js/main.js from config.js;
     --s-color only paints networks with no layered artwork (and the
     text-label fallback) */
  --s-color: #fff;
  --s-glow:  #fff;
  --s-glow2: var(--s-glow);
  display: grid;
  place-items: center;
  color: #fff;
  /* one clock for everything: scale, color, glow fade (below) and
     drift amplitude all move on the same .3s ease */
  transition: transform .3s ease, color .3s ease, --drift-amp .3s ease;
}
.social-link:hover,
.social-link:focus-visible {
  color: var(--s-color);
  transform: scale(1.06);
  --drift-amp: 3px;
}

.social-link__svg {
  /* big presence (1.5× the original size) — the vh cap keeps the
     row from choking on short screens */
  grid-area: 1 / 1;            /* both copies stack in the same cell */
  width: min(clamp(66px, 7.8vw, 108px), 15vh);
  height: auto;
  display: block;
  fill: currentColor;
  /* always running — amplitude (--drift-amp) gates its visibility */
  animation: social-drift 2.4s ease-in-out infinite;
}

/* Two stacked copies: white ink on top, brand artwork beneath.
   The artwork copy carries its halo PERMANENTLY — fading the copy's
   opacity fades glyph color and glow as one move, so nothing can
   snap in separately (filter interpolation is never involved). */
.social-link__svg--ink { transition: opacity .3s ease; }
.social-link__svg--color {
  opacity: 0;
  transition: opacity .3s ease;
  filter:
    drop-shadow(0 0 7px  color-mix(in srgb, var(--s-glow)  55%, transparent))
    drop-shadow(0 0 20px color-mix(in srgb, var(--s-glow2) 30%, transparent));
}
.social-link:hover .social-link__svg--ink,
.social-link:focus-visible .social-link__svg--ink   { opacity: 0; }
.social-link:hover .social-link__svg--color,
.social-link:focus-visible .social-link__svg--color { opacity: 1; }


/* text fallback if a network has no icon path registered in main.js */
.social-link__label {
  font-family: var(--font-mono);
  font-size: .8rem;
  letter-spacing: .2em;
  text-transform: uppercase;
}

/* links whose url is still "" in config.js — quietly waiting */
.social-link.is-unwired { cursor: help; }

@keyframes social-drift {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(calc(var(--drift-amp) * -1)); }
}


/* ─── 7. DESCRIPTION — EPWA font cycler ─────────────────────────── */
.desc {
  border-bottom: var(--rule);
  padding: 2.2rem 1.25rem 3.5rem;
}

.desc__eyebrow {
  margin-bottom: 2rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
/* stray registration mark — the printer never cleaned the plate */
.desc__eyebrow::after {
  content: "⊕";
  font-family: var(--font-mono);
  font-size: 1.5rem;
  color: var(--red);
  opacity: .6;
}

.desc__grid {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  gap: 0 3rem;
  align-items: start;
}

/* The cycler word sits in an inner span; js/main.js applies each
   font's own size + letter-spacing corrections (from config.js) so
   "EPWA" keeps consistent optical weight across wildly different
   typefaces instead of jumping between cramped and sprawling. */
.desc__cycler {
  font-size: clamp(4.5rem, 15vw, 14rem);
  text-transform: uppercase;
  display: flex;
  align-items: flex-end;      /* baseline stays planted while fonts swap */
  height: 1.08em;
  overflow: visible;
  word-break: keep-all;
}
.desc__cycler .cycler-word {
  display: inline-block;
  font-family: var(--font-cycle-1);
  font-weight: 900;
  line-height: .85;
  letter-spacing: -0.02em;
}

.desc__copy {
  border-left: var(--rule);
  padding-left: 2rem;
  padding-top: .5rem;
}

.desc__lede {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.35rem;
  line-height: 1.25;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  margin-bottom: 1.2rem;
}

.desc__body {
  font-family: var(--font-body);
  margin-bottom: 1.6rem;
  white-space: pre-line;   /* line breaks in config.js are kept */
}

.desc__editnote {
  color: var(--olive);
  transform: rotate(-1deg);
  display: inline-block;
  font-size: .72rem;
}


/* ─── 8. SELECTOR — modular 2×2 index ───────────────────────────── */
/* The tiles fill the whole screen (header row stays its own size) */
.selector {
  padding: 0;
  display: flex;
  flex-direction: column;
  min-height: calc(100svh - var(--masthead-h));
}

.selector__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.6rem 1.25rem 1.2rem;
}
.selector__title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.2rem, 6vw, 4rem);
  letter-spacing: -0.02em;
  line-height: 1;
}
.selector__note { color: var(--olive); }

/* gap+background trick: 3px gaps read as ink rule lines */
.selector__grid {
  flex: 1;                 /* tiles absorb the rest of the screen */
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-auto-rows: 1fr;     /* rows share the height equally */
  gap: 3px;
  background: var(--ink);
  border-top: var(--rule);
}

.sel-tile {
  position: relative;
  background: var(--paper);
  min-height: clamp(260px, 38vh, 420px);
  padding: 1.2rem 1.25rem;
  display: flex;
  flex-direction: column;
  text-align: left;
  overflow: hidden;
  contain: layout paint;
}
.sel-tile:hover { background: var(--red); color: var(--paper); }

.sel-tile__num {
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .15em;
  color: var(--red);
}
.sel-tile:hover .sel-tile__num { color: var(--paper); }

/* Framed like a mounted print: ink border → slim manilla sliver →
   thin inner outline → the artwork (same proportions as the original
   placeholder frames). Hugs whatever image the tile is given. */
.sel-tile__frame {
  align-self: flex-end;
  display: block;
  width: min(64%, 340px);
  border: var(--rule);
  background: var(--paper-deep);   /* the manilla showing through */
  padding: 3px;
  margin: .8rem 0;
}
.sel-tile__img {
  display: block;
  width: 100%;
  height: auto;
  border: 2px solid var(--ink);    /* inner outline */
}
.sel-tile:hover .sel-tile__frame { border-color: var(--paper); }
.sel-tile:hover .sel-tile__img { border-color: var(--paper); }

.sel-tile__title {
  margin-top: auto;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(1.8rem, 4.5vw, 3.4rem);
  line-height: .95;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}

.sel-tile__go {
  position: absolute;
  right: 1.25rem;
  bottom: 1.2rem;
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .12em;
}


/* ─── 8.5 DISPATCH — activity log + newsletter framework ────────── */
.dispatch {
  border-top: var(--rule-heavy);
  padding: 2rem 1.25rem 3.5rem;
}

.dispatch__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem 2rem;
  flex-wrap: wrap;
  margin-bottom: 2rem;
}
.dispatch__title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.2rem, 6vw, 4rem);
  line-height: .9;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}

.dispatch__grid {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: 2.5rem;
  align-items: start;
}

/* The log: dated ledger rows */
.dispatch__log { border-top: var(--rule); }

.d-entry {
  display: grid;
  grid-template-columns: 110px 1fr;
  gap: 1.2rem;
  padding: 1.1rem 0 1.2rem;
  border-bottom: 2px solid var(--ink);
}
.d-entry__date {
  font-family: var(--font-mono);
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .12em;
  color: var(--red);
  padding-top: .35rem;
}
.d-entry__title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 1.35rem;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  line-height: 1.05;
}
.d-entry__blurb {
  margin-top: .4rem;
  font-size: .97rem;
  max-width: 62ch;
  white-space: pre-line;
}

.dispatch__empty {
  font-family: var(--font-mono);
  border: 3px dashed var(--olive);
  padding: 1.6rem;
  line-height: 1.8;
  font-size: .8rem;
}

/* The newsletter slot — framework only, nothing wired */
.newsletter {
  position: relative;
  border: var(--rule);
  background: var(--paper-deep);
  padding: 1.6rem 1.5rem 1.4rem;
}
.newsletter__stamp {
  position: absolute;
  top: -1rem;
  right: 1rem;
}
.newsletter__title {
  font-family: var(--font-poster);
  font-size: 1.7rem;
  letter-spacing: -0.02em;
  line-height: 1;
  margin-bottom: .7rem;
}
.newsletter__pitch {
  font-size: .95rem;
  margin-bottom: 1.2rem;
  max-width: 42ch;
}
.newsletter__form { display: flex; }
.newsletter__input {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: .82rem;
  letter-spacing: .05em;
  color: var(--ink);
  background: var(--paper);
  border: var(--rule);
  padding: .7rem .8rem;
}
.newsletter__input::placeholder { color: var(--olive); }
.newsletter__btn {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: .95rem;
  letter-spacing: .02em;
  text-transform: uppercase;
  background: var(--ink);
  color: var(--paper);
  border: var(--rule);
  border-left: none;
  padding: .7rem 1.2rem;
}
.newsletter__btn:hover { background: var(--red); }
.newsletter__note {
  margin-top: .9rem;
  color: var(--olive);
  font-size: .7rem;
  line-height: 1.6;
}


/* ─── 8.6 ACHIEVEMENTS — the season's goal board ────────────────── */
/* THE BOARD's grid-paper treatment, repurposed: one sticky note per
   goal. The note's paper stock IS its rarity — yellowed (bronze) →
   plain (silver) → manilla (gold) → signal red (platinum). Done
   notes take a red UNLOCKED rubber stamp; locked chained goals hang
   as dashed ghost notes under their parent. Notes keep their exact
   colors in BOTH colorways — physical paper, same trick as the
   folders. Built by js/main.js from config → achievements. */
.achieve {
  border-top: var(--rule-heavy);
  background-color: var(--paper-deep);
  /* the same graph-paper plate THE BOARD uses */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='112' height='112'%3E%3Cpath d='M28 0v112M56 0v112M84 0v112M0 28h112M0 56h112M0 84h112' stroke='%237A7A52' stroke-opacity='.28' stroke-width='1'/%3E%3Cpath d='M0 .5h112M.5 0v112' stroke='%237A7A52' stroke-opacity='.55' stroke-width='1'/%3E%3C/svg%3E");
  background-size: 112px 112px;
}

.achieve__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem 2rem;
  flex-wrap: wrap;
  padding: 1.4rem 1.25rem;
  border-bottom: var(--rule);
  background: var(--paper);
}
.achieve__lead {
  display: flex;
  align-items: baseline;
  gap: 1.4rem;
  flex-wrap: wrap;
}
.achieve__title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.2rem, 6vw, 4rem);
  line-height: .9;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}
/* header meta: the red countdown to next season over the unlock
   tally — the "little text" slot, same spot the board's note sits */
.achieve__meta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .4rem;
}
.achieve__countdown {
  color: var(--red);
  font-size: .95rem;
  font-weight: 700;
  letter-spacing: .1em;
}
.achieve__count {
  color: var(--olive);
  font-size: .72rem;
  letter-spacing: .14em;
}

/* The corkboard body: a real grid, max 4 notes per row, stretched to
   FILL the page width (no cap) — on a wide screen the squares get big
   and the whole board runs tall, so you scroll down through the work. */
.achieve__paper {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2.25rem;
  align-items: start;
  padding: 3rem clamp(1.25rem, 5vw, 4rem) 4rem;
}

/* THE NOTE — flat square of real paper, adhesive band up top. Same
   size for every note (the grid cell sets it); aspect-ratio keeps it
   square. Hardcoded colors on purpose: identical in both colorways. */
.a-note {
  position: relative;
  aspect-ratio: 1 / 1;
  padding: 1.5rem 1.3rem 1.1rem;
  display: flex;
  flex-direction: column;
  gap: .6rem;
  background: #E8E0D0;   /* silver = plain stock (default) */
  color: #1A1208;
  transform: rotate(-.8deg);
  overflow: hidden;      /* keep the big fitted handwriting inside */
}
/* the glue strip */
.a-note::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 13px;
  background: rgba(26, 18, 8, .13);
}
/* hand-slapped jitter — js deals these in rotation */
.a-note--r1 { transform: rotate(-1.6deg); }
.a-note--r2 { transform: rotate(.9deg); }
.a-note--r3 { transform: rotate(-.5deg); }
.a-note--r4 { transform: rotate(1.7deg); }

.a-note__text {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-family: var(--font-note);   /* note-only face — set in css/fonts.css */
  font-size: 2rem;                 /* fallback; js fits each note's size */
  line-height: 1.05;
  /* a little print texture: screen-print wear on the glyph edges +
     a faint red ink-misregistration ghost, like the display type */
  filter: url(#rough-ink);
  text-shadow: .018em .016em 0 rgba(181, 39, 30, .3);
}
.a-note__tier {
  align-self: flex-end;
  font-size: .6rem;
  font-weight: 700;
  letter-spacing: .22em;
  color: #7A7A52;
}

/* rarity = paper stock (note size stays uniform — the grid sets it) */
.a-note--bronze   { background: #D9CDB4; }   /* yellowed */
.a-note--gold     { background: #D9C68F; }   /* manilla  */
.a-note--gold .a-note__tier { color: #1A1208; }
.a-note--platinum { background: #B5271E; color: #E8E0D0; }
.a-note--platinum::before { background: rgba(0, 0, 0, .22); }
.a-note--platinum .a-note__tier { color: #E8E0D0; }

/* done: the red rubber stamp hits the corner */
.a-note--done::after {
  content: "UNLOCKED ✓";
  position: absolute;
  top: 1.5rem;
  right: -.6rem;
  transform: rotate(-7deg);
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: .78rem;
  letter-spacing: .18em;
  color: var(--red);
  border: 3px solid var(--red);
  padding: .3rem .55rem .24rem;
}
/* red-on-red rescue: a finished platinum stamps in paper tone */
.a-note--platinum.a-note--done::after {
  color: #E8E0D0;
  border-color: #E8E0D0;
}

/* locked chained goals: a ghost note — dashed outline, nothing
   pinned yet. Vars (not hardcodes): the ghost isn't paper, it's a
   reserved space on the board, so it follows the colorway. */
.a-note--locked {
  background: none;
  border: 3px dashed var(--olive);
  color: var(--olive);
}
.a-note--locked::before { display: none; }
.a-note--locked .a-note__tier { color: var(--olive); }
.a-note--locked.a-note--platinum .a-note__tier { color: var(--red); }
.a-note__lock {
  font-size: .6rem;
  font-weight: 700;
  letter-spacing: .22em;
}

.achieve__empty {
  font-family: var(--font-mono);
  color: var(--ink);
  background: var(--paper);
  border: 3px dashed var(--olive);
  padding: 2rem;
  max-width: 46ch;
  line-height: 1.8;
}


/* ─── 9. STAGE — full-screen 3D carousel ────────────────────────── */
/* No header strip — the carousel owns the full screen. The counter
   floats top-right; the square ↓ button (bottom right) scrolls down
   to THE BOARD. */
.stage {
  position: relative;
  min-height: calc(100svh - var(--masthead-h));
  display: flex;
  flex-direction: column;
  /* no border here — it would eat the last pixels of the full-screen
     view; the heavy seam lives on .board's top edge, below the fold */
}

.stage__counter {
  position: absolute;
  top: 1.2rem;
  right: 1.25rem;
  z-index: 9993;   /* above the lifted carousel (9992), under masthead */
  font-size: 1rem;
  border: 3px solid var(--ink);
  background: var(--paper);
  padding: .35em .7em;
  transform: rotate(1.5deg);
}

.stage__down {
  position: absolute;
  bottom: 1.25rem;
  right: 1.25rem;
  z-index: 9993;   /* above the lifted carousel (9992) so it stays clickable */
  border: var(--rule);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: .72rem;
  letter-spacing: .16em;
  line-height: 1;
  padding: .8rem 1rem;
}
.stage__down:hover { background: var(--ink); color: var(--paper); }
.stage__down:active { background: var(--red); color: var(--paper); }

.carousel {
  flex: 1;
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: 1rem .75rem;
  min-height: 0;
}

.carousel__viewport {
  flex: 1;
  align-self: stretch;
  perspective: 2000px;
  display: grid;
  place-items: center;
  min-height: 0;          /* sized by the stage, not a fixed clamp */
  overflow: hidden;
}

/* The ring scales from the real available space: nearly the full
   stage height, up to 60% of the viewport width. Panels hug their
   images inside these bounds (js/carousel.js → sizePanel). */
.carousel__ring {
  position: relative;
  width: min(60vw, 860px);
  height: calc(100% - 2.5rem);
  transform-style: preserve-3d;
  transition: transform 520ms cubic-bezier(.22, .8, .24, 1);
}

/* Modular panel: hugs its image's exact aspect ratio — js/carousel.js
   sizes each frame to its artwork (10px matte + caption strip), so a
   landscape piece gets a landscape panel, a poster gets a tall one. */
.c-panel {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 74%;      /* pre-decode default; JS replaces per image */
  display: flex;
  flex-direction: column;
  background: var(--paper-deep);
  border: var(--rule);
  padding: 10px;
  backface-visibility: hidden;
  cursor: pointer;
}
.c-panel__img {
  display: block;
  width: 100%;
  height: auto;
}
.c-panel__img:not([src]) {
  aspect-ratio: 4 / 3;
  background: var(--paper);
}
.c-panel__strip {
  border-top: 2px solid var(--ink);
  margin-top: 10px;
  padding-top: 6px;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  display: flex;
  justify-content: space-between;
  gap: .5rem;
}
.c-panel__strip em { font-style: normal; color: var(--red); }

.c-panel:not(.is-front) { opacity: .45; }
.c-panel.is-front { cursor: zoom-in; }

/* Square stamp arrows (shared by carousel + theater) */
.c-arrow {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .2rem;
  border: var(--rule);
  background: var(--paper);
  width: 64px;
  height: 64px;
  padding: 0;
  flex: 0 0 auto;
}
.c-arrow__glyph {
  font-family: var(--font-poster);
  font-size: 1.65rem;   /* lone glyph — a touch bigger without labels */
  line-height: 1;
}
.c-arrow:hover { background: var(--ink); color: var(--paper); }
.c-arrow:active { background: var(--red); color: var(--paper); }

/* (.stage__caption retired — replaced by the ↓ button) */


/* ─── 10. BOARD — grid paper flat file ──────────────────────────── */
.board {
  border-top: var(--rule-heavy);   /* the seam under the full-screen stage */
  background-color: var(--paper-deep);
  /* graph-paper lines drawn as SVG — flat strokes, no gradients */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='112' height='112'%3E%3Cpath d='M28 0v112M56 0v112M84 0v112M0 28h112M0 56h112M0 84h112' stroke='%237A7A52' stroke-opacity='.28' stroke-width='1'/%3E%3Cpath d='M0 .5h112M.5 0v112' stroke='%237A7A52' stroke-opacity='.55' stroke-width='1'/%3E%3C/svg%3E");
  background-size: 112px 112px;
}

.board__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.4rem 1.25rem;
  border-bottom: var(--rule);
  background: var(--paper);
}
.board__title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(1.8rem, 4.5vw, 3rem);
  letter-spacing: -0.02em;
}
.board__note { color: var(--olive); }

.board__paper {
  padding: 3.5rem clamp(1.25rem, 5vw, 4rem) 4.5rem;
  min-height: 55vh;
  columns: 320px 3;
  column-gap: 2.75rem;
}

/* Work pinned to the board — taped, slightly askew */
.b-item {
  break-inside: avoid;
  margin-bottom: 2.75rem;
  background: var(--paper);
  border: var(--rule);
  padding: 9px;
  position: relative;
  transform: rotate(-.7deg);
}
.b-item:nth-child(even) { transform: rotate(.8deg); }
.b-item:nth-child(3n)   { transform: rotate(-1.3deg); }

/* the tape strip */
.b-item::before {
  content: "";
  position: absolute;
  top: -12px;
  left: 50%;
  width: 92px;
  height: 24px;
  background: var(--olive);
  opacity: .55;
  transform: translateX(-50%) rotate(-2deg);
}

.b-item__img { width: 100%; }
.b-item__img:not([src]) {
  aspect-ratio: 4 / 3;
  background: var(--paper-deep);
}
.b-item__cap {
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  border-top: 2px solid var(--ink);
  margin-top: 8px;
  padding-top: 6px;
  display: flex;
  justify-content: space-between;
  gap: .5rem;
}
.b-item__cap em { font-style: normal; color: var(--red); }

.board__empty {
  font-family: var(--font-mono);
  color: var(--ink);
  background: var(--paper);
  border: 3px dashed var(--olive);
  padding: 2rem;
  max-width: 46ch;
  line-height: 1.8;
}


/* ─── 11. VIDEO — retro file manager ────────────────────────────── */
/* An old-OS explorer window: title bar, C:\ path readout, and a
   grid (3 across max) of manilla folders → video cards. Folders are
   MANILLA IN BOTH COLORWAYS via the fixed --manilla token. */
.explorer {
  /* full-bleed — flush to the sheet edges, no surrounding gap.
     grid paper lives here so it shows behind folders AND below the
     tight files block. */
  min-height: calc(100svh - var(--masthead-h));
  display: flex;
  flex-direction: column;
  background-color: var(--paper);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='112' height='112'%3E%3Cpath d='M28 0v112M56 0v112M84 0v112M0 28h112M0 56h112M0 84h112' stroke='%237A7A52' stroke-opacity='.28' stroke-width='1'/%3E%3Cpath d='M0 .5h112M.5 0v112' stroke='%237A7A52' stroke-opacity='.55' stroke-width='1'/%3E%3C/svg%3E");
  background-size: 112px 112px;
}

.explorer__titlebar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  background: var(--ink);
  color: var(--paper);
  padding: .45rem .8rem;
}
.explorer__apptitle {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 1rem;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.explorer__winbtns { display: flex; gap: .45rem; }
.explorer__winbtn {
  display: block;
  width: 14px;
  height: 14px;
  border: 2px solid var(--paper);
}
.explorer__winbtn--min   { background: transparent; }
.explorer__winbtn--max   { background: var(--olive); }
.explorer__winbtn--close { background: var(--red); }

.explorer__pathbar {
  display: flex;
  align-items: center;
  gap: .8rem;
  padding: .4rem .8rem;
  background: var(--paper-deep);
  border-bottom: var(--rule);
  font-size: .78rem;
  letter-spacing: .08em;
}
.explorer__pathtext { flex: 1; min-width: 0; }
#explorer-count { color: var(--olive); white-space: nowrap; }

/* real explorer-style back / forward buttons — CSS-drawn triangles
   in a retro double-framed key */
.explorer__nav { display: flex; gap: .35rem; }
.explorer__navbtn {
  position: relative;
  width: 42px;
  height: 30px;
  border: 2px solid var(--ink);
  background: var(--paper);
  color: var(--ink);
  font-size: 0;                            /* hide the fallback glyph */
  padding: 0;
}
.explorer__navbtn::before {                /* inner retro frame line */
  content: "";
  position: absolute;
  inset: 2px;
  border: 1px solid currentColor;
  opacity: .3;
}
.explorer__navbtn::after {                 /* the triangle */
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 0;
  height: 0;
  border-top: 7px solid transparent;
  border-bottom: 7px solid transparent;
}
#explorer-back::after { border-right: 11px solid currentColor; margin-left: -2px; }
#explorer-fwd::after  { border-left: 11px solid currentColor; margin-left: 2px; }
.explorer__navbtn:not(:disabled):hover { background: var(--ink); color: var(--paper); }
.explorer__navbtn:not(:disabled):active { background: var(--red); color: var(--paper); }
.explorer__navbtn:disabled { opacity: .3; }

.explorer__grid {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* 3 across, max */
  gap: 2rem 1.5rem;
  align-content: start;
  padding: 2rem 1.5rem 2.5rem;
}

/* FILES view — video cards tile tight: no gaps, cards fused to a
   3px ink grid (same trick as the 2×2 index), content-height block
   so grid paper still shows below. */
.explorer__grid--files {
  flex: 0 0 auto;
  gap: 3px;
  /* 3px ink padding = the same seam on the page edges (left/right/
     bottom); the top edge is the pathbar's border-bottom */
  padding: 0 3px 3px;
  background: var(--ink);
}

/* shared item behavior — retro dashed selection on hover */
.explorer__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .7rem;
  padding: 1rem .75rem;
  text-align: center;
  cursor: pointer;
  text-decoration: none;
  color: inherit;
  background: none;
  border: none;
  font: inherit;
}
.explorer__item:hover { outline: 2px dashed var(--ink); outline-offset: 2px; }
.explorer__item:hover .explorer__label { background: var(--red); color: #F0EDE4; }

/* THE FOLDER — manilla PNG icons (recolored from the source art).
   Closed at rest; on hover it crossfades to the open folder and
   grows a touch. Manilla reads on both colorways. */
.folder-icon {
  position: relative;
  width: min(380px, 92%);
  transition: transform 220ms cubic-bezier(.34, .7, .3, 1);
}
.folder-img {
  display: block;
  width: 100%;
  height: auto;
  transition: opacity 220ms ease;
}
.folder-img--open {                        /* stacked over the closed one */
  position: absolute;
  inset: 0;
  opacity: 0;
}
.explorer__item:hover .folder-icon { transform: scale(1.05); }
.explorer__item:hover .folder-img--closed { opacity: 0; }
.explorer__item:hover .folder-img--open { opacity: 1; }

.explorer__label {
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: .8rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: .15em .5em;
  line-height: 1.5;
}
.explorer__meta {
  font-family: var(--font-mono);
  font-size: .66rem;
  letter-spacing: .12em;
  color: var(--olive);
}

/* VIDEO CARD — thumbnail with a caption strip fused underneath
   (title left, views right in red — the design-caption pattern).
   Fills its grid cell edge to edge; the 3px ink gaps are the seams. */
.explorer__file {
  align-items: stretch;                    /* override centered item */
  gap: 0;
  padding: 0;
  background: var(--paper);
  overflow: hidden;
}
.explorer__file:hover { outline: none; }   /* seams do the separating */
.explorer__file:hover .explorer__cap { background: var(--red); }
.explorer__file:hover .explorer__cap-title,
.explorer__file:hover .explorer__cap-views { color: #F0EDE4; }

.explorer__thumb {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
  border: none;                            /* the card + seams frame it */
  background: var(--paper-deep);
}
.explorer__thumb--missing {
  display: grid;
  place-content: center;
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .24em;
  color: var(--ink);
  /* flat hazard stripes on manilla — retro test card */
  background-color: var(--manilla);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28'%3E%3Cpath d='M-7 14 L14 -7 L21 0 L0 21 Z M7 28 L28 7 L35 14 L14 35 Z' fill='%231A1208' fill-opacity='.16'/%3E%3C/svg%3E");
  background-size: 28px 28px;
}
html[data-theme="dark"] .explorer__thumb--missing { color: #1A1208; }

.explorer__cap {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .6rem;
  border-top: var(--rule);                 /* fuses cap to the thumb */
  padding: .5rem .6rem .55rem;
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  text-align: left;
}
.explorer__cap-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.explorer__cap-views {
  font-style: normal;
  color: var(--red);
  white-space: nowrap;
}

.explorer__empty {
  grid-column: 1 / -1;
  border: 3px dashed var(--olive);
  padding: 2rem;
  font-family: var(--font-mono);
  font-size: .8rem;
  line-height: 1.9;
  text-align: center;
  color: var(--olive);
}

/* kept for the carousel's empty-state slate */
.screen-placeholder {
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 1rem;
  background: var(--ink);
  color: var(--paper);
  text-align: center;
  font-family: var(--font-mono);
  font-size: .8rem;
  line-height: 1.8;
  padding: 1rem;
}


/* ─── 12. STUBS — departments in development ────────────────────── */
.stub {
  min-height: calc(88svh - var(--masthead-h));
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 3rem 1.25rem 4rem;
  position: relative;
}
.stub--full {
  min-height: calc(100svh - var(--masthead-h));   /* full page */
  overflow: hidden;                                /* clip the tape ends */
}

/* CAUTION TAPE — hazard yellow bands crossing the section, fixed
   colors in both colorways (like the manilla folders). */
.tape {
  position: absolute;
  left: -12%;
  width: 124%;
  padding: .55rem 0;
  background: #D8A92B;                    /* aged hazard yellow */
  color: #14100A;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(1.1rem, 2.6vw, 1.9rem);
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;                            /* sits UNDER the text (z-1) */
}
.tape span { display: inline-block; }
.tape--a { top: 40%; transform: rotate(-13deg); }
.tape--b { top: 54%; transform: rotate(11deg); }

/* stub text rides above the tape */
.stub__stamp, .stub__title, .stub__note { position: relative; z-index: 1; }
.stub__stamp {
  position: absolute;
  top: clamp(2rem, 12vh, 6rem);
  right: clamp(1rem, 8vw, 6rem);
  transform: rotate(8deg);
}
.stub__title {
  font-family: var(--font-poster);
  font-size: clamp(3.4rem, 14vw, 12rem);
  line-height: .92;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}
.stub__note {
  margin-top: 2rem;
  color: var(--olive);
  line-height: 2;
  border-left: var(--rule);
  padding-left: 1.2rem;
}


/* ─── 12.5 PRODUCT DESIGN — split landing + segments ────────────── */
.duo {
  display: flex;
  min-height: calc(100svh - var(--masthead-h));
}

.duo__half {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.7rem;
  padding: 2.5rem 2rem;
  text-align: center;
  cursor: pointer;
}
.duo__half + .duo__half { border-left: 2px solid var(--ink); }  /* the thin divider */

.duo__logo {
  display: block;
  width: min(46%, 300px);
  height: auto;
}

/* reserved slot while a product's logo is pending */
.duo__logo-slot {
  width: min(46%, 300px);
  aspect-ratio: 1;
  border: 3px dashed currentColor;
  opacity: .5;
  display: grid;
  place-content: center;
  font-family: var(--font-mono);
  font-size: .66rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  line-height: 2;
  padding: 1rem;
}

.duo__name {
  font-family: "Arial Black", "Archivo Black", sans-serif;
  font-size: clamp(1.7rem, 3.6vw, 3rem);
  line-height: 1;
  letter-spacing: -0.01em;
  border-bottom: 6px solid transparent;   /* accent set inline per product */
  padding-bottom: .22em;
}

.duo__cue {
  font-family: var(--font-mono);
  font-size: .64rem;
  letter-spacing: .22em;
  opacity: .45;
}
.duo__half:hover .duo__cue { opacity: 1; }

/* scaffolded per-product segments below the landing */
.p-seg {
  border-top: var(--rule-heavy);
  padding: 2rem 1.25rem 4rem;
  min-height: 55vh;
}
.p-seg__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem 2rem;
  flex-wrap: wrap;
  margin-bottom: 1.8rem;
}
.p-seg__title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.2rem, 6vw, 4rem);
  line-height: .9;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}
.p-seg__note {
  font-family: var(--font-mono);
  color: var(--olive);
  border-left: var(--rule);
  padding-left: 1.2rem;
  line-height: 2;
  font-size: .8rem;
  max-width: 60ch;
}


/* ─── 13. COLOPHON — logo mark, everything centered ─────────────── */
.colophon {
  background: var(--ink);
  color: var(--paper);
  border-top: 6px solid var(--red);
  padding: .9rem 1.25rem .85rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: .5rem;
}
.colophon__mark {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .7rem;                              /* keep FOR / YAN close */
}
.colophon__flank {
  font-family: "Franklin Gothic Heavy", "Arial Black", var(--font-poster);
  font-weight: 400;
  font-size: clamp(2.5rem, 7.5vw, 4.6rem);
  line-height: 1;
  letter-spacing: -0.01em;
  transform: translateY(.26em);            /* sit a little lower */
}
.colophon__logo {
  width: min(250px, 46vw);
  height: auto;
}
/* the colophon band inverts with the theme (bg = ink token): in the
   dark colorway it's a LIGHT strip, so the white mark flips to dark */
html[data-theme="dark"] .colophon__logo { filter: invert(1); }

/* all colophon text on ONE line (wraps only when it must) */
.colophon__cols {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: baseline;
  gap: .4rem 2.2rem;
  color: var(--paper-deep);
  font-size: .7rem;
  letter-spacing: .12em;
}


/* ─── 14. LIGHTBOX — click-to-zoom ──────────────────────────────── */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 10000;
  background: rgba(26, 18, 8, .95);
  display: grid;
  place-items: center;
  padding: 3.5rem 1.5rem 2rem;
}
.lightbox[hidden] { display: none; }

.lightbox__figure {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .9rem;
  max-width: 100%;
}
.lightbox__img {
  max-width: min(92vw, 1400px);
  max-height: 80vh;
  object-fit: contain;
  border: 4px solid var(--paper);
  background: var(--paper-deep);
}
.lightbox__caption {
  color: var(--paper);
  letter-spacing: .12em;
  text-transform: uppercase;
}
.lightbox__close {
  position: absolute;
  top: 1.2rem;
  right: 1.2rem;
  color: var(--paper);
  border: 3px solid var(--paper);
  padding: .4rem .9rem;
  display: flex;
  align-items: center;
  gap: .6rem;
  font-family: var(--font-poster);
  font-size: 1.3rem;
  line-height: 1;
}
.lightbox__close .mono { font-size: .6rem; letter-spacing: .2em; }
.lightbox__close:hover { background: var(--red); border-color: var(--red); }


/* ─── 15. RESPONSIVE ────────────────────────────────────────────── */
/* Render budget: skip offscreen layout/paint where supported. */
@supports (content-visibility: auto) {
  .selector,
  .dispatch,
  .board,
  .p-seg {
    content-visibility: auto;
  }
  /* NOTE: .achieve is deliberately NOT content-visibility'd — the
     per-note font fit needs the section laid out to measure it, and
     CV skips layout while offscreen. It's only 9 notes; cheap. */

  .selector { contain-intrinsic-size: 900px; }
  .dispatch { contain-intrinsic-size: 720px; }
  .board { contain-intrinsic-size: 1300px; }
  .p-seg { contain-intrinsic-size: 520px; }
}

@media (max-width: 980px) {
  .desc__grid { grid-template-columns: 1fr; gap: 2rem 0; }
  .dispatch__grid { grid-template-columns: 1fr; }
  .desc__copy { border-left: none; border-top: var(--rule); padding: 1.5rem 0 0; }
  .explorer__grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 760px) {
  /* ── ACHIEVEMENTS: 2-up notes, tighter board ──────────────────── */
  .achieve__paper {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.25rem;
    padding: 2rem 1rem 3rem;
  }
  .achieve__meta { align-items: flex-start; }

  /* ── MASTHEAD: one line + hamburger page menu ─────────────────── */
  .masthead {
    position: relative;                 /* anchors the tab dropdown */
    align-items: center;
    gap: 0 .7rem;
    padding: 0 .8rem;
  }
  .masthead__menu { display: flex; }    /* the 3-line picker appears */
  .masthead__meta { display: none; }
  .masthead__theme { margin-left: auto; }   /* meta hidden — toggle keeps the corner */
  .masthead__brand { padding: .45rem 0; font-size: 1.7rem; }

  /* Folder tabs collapse into a dropdown under the bar — hidden until
     the hamburger adds .menu-open, then stacked full width. */
  .tabs {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 9995;                      /* over content, under lightbox */
    display: none;
    flex-direction: column;
    overflow: visible;                  /* undo desktop's scroll strip */
    background: var(--paper);
    border-bottom: var(--rule);
  }
  .masthead.menu-open .tabs { display: flex; }
  .tab {
    font-size: 1rem;
    padding: .85rem 1rem;
    background: var(--paper);
    border: none;
    border-bottom: 2px solid var(--ink);
  }
  .tab + .tab { margin-left: 0; }       /* undo the desktop border-smush */
  .tab.is-active {
    border-top: none;
    border-left: 6px solid var(--red);  /* active marker moves to the side */
    margin-bottom: 0;
    background: var(--paper-deep);
  }

  /* ── HERO: show the reel FULL, blurred fill behind (no crop) ──── */
  .hero__video--fg { object-fit: contain; }
  .hero__video--bg {
    display: block;
    object-fit: cover;
    transform: scale(1.12);             /* over-scan hides the blurred edge */
    filter: blur(26px);
  }

  /* ── SIGNAL: bigger logo share, tighter icon row ──────────────── */
  .signal__logo { width: min(70vw, 400px); }
  /* bottom padding floats the icons clear of the ↓ square */
  .signal__social { gap: clamp(1rem, 5vw, 2rem); padding: 0 1rem 3.5rem; }
  .social-link__svg { width: min(clamp(57px, 16.5vw, 81px), 15vh); }

  /* ── CAROUSEL: lift the wrapped arrows clear of ALT VIEW ──────── */
  .carousel {
    flex-wrap: wrap;
    justify-content: center;
    gap: 1rem;
    padding-bottom: 4.25rem;            /* room for the ALT VIEW button */
  }
  /* arrows stay square on mobile, side by side under the ring;
     ring gets explicit dims (the % height can't resolve here) */
  .carousel__viewport { flex-basis: 100%; order: -1; min-height: clamp(300px, 52vh, 560px); }
  .carousel__ring { width: min(86vw, 540px); height: min(54vh, 560px); }
  .stage__down { bottom: .9rem; right: .9rem; padding: .6rem .8rem; font-size: .66rem; }

  .explorer { margin: .75rem; }
  .explorer__grid { grid-template-columns: 1fr; gap: 1.6rem; }

  .selector__grid { grid-template-columns: 1fr; }

  /* ── PRODUCT: two products split the page 50/50, nothing clipped ─ */
  .duo { flex-direction: column; }
  .duo__half {
    flex: 1 1 0;
    min-height: 0;                      /* split the container equally —
                                          50svh each used to overflow */
    padding: 1.5rem 1.25rem;
    gap: 1rem;
  }
  .duo__logo, .duo__logo-slot { width: min(42%, 190px); }
  .duo__half + .duo__half {
    border-left: none;
    border-top: 2px solid var(--ink);   /* divider rotates with the stack */
  }
}


/* ─── 16. REDUCED MOTION ────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .hero__ticker span { animation: none; }
  .sheet.is-leaving,
  .sheet.is-covering { animation-duration: 1ms; animation-delay: 0ms; }
  .carousel__ring { transition: none; }
  .custom-cursor { transition: none; }
  .social-link__svg { animation: none; }
}
