/* ==========================================================================
   PrizmaCore — Prism Signal design system CSS
   Ported from _redesign-reference/prism-signal-ii.template.html
   Source of truth: _brand-lock.md (v2, locked 2026-08-15)

   Page-agnostic: no homepage content is hardcoded here. Any page that
   includes this file + assets/fonts.html + assets/flow.js can use any
   component documented in assets/COMPONENTS.md.

   Fonts: loaded via Google Fonts links in assets/fonts.html (Inter Tight
   300/400/500/600/800 — the single house family since round 10) — NOT
   embedded here. Do not add @font-face / base64 font blocks to this file.
   ========================================================================== */

:root{
  --bg:#F8F8F7;
  --surface:#FFFFFF;
  --hairline:#EAEAE7;
  --rule:#DBDBD7;
  --ink:#191919;
  --ink-hi:#333331;
  --muted:#6B6B68;
  --blue:#2151E8;
  --blue-deep:#1A41BE;
  --ice:#DEEDFC;
  --mint:#DFF4EC;
  --fade-text:linear-gradient(96deg,#A89B6B 0%,#C9B98E 38%,#D9C9A5 70%,#EFE9DA 100%);
  --sans:'Inter Tight',ui-sans-serif,'Helvetica Neue',Arial,sans-serif;
  /* utility face (round 10): the mono was retired sitewide — every label,
     eyebrow and caption now sets in the house sans. The variable name stays
     so page-local styles keep working. */
  --mono:'Inter Tight',ui-sans-serif,'Helvetica Neue',Arial,sans-serif;
  --serif:Georgia,'Times New Roman',serif;

  /* transition layer — flow.js writes these live (see §5 of the brand lock) */
  --vel:0;      /* 0-1 normalised scroll velocity */
  --sm:0px;     /* smoothed scroll position */

  /* shared grain tiles — see the FILM GRAIN STANDARD block below */
  --noise-fine:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.74' numOctaves='1' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  --noise-paper:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.4' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='0.085' intercept='0.915'/%3E%3CfeFuncG type='linear' slope='0.085' intercept='0.915'/%3E%3CfeFuncB type='linear' slope='0.085' intercept='0.915'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23p)'/%3E%3C/svg%3E");
  --noise-coarse:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='320'%3E%3Cfilter id='c'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.28' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='320' height='320' filter='url(%23c)'/%3E%3C/svg%3E");
}

/* ==========================================================================
   PALETTE SYSTEM — brand-lock v2.2
   One attribute selects a page's whole dark identity:
     <body data-palette="saigon">        (omit → Saigon, the house parent)
   Every palette must ship the full token set below and clear §6 on its own
   grounds. flow.js reads the same attribute for its aurora colours.
   Parents: saigon · london.  Blends: ember · harbour · fieldwork.
   ========================================================================== */
:root,
[data-palette="saigon"]{
  /* counter-accents (v2.4): complementary + contrasting counterpoints.
     --acc2/--acc3 are tuned for the LIGHT ground, --acc2-on/--acc3-on for
     dark fields. Never used as large fills — accents, rules, numerals,
     washes and hovers only. */
  --acc2:#4A2340; --acc2-rgb:74,35,64;
  --acc3:#12463F; --acc3-rgb:18,70,63;
  --acc2-on:#C79ABF; --acc2-on-rgb:199,154,191;
  --acc3-on:#6FBDAF; --acc3-on-rgb:111,189,175;

  --gr-hero:#14130F; --gr-band:#1E1D18; --gr-deep:#100F0C; --gr-menu:#191811;
  --od:#EFE9DA; --od-rgb:239,233,218; --paper:#EFE9DA;
  --blue:#7A5E33; --blue-deep:#5E4726; --acc-rgb:122,94,51;
  --gl1-rgb:107,107,69; --gl2-rgb:168,155,107; --gl3-rgb:140,109,63;
  --field-media:linear-gradient(155deg,#1C1C12 0%,#3E3F26 34%,#5A5533 64%,#6E5730 100%);
  --field-cta:linear-gradient(135deg,#1B1A12 0%,#3A3A24 42%,#4E4A2C 72%,#5A5533 100%);
  --cta-bloom:rgba(168,155,107,.32);
  --fade-text:linear-gradient(96deg,#A89B6B 0%,#C9B98E 38%,#D9C9A5 70%,#EFE9DA 100%);
  --ice:#E4DAC0; --mint:#EDE6D2;
  --tint-a1:#EFE9DA; --tint-a2:#E4DAC0; --tint-b1:#EDE6D2; --tint-b2:#F3ECDD;
  --word-off:#C7C2B4;
  --grain-op:.36;
  --aurora-filter:blur(34px) saturate(1.12) contrast(1.24);
  --aurora-filter-menu:blur(40px) saturate(1.25) contrast(1.16);
}
[data-palette="london"]{
  /* counter-accents (v2.4): complementary + contrasting counterpoints.
     --acc2/--acc3 are tuned for the LIGHT ground, --acc2-on/--acc3-on for
     dark fields. Never used as large fills — accents, rules, numerals,
     washes and hovers only. */
  --acc2:#5C1622; --acc2-rgb:92,22,34;
  --acc3:#0E3F45; --acc3-rgb:14,63,69;
  --acc2-on:#E39AA6; --acc2-on-rgb:227,154,166;
  --acc3-on:#6FC2CC; --acc3-on-rgb:111,194,204;

  --gr-hero:#05070E; --gr-band:#0B1020; --gr-deep:#070C18; --gr-menu:#080D1C;
  --od:#FFFFFF; --od-rgb:255,255,255; --paper:#FFFFFF;
  --blue:#1B4FD8; --blue-deep:#123A9E; --acc-rgb:27,79,216;
  --gl1-rgb:27,79,216; --gl2-rgb:46,107,255; --gl3-rgb:232,80,15;
  --field-media:linear-gradient(155deg,#07102B 0%,#1B4FD8 40%,#6E3B55 68%,#C4400C 100%);
  --field-cta:linear-gradient(135deg,#0D1740 0%,#2050DE 36%,#7A3A46 70%,#C4400C 100%);
  --cta-bloom:rgba(255,142,90,.42);
  --fade-text:linear-gradient(96deg,#4E86FF 0%,#9C6BA8 44%,#FF6A2B 78%,#FF8E5A 100%);
  --ice:#DEEDFC; --mint:#DFF4EC;
  --tint-a1:#DEEDFC; --tint-a2:#E6E4FC; --tint-b1:#E9E4FC; --tint-b2:#F4E6F7;
  --word-off:#C9C9C4;
  --grain-op:.34;
  --aurora-filter:blur(32px) saturate(1.2) contrast(1.22);
  --aurora-filter-menu:blur(38px) saturate(1.32) contrast(1.14);
}
/* blend — smoke grounds, vermilion + coral, sand edges */
[data-palette="ember"]{
  /* counter-accents (v2.4): complementary + contrasting counterpoints.
     --acc2/--acc3 are tuned for the LIGHT ground, --acc2-on/--acc3-on for
     dark fields. Never used as large fills — accents, rules, numerals,
     washes and hovers only. */
  --acc2:#14402E; --acc2-rgb:20,64,46;
  --acc3:#40203C; --acc3-rgb:64,32,60;
  --acc2-on:#7BC4A4; --acc2-on-rgb:123,196,164;
  --acc3-on:#C9A0C2; --acc3-on-rgb:201,160,194;

  --gr-hero:#16110E; --gr-band:#201814; --gr-deep:#120D0A; --gr-menu:#1B1310;
  --od:#F2E7DC; --od-rgb:242,231,220; --paper:#F2E7DC;
  --blue:#A63A0E; --blue-deep:#7E2B08; --acc-rgb:166,58,14;
  --gl1-rgb:196,64,12; --gl2-rgb:255,142,90; --gl3-rgb:217,201,165;
  --field-media:linear-gradient(155deg,#1C120D 0%,#5A2A16 40%,#8A3A16 70%,#A6431A 100%);
  --field-cta:linear-gradient(135deg,#1E120C 0%,#6B2A12 42%,#94380F 72%,#A6431A 100%);
  --cta-bloom:rgba(255,142,90,.34);
  --fade-text:linear-gradient(96deg,#E8500F 0%,#FF6A2B 34%,#FF8E5A 68%,#F2E7DC 100%);
  --ice:#EBD9C4; --mint:#F1E4D6;
  --tint-a1:#F3E9DC; --tint-a2:#EBD9C4; --tint-b1:#F1E4D6; --tint-b2:#F6EDE2;
  --word-off:#CBBFB2;
  --grain-op:.35;
  --aurora-filter:blur(33px) saturate(1.18) contrast(1.22);
  --aurora-filter-menu:blur(39px) saturate(1.3) contrast(1.15);
}
/* blend — navy grounds, cobalt cooling into khaki and sand */
[data-palette="harbour"]{
  /* counter-accents (v2.4): complementary + contrasting counterpoints.
     --acc2/--acc3 are tuned for the LIGHT ground, --acc2-on/--acc3-on for
     dark fields. Never used as large fills — accents, rules, numerals,
     washes and hovers only. */
  --acc2:#5A1A22; --acc2-rgb:90,26,34;
  --acc3:#3A2140; --acc3-rgb:58,33,64;
  --acc2-on:#E09AA3; --acc2-on-rgb:224,154,163;
  --acc3-on:#BE9CD0; --acc3-on-rgb:190,156,208;

  --gr-hero:#060A14; --gr-band:#0B1220; --gr-deep:#070D18; --gr-menu:#0A1020;
  --od:#EDEAE0; --od-rgb:237,234,224; --paper:#EDEAE0;
  --blue:#1B4FD8; --blue-deep:#123A9E; --acc-rgb:27,79,216;
  --gl1-rgb:27,79,216; --gl2-rgb:46,107,255; --gl3-rgb:168,155,107;
  --field-media:linear-gradient(155deg,#07102B 0%,#173F9E 38%,#4A5A6E 70%,#6E6A4A 100%);
  --field-cta:linear-gradient(135deg,#0C1533 0%,#1B4FD8 40%,#4A5470 72%,#6E6A4A 100%);
  --cta-bloom:rgba(168,155,107,.34);
  --fade-text:linear-gradient(96deg,#4E86FF 0%,#8E9AD8 40%,#BFB48A 74%,#D9C9A5 100%);
  --ice:#E2E4DA; --mint:#EDEDE4;
  --tint-a1:#E6EAF2; --tint-a2:#E2E4DA; --tint-b1:#EDEDE4; --tint-b2:#F2F1E9;
  --word-off:#C6C6BE;
  --grain-op:.34;
  --aurora-filter:blur(33px) saturate(1.16) contrast(1.22);
  --aurora-filter-menu:blur(39px) saturate(1.28) contrast(1.15);
}
/* blend — smoke and olive with one cobalt accent held back for the edge */
[data-palette="fieldwork"]{
  /* counter-accents (v2.4): complementary + contrasting counterpoints.
     --acc2/--acc3 are tuned for the LIGHT ground, --acc2-on/--acc3-on for
     dark fields. Never used as large fills — accents, rules, numerals,
     washes and hovers only. */
  --acc2:#54202A; --acc2-rgb:84,32,42;
  --acc3:#0F423C; --acc3-rgb:15,66,60;
  --acc2-on:#DE9CA6; --acc2-on-rgb:222,156,166;
  --acc3-on:#6FBFB2; --acc3-on-rgb:111,191,178;

  --gr-hero:#12130F; --gr-band:#1B1D17; --gr-deep:#0E100C; --gr-menu:#16180F;
  --od:#EAE9DE; --od-rgb:234,233,222; --paper:#EAE9DE;
  --blue:#4F5230; --blue-deep:#3A3C22; --acc-rgb:79,82,48;
  --gl1-rgb:107,107,69; --gl2-rgb:90,100,60; --gl3-rgb:46,107,255;
  --field-media:linear-gradient(155deg,#161810 0%,#33381F 38%,#4A5230 68%,#2E4A6E 100%);
  --field-cta:linear-gradient(135deg,#141610 0%,#333A20 42%,#4C5432 70%,#25406B 100%);
  --cta-bloom:rgba(46,107,255,.30);
  --fade-text:linear-gradient(96deg,#A89B6B 0%,#C9B98E 34%,#7C93C8 70%,#4E86FF 100%);
  --ice:#E1E4D2; --mint:#EBEEE0;
  --tint-a1:#EDEDE2; --tint-a2:#E1E4D2; --tint-b1:#EBEEE0; --tint-b2:#F2F3EA;
  --word-off:#C4C4B8;
  --grain-op:.35;
  --aurora-filter:blur(34px) saturate(1.14) contrast(1.24);
  --aurora-filter-menu:blur(40px) saturate(1.26) contrast(1.16);
}
*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  background:var(--bg);color:var(--ink);
  font-family:var(--sans);font-weight:400;font-size:16px;line-height:1.6;
  -webkit-font-smoothing:antialiased;overflow-x:hidden;
}
::selection{background:var(--blue);color:#fff}

.wrap{max-width:1660px;margin:0 auto;padding-left:clamp(20px,3vw,52px);padding-right:clamp(20px,3vw,52px)}
.label{font-family:var(--mono);font-weight:500;font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
a{color:inherit;text-decoration:none}
a:focus-visible,button:focus-visible{outline:2px solid var(--blue);outline-offset:3px}
/* ground-aware focus rings (brand-lock §6): the blue ring above reads fine on
   light grounds, but drops well below 3:1 on the site's dark surfaces — swap
   to the palette's own --od (near-white/cream, ≥4.5:1 on every dark ground in
   all five palettes) wherever focus can land on a dark field. */
.hero a:focus-visible,.hero button:focus-visible,
[data-band] a:focus-visible,[data-band] button:focus-visible,
.orch a:focus-visible,.orch button:focus-visible,
.media a:focus-visible,.media button:focus-visible,
.cta-card a:focus-visible,.cta-card button:focus-visible,
.overlay a:focus-visible,.overlay button:focus-visible,
footer a:focus-visible,footer button:focus-visible{
  outline-color:var(--od);
}

/* soft hue-fade glow blobs (Apple-style ambient colour) */
.glow{position:absolute;border-radius:50%;filter:blur(70px);pointer-events:none;will-change:transform}
.glow-blue{background:rgba(var(--gl1-rgb),.16)}
.glow-violet{background:rgba(var(--gl2-rgb),.14)}
.glow-orchid{background:rgba(var(--gl3-rgb),.11)}
@keyframes drift{
  0%{transform:translate(0,0) scale(1)}
  50%{transform:translate(4%,6%) scale(1.06)}
  100%{transform:translate(-3%,-4%) scale(.97)}
}
.drift{animation:drift 22s ease-in-out infinite alternate}
.drift.d2{animation-duration:28s;animation-delay:-9s}
.drift.d3{animation-duration:34s;animation-delay:-17s}

/* gradient text — one word only, slow hue drift */
.fade-word{
  background:var(--fade-text);background-size:220% 100%;
  -webkit-background-clip:text;background-clip:text;color:transparent;
  animation:huedrift 9s ease-in-out infinite alternate;
}
@keyframes huedrift{from{background-position:0% 0}to{background-position:100% 0}}

.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:10px;
  font-weight:600;font-size:15.5px;padding:14px 28px;border-radius:999px;
  border:1px solid transparent;cursor:pointer;
  transition:background-color .25s,color .25s,border-color .25s,box-shadow .35s,transform .25s;
}
.btn:active{transform:scale(.98)}
.btn-blue{background:var(--blue);color:#fff}
.btn-blue:hover{background:var(--blue-deep);box-shadow:0 0 0 5px rgba(var(--acc-rgb),.15),0 10px 30px rgba(var(--acc-rgb),.28),0 14px 44px -8px rgba(var(--gl3-rgb),.3)}
.btn-line{border-color:var(--rule);color:var(--ink);background:transparent}
.btn-line:hover{border-color:var(--ink);background:var(--ink);color:#fff}
.btn-paper{background:var(--paper);color:var(--gr-band)}
.btn-paper:hover{background:var(--ice);box-shadow:0 0 0 5px rgba(var(--od-rgb),.16)}

.u-link{position:relative;padding-bottom:2px;font-weight:600}
.u-link::after{
  content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;background:var(--fade-text);
  transform:scaleX(0);transform-origin:left;transition:transform .4s cubic-bezier(0,1,.5,1);
}
.u-link:hover::after{transform:scaleX(1)}

/* aurora — living gradient canvas (monopo-style), tiny buffer scaled + blurred */
.aurora{
  position:absolute;inset:-18%;width:136%;height:136%;pointer-events:none;
  filter:var(--aurora-filter);opacity:1;
}
.aurora[data-aurora="light"]{filter:blur(56px) saturate(.95) contrast(1.06);opacity:.8}

/* ---- FILM GRAIN STANDARD (brand-lock v2.2 §5) --------------------------
   Two stitched monochrome turbulence tiles — one tight, one coarse — blended
   into the field itself rather than laid over it as a flat veil. Pure static
   image layers: nothing animates, so this is reduced-motion safe by
   construction. Strength is per-palette via --grain-op. */
.grain::after{
  content:"";position:absolute;inset:0;pointer-events:none;z-index:0;
  opacity:var(--grain-op);mix-blend-mode:overlay;
  background-image:var(--noise-fine),var(--noise-coarse);
  background-size:140px 140px,320px 320px;
  background-blend-mode:overlay;
}
/* copy sits above the grain (these wraps are position:relative with auto
   z-index, so without this the ::after paints over the text) */
.orch .wrap,.media .wrap,footer .wrap,.overlay-bar,.overlay-inner{z-index:1}

/* gradient-border card (padding-box / border-box trick) */
.grad-border{
  border:1px solid transparent !important;
  background:
    linear-gradient(var(--surface),var(--surface)) padding-box,
    linear-gradient(120deg,rgba(var(--acc-rgb),.55),rgba(var(--gl2-rgb),.5),rgba(var(--gl3-rgb),.5)) border-box !important;
}

/* slow gradient drift for stark colour fields */
@keyframes gradShift{from{background-position:0% 0%}to{background-position:100% 100%}}
.grad-live{background-size:180% 180%;animation:gradShift 18s ease-in-out infinite alternate}

/* masked line reveals (pxpush / Splitting-style) */
.ln{display:block;overflow:hidden;padding-bottom:.06em;margin-bottom:-.06em}
.ln__in{display:block;transform:translateY(115%);transition:transform 1.05s cubic-bezier(.22,1,.36,1)}
[data-lines].lines-on .ln__in{transform:none}
/* round 13: a heading that will be split into lines is not painted until the
   split has happened (flow.js adds .lines-split as it splits), so first paint
   never shows the whole line, loses it, then raises it again — the "flash
   then animate" of the round-12 preview. Same idea as .rv's opacity:0. */
[data-lines]:not(.lines-split){opacity:0}
@media (prefers-reduced-motion:reduce){
  .ln__in{transform:none !important;transition:none !important}
  [data-lines]:not(.lines-split){opacity:1}
}

/* reveal-once with slight blur (Apple-ish) */
.rv{opacity:0;transform:translateY(24px);filter:blur(6px);
  transition:opacity .8s cubic-bezier(0,1,.5,1),transform .8s cubic-bezier(0,1,.5,1),filter .8s cubic-bezier(0,1,.5,1)}
.rv.on{opacity:1;transform:none;filter:none}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .rv{opacity:1;transform:none;filter:none;transition:none}
  .drift,.fade-word{animation:none !important}
  .wordrv span{color:inherit !important;transition:none}
  .grad-live{animation:none !important}
  .ff.go .ft,.ff.go .fb,.pc-fl{animation:none !important}
  .pc-asm{transform:none !important;opacity:1 !important}
  .pc-hov{transition:none !important}
  .cur{display:none !important}
  html.has-cur,html.has-cur *{cursor:auto !important}
  /* v2.3 layers */
  .hue-veil{display:none !important}
  [data-sig="wash"] .aurora{opacity:.4}
  [data-stack]{position:static !important;transform:none !important;opacity:1 !important;filter:none !important}
  [data-magnetic],[data-pointer]{transform:none !important}
  .float{transform:none !important}
  .float .shot{transition:none !important}
  .overlay{transition:none !important}
  .overlay-nav a,.overlay-aside{transition:none !important;transition-delay:0s !important}
}

/* nav — transparent over the dark hero, solid after */
header{
  position:sticky;top:0;z-index:50;background:transparent;
  border-bottom:1px solid transparent;
  transition:background-color .35s,border-color .35s;
  --nav-ink:var(--od);--nav-dim:rgba(var(--od-rgb),.6);
}
header.scrolled{
  background:rgba(248,248,247,.9);backdrop-filter:blur(12px);
  border-bottom:1px solid var(--hairline);
  --nav-ink:var(--ink);--nav-dim:var(--muted);
}
/* three columns — brand | links | actions — so the link cluster is centred on
   the page rather than floating between two clusters of unequal width
   (2026-08-23: Mitch flagged the bar as unevenly spaced) */
.navbar{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;height:66px;gap:24px}
.navbar>:last-child{justify-self:end}
.brand{font-weight:800;font-size:19px;letter-spacing:-.02em;display:inline-flex;align-items:center;gap:9px;white-space:nowrap}
/* the prism mark sits beside every wordmark (2026-08-23). Mark = assets/prizmacore-mark.svg,
   viewBox 1530x2140, so height drives width. */
.brand-mark{height:21px;width:auto;display:block;flex:none}
header .brand,header .navlinks a,header .menu-btn{color:var(--nav-ink)}
.navlinks{display:flex;gap:26px;align-items:center}
.navlinks a{font-size:14px;transition:color .25s}
.navlinks a:hover{color:var(--blue)}
header.scrolled .navlinks a:hover{color:var(--blue)}
/* featured link: the marker is a corner dot so it takes no horizontal room —
   every gap in the cluster stays exactly 26px (it used to sit inline and
   widen one gap to 40px). */
.nav-feat{position:relative}   /* round 15: featured dot removed — no glowing dots anywhere */
/* actions column (round 10): Orchestrator sits alone, centred in the free
   space between the link cluster and the CTA — auto margins split the slack
   evenly so it reads as "exactly between About and the button". */
.nav-actions{display:flex;align-items:center;gap:18px;width:100%}
.nav-actions .orc{margin:0 auto;font-size:14px;font-weight:500;color:var(--nav-ink);white-space:nowrap;transition:color .25s}
.nav-actions .orc:hover{color:var(--blue)}
.nav-cta{padding:10px 22px;font-size:14px}
.menu-btn{
  display:inline-flex;align-items:center;gap:9px;cursor:pointer;background:none;border:0;
  font-family:var(--mono);font-size:11.5px;letter-spacing:.08em;text-transform:uppercase;
  padding:10px 4px;transition:color .25s;
}
.menu-btn:hover{color:var(--blue)}
.menu-btn .bars{display:inline-flex;flex-direction:column;gap:4px;width:18px}
.menu-btn .bars i{height:2px;background:currentColor;transition:transform .3s,opacity .3s}

/* MUTEK-style fullscreen gradient menu overlay */
.overlay{
  position:fixed;inset:0;z-index:100;background:var(--gr-menu);color:var(--od);
  transform:translateY(-102%);transition:transform .65s cubic-bezier(.77,0,.18,1);
  overflow:hidden;display:flex;flex-direction:column;
}
.overlay.open{transform:translateY(0)}
.overlay .aurora{opacity:1;filter:var(--aurora-filter-menu)}
/* width:100% matters: in the overlay's column flexbox, .wrap's auto margins
   would otherwise shrink the bar to fit-content and centre brand + close
   together (round 10 — Mitch flagged the ✕ hugging the logo). Full width
   restores space-between: brand hard left, ✕ Close hard right. */
.overlay-bar{position:relative;display:flex;align-items:center;justify-content:space-between;height:66px;flex:none;width:100%}
.overlay-bar .brand{color:var(--od)}
.overlay-close{
  background:none;border:0;cursor:pointer;color:var(--od);
  font-family:var(--mono);font-size:11.5px;letter-spacing:.08em;text-transform:uppercase;
  padding:10px 4px;transition:opacity .25s;
}
.overlay-close:hover{opacity:.6}
.overlay-inner{position:relative;flex:1;display:grid;grid-template-columns:minmax(0,1.5fr) minmax(0,1fr);gap:40px;align-items:center;width:100%}
.overlay-nav{display:flex;flex-direction:column;gap:2px}
.overlay-nav a{
  font-weight:600;font-size:clamp(38px,7vw,92px);line-height:1.06;letter-spacing:-.03em;color:var(--od);
  width:fit-content;opacity:0;transform:translateY(40px);
  display:flex;align-items:baseline;gap:.35em;
  transition:opacity .55s cubic-bezier(0,1,.5,1),transform .55s cubic-bezier(0,1,.5,1),color .3s;
}
.overlay.open .overlay-nav a{opacity:1;transform:none}
.overlay-nav a::after{
  content:"→";font-weight:300;font-size:.5em;opacity:0;transform:translateX(-14px);
  transition:opacity .3s,transform .35s cubic-bezier(0,1,.5,1);
  background:var(--fade-text);-webkit-background-clip:text;background-clip:text;color:transparent;
}
.overlay-nav a:hover::after{opacity:1;transform:none}
.overlay-nav a:hover{color:transparent;background:var(--fade-text);-webkit-background-clip:text;background-clip:text}
.overlay-nav a:nth-child(1){transition-delay:.16s}
.overlay-nav a:nth-child(2){transition-delay:.22s}
.overlay-nav a:nth-child(3){transition-delay:.28s}
.overlay-nav a:nth-child(4){transition-delay:.34s}
.overlay-nav a:nth-child(5){transition-delay:.40s}
.overlay-aside{display:flex;flex-direction:column;gap:26px;opacity:0;transform:translateY(24px);
  transition:opacity .55s cubic-bezier(0,1,.5,1) .45s,transform .55s cubic-bezier(0,1,.5,1) .45s}
.overlay.open .overlay-aside{opacity:1;transform:none}
.overlay-aside .label{color:rgba(var(--od-rgb),.6);font-size:13px}
.overlay-aside p{color:rgba(var(--od-rgb),.78);font-size:17px;max-width:38ch}
.overlay-aside .row{display:flex;flex-direction:column;gap:8px}
.overlay-aside .row a{color:var(--od);font-size:18.5px;width:fit-content;transition:color .25s}
.overlay-aside .row a:hover{color:var(--acc3-on)}
@media (max-width:900px){
  .overlay{overflow-y:auto;-webkit-overflow-scrolling:touch}
  .overlay-bar{position:sticky;top:0;z-index:3;background:rgba(0,0,0,.28);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px)}
  .overlay-inner{grid-template-columns:1fr;flex:none;align-items:start;align-content:start;gap:44px;padding-bottom:48px}
}

/* main above fixed footer */
main{position:relative;z-index:2;background:var(--bg);
  box-shadow:0 30px 60px rgba(25,25,25,.18)}

/* hero — dark, serious, high contrast */
.hero{
  margin-top:-66px;padding:clamp(150px,16vw,220px) 0 clamp(56px,6vw,96px);
  position:relative;overflow:hidden;background:var(--gr-hero);color:var(--od);
}
.hero::before{
  content:"";position:absolute;inset:0;pointer-events:none;z-index:1;opacity:.5;
  background:repeating-linear-gradient(180deg,rgba(var(--od-rgb),.028) 0 1px,transparent 1px 5px);
}
#heroGlow{position:absolute;inset:0;pointer-events:none}
#heroGlow .glow{width:min(760px,80vw);aspect-ratio:1}
#heroGlow .g1{top:-32%;right:-8%;background:rgba(var(--gl1-rgb),.32)}
#heroGlow .g2{top:8%;right:22%;width:min(520px,56vw);background:rgba(var(--gl2-rgb),.26)}
#heroGlow .g3{bottom:-46%;left:-10%;width:min(600px,64vw);background:rgba(var(--gl3-rgb),.22)}
.hero .wrap{position:relative;z-index:2}
.hero .label{display:block;margin-bottom:34px;color:rgba(var(--od-rgb),.55)}
.hero-display{
  font-size:clamp(38px,6vw,108px);line-height:1.12;letter-spacing:-.028em;
  font-weight:600;max-width:18ch;text-wrap:balance;overflow-wrap:break-word;color:var(--od);
}
.hero-display .quiet{font-weight:300;color:rgba(var(--od-rgb),.8)}
.hero-foot{
  display:grid;grid-template-columns:minmax(0,1fr) auto;gap:40px;align-items:end;
  margin-top:clamp(40px,5vw,68px);padding-top:28px;border-top:1px solid rgba(var(--od-rgb),.2);
}
.hero-foot p{color:rgba(var(--od-rgb),.62);max-width:52ch;font-size:17px}
.hero-ctas{display:flex;gap:14px;flex-wrap:wrap}
.btn-ghostw{border-color:rgba(var(--od-rgb),.45);color:var(--od);background:transparent}
.btn-ghostw:hover{background:var(--od);border-color:var(--od);color:var(--gr-band)}

/* ---- BOARD — split-flap strip (round 8, 2026-08-23) ---------------------
   Replaces the marquee (two rounds of ticker were both vetoed as generic).
   One row of mono flap cells under the hero flips through the page's
   statements in a left-to-right cascade, the way a Solari departures board
   does: typographic, vintage, satisfying, and not a thing you see on every
   site. flow.js (initBoard) builds the cells from data-msgs, auto-advances
   while in view, advances on hover, and ratchets changed cells through one
   glyph before they settle. Reduced motion: the first statement, static. */
.board{
  position:relative;overflow:hidden;color:var(--od);
  background:var(--gr-hero);
  border-top:1px solid rgba(var(--od-rgb),.1);
  border-bottom:1px solid rgba(var(--od-rgb),.1);
  padding:15px 0 14px;
}
.board-wrap{position:relative;z-index:1;display:flex;align-items:center;gap:clamp(16px,2.4vw,40px)}
.board-eyebrow,.board-meta{
  font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  color:rgba(var(--od-rgb),.55);white-space:nowrap;flex:none;
}
.board-eyebrow{display:inline-flex;align-items:center;gap:10px}
/* round 15: the "on air" lamp is gone at Mitchell's request — no glowing dots anywhere. */
.board-meta{margin-left:auto}
.board-flap{display:flex;gap:2px;flex:none;--ffs:clamp(13px,1.15vw,18px)}
.ff{
  position:relative;width:calc(var(--ffs) * .92);height:calc(var(--ffs) * 1.5);
  font-family:var(--mono);font-size:var(--ffs);line-height:1;text-transform:uppercase;
  color:var(--od);border-radius:2px;perspective:260px;
  background:color-mix(in srgb,var(--od) 6%,var(--gr-hero));
}
.ff::before{content:"";position:absolute;inset:0;border-radius:2px;box-shadow:inset 0 0 0 1px rgba(var(--od-rgb),.09);z-index:3;pointer-events:none}
.ff::after{content:"";position:absolute;left:0;right:0;top:50%;height:1px;background:rgba(0,0,0,.6);z-index:2;pointer-events:none}
.ff i{
  position:absolute;inset:0;display:grid;place-items:center;font-style:normal;border-radius:2px;
  background:inherit;backface-visibility:hidden;-webkit-backface-visibility:hidden;
}
.ff .t,.ff .ft{clip-path:inset(0 0 50% 0);background-image:linear-gradient(0deg,rgba(0,0,0,.14),transparent 45%)}
.ff .b,.ff .fb{clip-path:inset(50% 0 0 0);background-image:linear-gradient(180deg,rgba(0,0,0,.2),transparent 40%)}
.ff .ft,.ff .fb{transform-origin:50% 50%}
.ff .fb{transform:rotateX(90deg)}
.ff.blank::before,.ff.blank::after{content:none}
.ff.blank i{background-image:none}

/* pointer-aware verb: "Tap" on touch, "Click" on fine pointers (round 12) */
.pt-f{display:none}
@media (hover:hover) and (pointer:fine){.pt-c{display:none}.pt-f{display:inline}}

/* odometer stat reels (round 12) — digits roll in the flap-board idiom */
.stat b{font-variant-numeric:tabular-nums}
.od{display:inline-flex;height:1em;overflow:hidden;vertical-align:baseline}
.od-reel{display:flex;flex-direction:column;line-height:1;
  transition:transform 1.25s cubic-bezier(.16,.84,.28,1)}
.od-reel span{display:block;height:1em}
.od-reel.run{transform:translateY(calc(var(--n) * -1em))}
@media (prefers-reduced-motion:reduce){.od-reel{transition:none}}
.ff.go .ft{animation:ffTop .2s cubic-bezier(.55,0,.85,.35) forwards}
.ff.go .fb{animation:ffBot .2s .2s cubic-bezier(.15,.6,.4,1) forwards}
@keyframes ffTop{to{transform:rotateX(-90deg)}}
@keyframes ffBot{to{transform:rotateX(0deg)}}
@media (max-width:900px){.board-meta{display:none}}
@media (max-width:560px){.board-eyebrow span{display:none}}

/* ---- SECTION NUMBERS (round 8) -----------------------------------------
   The Nº00X editing labels stay in the source so sections can be named by
   number while reviewing, but never ship visibly: hidden by default, shown
   when the page is opened with ?edit (flow.js sets html.edit). */
.sn{display:none}
html.edit .sn{display:inline}

/* ---- band modifier: pure-black cut, heavier grain (v2.3) ---------------
   [data-band="black"] drops a section to true #000 and pushes the grain, for
   hard rhythm breaks between palette-coloured fields. */
[data-band="black"]{background-color:#000 !important;--grain-op:.4;position:relative;overflow:hidden}
/* a black band should breathe, not sit flat — one very quiet aurora behind it
   (v2.4 round 6). Restrained on purpose: this is the one place subtle wins. */
[data-band="black"] .aurora{opacity:.3;filter:blur(58px) saturate(.85) contrast(1.02)}
[data-band="black"] .wrap{position:relative;z-index:1}

/* sections */
.sect{padding:clamp(64px,8vw,124px) 0}
.sect-grid{display:grid;grid-template-columns:minmax(0,4fr) minmax(0,8fr);gap:clamp(28px,4vw,72px);align-items:start}
.sect-sticky{position:sticky;top:96px}
.sect-sticky h2{font-size:clamp(34px,4.2vw,72px);line-height:.98;letter-spacing:-.03em;font-weight:600;margin-top:14px}
.sect-sticky .label{display:block}
.sect-sticky p{color:var(--muted);font-size:15.5px;max-width:34ch;margin-top:18px}

/* service cards — tint grounds, sticky-stacking on scroll */
.svc-cards{display:flex;flex-direction:column;gap:20px}
.svc-card{
  border-radius:20px;padding:32px 32px 30px;
  will-change:transform,opacity;
  display:grid;grid-template-columns:minmax(0,1fr) auto;gap:20px;align-items:start;
  position:sticky;top:calc(112px + var(--stk,0)*20px);
  transform-origin:center top;will-change:transform;
  transition:box-shadow .3s cubic-bezier(0,1,.5,1);
  box-shadow:0 -10px 30px rgba(25,25,25,.06);
}
.svc-card:hover{box-shadow:
  0 22px 44px rgba(25,25,25,.08),
  0 0 0 1px rgba(var(--gl2-rgb),.22),
  0 10px 44px -8px rgba(var(--acc-rgb),.32),
  0 16px 52px -12px rgba(var(--gl3-rgb),.28)}
.svc-ice{background:linear-gradient(135deg,var(--tint-a1) 0%,var(--tint-a2) 100%)}
.svc-mint{background:linear-gradient(135deg,var(--tint-b1) 0%,var(--tint-b2) 100%)}
.svc-paper{background:var(--surface);border:1px solid var(--hairline)}
.svc-card h3{font-size:clamp(21px,2.2vw,30px);font-weight:600;letter-spacing:-.02em;line-height:1.1}
.svc-card p{grid-column:1;color:#4B4B48;font-size:15.5px;max-width:58ch;margin-top:8px}
.svc-card .price{font-family:var(--mono);font-weight:500;font-size:12px;letter-spacing:.06em;text-align:right;white-space:nowrap;padding-top:8px}
.svc-card .go{grid-column:1;margin-top:16px;font-size:14.5px;justify-self:start}

/* word-reveal statement */
.statement{
  padding:clamp(48px,6vw,96px) 0 clamp(56px,7vw,110px);text-align:center;position:relative;
  background:radial-gradient(ellipse 60% 90% at 50% 40%,rgba(var(--gl2-rgb),.07) 0%,rgba(var(--gl2-rgb),0) 70%);
}
.statement .label{display:block;margin-bottom:26px}
.wordrv{
  font-size:clamp(30px,5vw,72px);line-height:1.12;letter-spacing:-.028em;font-weight:600;
  max-width:26ch;margin:0 auto;text-wrap:balance;
  color:var(--word-off);   /* round 13: starts un-inked, so first paint never flashes full ink before the split */
}
.wordrv span{color:var(--word-off);transition:color .5s cubic-bezier(0,1,.5,1)}
.wordrv span.on{color:var(--ink)}
@media (prefers-reduced-motion:reduce){.wordrv{color:var(--ink)}}   /* spans inherit (RM block above) — full ink, no reveal */

/* ORCHESTRATOR — dark showcase band */
.orch{background:var(--gr-band);color:var(--od);position:relative;overflow:hidden;padding:clamp(80px,10vw,150px) 0}
.orch .glow{opacity:.9}
.orch .og1{width:min(820px,90vw);aspect-ratio:1;top:-42%;right:-12%}
.orch .og2{width:min(560px,60vw);aspect-ratio:1;bottom:-38%;left:-8%}
.orch .wrap{position:relative}
.orch .label{color:rgba(var(--od-rgb),.55);display:block;margin-bottom:30px}
.orch h2{
  font-weight:600;font-size:clamp(32px,4.8vw,72px);line-height:1.06;letter-spacing:-.028em;
  max-width:20ch;text-wrap:balance;
}
.orch h2 .fade-word{font-weight:600}
.orch .lede{color:rgba(var(--od-rgb),.66);max-width:56ch;margin-top:26px;font-size:17px}
.stats{
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:0;
  border-top:1px solid rgba(var(--od-rgb),.18);border-bottom:1px solid rgba(var(--od-rgb),.18);
  margin:clamp(40px,5vw,64px) 0;
}
.stat{padding:30px 28px;border-left:1px solid rgba(var(--od-rgb),.18)}
.stat:first-child{border-left:0;padding-left:0}
.stat b{
  display:block;font-weight:600;font-size:clamp(34px,4.6vw,64px);line-height:1;letter-spacing:-.03em;
  font-variant-numeric:tabular-nums;
}
.stat span{display:block;margin-top:10px;font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:rgba(var(--od-rgb),.5)}
.orch-foot{display:flex;align-items:center;justify-content:space-between;gap:26px;flex-wrap:wrap}
.orch-chips{display:flex;flex-wrap:wrap;gap:9px}
.orch-chip{
  font-family:var(--mono);font-size:12px;letter-spacing:.05em;text-transform:uppercase;
  border:1px solid rgba(var(--od-rgb),.28);border-radius:999px;padding:9px 18px;color:rgba(var(--od-rgb),.85);
  transition:border-color .25s,color .25s,background-color .25s;
}
.orch-chip:hover{border-color:var(--od);background:rgba(var(--od-rgb),.08);color:var(--od)}

/* why cards */
.cards{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.card{
  background:var(--surface);border:1px solid var(--hairline);border-radius:16px;padding:30px 28px;
  transition:transform .3s cubic-bezier(0,1,.5,1),box-shadow .3s cubic-bezier(0,1,.5,1);
}
.card:hover{transform:translateY(-6px);box-shadow:0 14px 28px rgba(25,25,25,.09)}
.card h3{font-size:20px;font-weight:600;letter-spacing:-.015em;line-height:1.2;margin-bottom:10px}
.card p{color:var(--muted);font-size:15px}

/* media on ice */
.media{
  position:relative;color:var(--od);
  background:var(--field-media);
  padding:clamp(64px,8vw,118px) 0;
}
.media-head{display:flex;justify-content:space-between;align-items:baseline;gap:16px;flex-wrap:wrap;margin-bottom:28px}
.media-head h2{font-weight:600;font-size:clamp(32px,4.4vw,60px);line-height:.98;letter-spacing:-.028em}
.media .label{color:rgba(var(--od-rgb),.99)}
.media .wrap{position:relative}
.shot{
  background:var(--surface);border-radius:20px;overflow:hidden;
  box-shadow:0 24px 48px rgba(25,25,25,.1);
  aspect-ratio:16/8.4;display:grid;place-items:center;position:relative;
  isolation:isolate;   /* round 14: own stacking context so transformed media clips cleanly to the radius */
}
.shot-inner{position:absolute;inset:0;transition:transform .6s cubic-bezier(0,1,.5,1);
  background:
    repeating-linear-gradient(0deg,transparent,transparent 55px,var(--hairline) 56px),
    repeating-linear-gradient(90deg,transparent,transparent 55px,var(--hairline) 56px)}
.shot:hover .shot-inner{transform:scale(1.045)}
/* round 12: when a real screenshot lands inside .shot-inner it pans gently on
   scroll (--fxp written by the flow loop). Dormant while frames are empty. */
.shot-inner>img{position:absolute;left:0;top:0;width:100%;height:118%;object-fit:cover;
  transform:translateY(calc(var(--fxp,0) * -15%))}
.shot span{position:relative;font-family:var(--mono);font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);background:var(--surface);border:1px solid var(--hairline);border-radius:999px;padding:11px 20px}

/* ---- FLOATING WINDOW (v2.3) -------------------------------------------
   A framed panel that reads as a pane of glass held above the field: deeper
   radius, layered shadow, a hairline lip, and a parallax wrapper so it drifts
   against the band behind it. The wrapper owns the parallax and the inner
   .shot owns the scroll-in scale — one motion owner each, never both on the
   same element. */
.float{will-change:transform}
.float .shot{
  border-radius:26px;
  box-shadow:
    0 2px 0 rgba(var(--od-rgb),.16) inset,
    0 30px 60px -12px rgba(0,0,0,.55),
    0 70px 120px -40px rgba(0,0,0,.65);
  transition:box-shadow .45s cubic-bezier(0,1,.5,1),transform .45s cubic-bezier(0,1,.5,1);
}
.float:hover .shot{
  box-shadow:
    0 2px 0 rgba(var(--od-rgb),.22) inset,
    0 40px 80px -14px rgba(0,0,0,.6),
    0 90px 150px -46px rgba(0,0,0,.7);
}

/* ---- FRAME (round 13) — media placeholders with real chrome -------------
   Extends .shot. Ratio classes size the frame; two chrome variants make a
   screenshot look like the thing it is — a browser window (.shot--browser:
   title bar, three lamps, URL pill) or a phone (.shot--phone: bezel and
   island). The <span> label names the asset that belongs there while the
   frame is empty. Drop an <img> or a muted looping <video> into .shot-inner
   and delete the label: images pan on scroll via --fxp (round 12 contract),
   video just plays. Motion contract unchanged — .float owns the drift, .shot
   owns the scroll-in scale. Tokens only. */
.shot.r-21x9{aspect-ratio:21/9}
.shot.r-16x10{aspect-ratio:16/10}
.shot.r-16x9{aspect-ratio:16/9}
.shot.r-4x5{aspect-ratio:4/5}
.shot.r-3x4{aspect-ratio:3/4}
.shot.r-1x1{aspect-ratio:1}
.shot.r-phone{aspect-ratio:9/19.5}
.shot-inner>video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.shot-inner>img.still{height:100%;transform:none}          /* opt out of the scroll pan */
/* round 14 (Mitchell's review): media anchors top-left so whatever object-fit
   has to crop falls off the bottom/right edge, the way a real viewport cuts a
   page — never the header or the left rail. And a filled frame paints no
   ground of its own: the .shot surface + .shot-inner hairline grid were
   bleeding through the anti-aliased radius as a pale fringe on dark bands. */
.shot-inner>img,.shot-inner>video{object-position:0 0}
.shot:has(>.shot-inner>img),.shot:has(>.shot-inner>video){background:transparent}
.shot-inner:has(>img),.shot-inner:has(>video){background:none}
/* Phone screens: a portrait capture already matches the screen's ratio, so it
   fits edge to edge with no scroll-pan and sits centred — the 118% pan box
   was pushing the still sideways and clipping its right edge. */
.shot--phone .shot-inner>img{height:100%;transform:none}
.shot--phone .shot-inner>img,.shot--phone .shot-inner>video{object-position:50% 0}
/* browser chrome */
.shot--browser .shot-bar{
  position:absolute;left:0;right:0;top:0;height:34px;z-index:1;
  display:flex;align-items:center;gap:6px;padding:0 14px;
  background:var(--bg);border-bottom:1px solid var(--hairline);
}
.shot--browser .shot-bar i{width:9px;height:9px;border-radius:50%;background:var(--rule);flex:none}
.shot--browser .shot-bar b{
  margin-left:10px;flex:1;max-width:46%;height:18px;border-radius:5px;
  background:var(--surface);border:1px solid var(--hairline);
  font-family:var(--mono);font-weight:500;font-size:9.5px;letter-spacing:.06em;line-height:16px;
  color:var(--muted);padding:0 9px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;
}
.shot--browser .shot-inner{top:34px}
/* phone chrome */
.shot--phone,.float .shot--phone{
  border-radius:38px;background:var(--gr-deep);
  box-shadow:0 0 0 1px rgba(var(--od-rgb),.14),0 30px 60px -12px rgba(0,0,0,.55),0 70px 120px -40px rgba(0,0,0,.65);
}
.shot--phone .shot-inner{inset:10px;border-radius:28px;background-color:color-mix(in srgb,var(--od) 7%,var(--gr-deep))}   /* screen a shade up from the bezel so the island reads */
.shot--phone::before{                                        /* the island */
  content:"";position:absolute;left:50%;top:22px;transform:translateX(-50%);
  width:26%;height:14px;border-radius:999px;background:var(--gr-deep);z-index:2;
}
.shot--phone span{font-size:10.5px;padding:9px 14px;text-align:center;max-width:78%}
@media (max-width:560px){
  .shot--phone,.float .shot--phone{border-radius:30px}
  .shot--phone .shot-inner{inset:8px;border-radius:22px}
  .shot--phone::before{top:16px;height:11px}
  .shot--phone span{display:none}          /* a phone on a phone is too small for a label */
}

/* ---- REEL (round 13) — one wide floating frame on the light ground right
   after the split-flap: the showreel moment as the hero exits ---- */
.reel{position:relative;z-index:1;background:var(--bg);padding:clamp(28px,4vw,56px) 0 clamp(8px,1.5vw,20px)}
.reel .float{max-width:1500px;margin:0 auto}
@media (max-width:560px){.reel{padding:20px 0 0}.reel .shot.r-21x9{aspect-ratio:16/10}}

/* ---- SHOT LAYOUTS (round 13) -------------------------------------------
   .shots-3       one browser + two phones, staggered (the media band)
   .shots-gallery two browsers + two phones on a four-column grid (case work)
   .shots-phones  a trio of phones, the middle one raised (app work)
   Doubled selectors on purpose: page-local .shots rules come later in the
   cascade and would otherwise win. */
.shots.shots-3{display:grid;grid-template-columns:minmax(0,2.4fr) minmax(0,.9fr) minmax(0,.9fr);gap:clamp(16px,2vw,28px);align-items:start}
.shots.shots-3 .float:nth-child(3){margin-top:22%}
.shots.shots-gallery{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:clamp(16px,2vw,28px);align-items:start}
.shots.shots-gallery .float:nth-child(1){grid-column:1/4}
.shots.shots-gallery .float:nth-child(2){grid-column:4;margin-top:12%}
.shots.shots-gallery .float:nth-child(3){grid-column:1;margin-top:-8%}
.shots.shots-gallery .float:nth-child(4){grid-column:2/5}
.shots.shots-phones{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(20px,3vw,44px);max-width:920px;margin:0 auto;align-items:start}
.shots.shots-phones .float:nth-child(2){margin-top:-7%}
@media (max-width:900px){
  .shots.shots-3{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .shots.shots-3 .float:first-child{grid-column:1/-1}
  .shots.shots-3 .float:nth-child(3){margin-top:14%}
  /* gallery on narrow screens: browser full width, the two phones share a
     row, browser full width — explicit rows, auto-placement never back-fills */
  .shots.shots-gallery{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .shots.shots-gallery .float:nth-child(1){grid-column:1/-1;grid-row:1}
  .shots.shots-gallery .float:nth-child(2){grid-column:1;grid-row:2;margin-top:0}
  .shots.shots-gallery .float:nth-child(3){grid-column:2;grid-row:2;margin-top:14%}
  .shots.shots-gallery .float:nth-child(4){grid-column:1/-1;grid-row:3}
  .shots.shots-phones{gap:14px}
}

/* ---- STICKY-COLUMN MEDIA + CTA FACE (round 13) --------------------------
   A small frame at the foot of a pinned .sect-sticky column gives the column
   something to hold while the rows scroll past. No data-fx on these: a
   pinned element's rect never moves, so a scroll-in would freeze half-way.
   flow.js (initStickyMediaFit) measures each pinned column and hides its
   frame (.is-unfit) when column + offset would not fit the viewport — the
   pinned column must always fit, or its lower half is never seen.
   .cta-face is the founder portrait in the CTA card's aside — who you will
   actually be talking to. */
.sticky-media{margin-top:clamp(22px,2.4vw,34px);max-width:300px}
.sticky-media.shot,.sticky-media .shot{box-shadow:0 18px 40px -12px rgba(25,25,25,.24)}
[data-sig="ink"] .sticky-media.shot,[data-sig="ink"] .sticky-media .shot{box-shadow:0 24px 50px -12px rgba(0,0,0,.55)}
.sticky-media.is-unfit{display:none}
.cta-face{width:84px;height:84px;border-radius:50%;overflow:hidden;flex:none;margin-bottom:6px;
  box-shadow:0 0 0 2px rgba(var(--od-rgb),.22),0 12px 28px -8px rgba(0,0,0,.5)}
.cta-face img{width:100%;height:100%;object-fit:cover;object-position:50% 18%;display:block}

/* ---- ICONS (round 15) --------------------------------------------------
   One external sprite, assets/icons.svg — Phosphor Icons, Regular weight
   (MIT). Monochrome, currentColor, no fills of their own, no motion, no
   glow: they inherit the ink of whatever they sit in. Markup:
     <svg class="ic" aria-hidden="true"><use href="/assets/icons.svg#i-check"/></svg>
   .ic       inline, 1.25em, for list items (cta-list, trust-row, price-list)
   .ic-card  block, 28px, the first child of a card (svc-card, deliverables)
   .ic-row   block, 26px, the first child of a #fixes row summary
   Mitchell's brief: "clean icons that suit the theme of the site and make
   lists of things more interesting" — and no glowing dots anywhere. */
.ic{display:inline-block;width:1.25em;height:1.25em;fill:currentColor;flex:none;vertical-align:-.25em}
.ic-card{display:block;width:28px;height:28px;opacity:.86}
.ic-row{display:block;width:26px;height:26px;opacity:.86;margin-bottom:14px}
.svc-card .ic-card{grid-column:1/-1;margin-bottom:-6px}
.cta-list li{display:grid;grid-template-columns:20px minmax(0,1fr);column-gap:12px;align-items:start}
.cta-list .ic{grid-row:span 2;width:20px;height:20px;margin-top:1px;opacity:.92}
.trust-row div{display:grid;grid-template-columns:18px minmax(0,1fr);column-gap:8px;align-items:start}
.trust-row .ic{grid-row:span 2;width:18px;height:18px;margin-top:2px;opacity:.86}
@media (max-width:560px){.ic-card{width:24px;height:24px}.ic-row{width:22px;height:22px;margin-bottom:10px}}

/* ---- SECTION STACKING (v2.3) ------------------------------------------
   [data-stack] recedes a section INTO THE BACKGROUND as the next one rides
   over it: scale down and dim. flow.js writes --stk-p (0-1 smoothstepped
   cover progress) and the whole move is pure CSS off that one variable. The
   element after a stacked section is lifted and made opaque so it genuinely
   covers. Deliberately NOT position:sticky — pinning a band taller than the
   viewport would strand its own lower half off-screen.
   Round 13: the per-frame blur is gone. A filter that changes every frame
   re-rasterises the whole viewport-sized band on every frame, exactly at the
   section handoff — that was the jitter between sections. Transform and
   opacity are compositor-only; keep it that way. */
[data-stack]{
  position:relative;z-index:0;
  transform:scale(calc(1 - var(--stk-p,0) * .06));
  opacity:calc(1 - var(--stk-p,0) * .72);
  transform-origin:center 30%;
  will-change:transform,opacity;
}
[data-stack] + *{position:relative;z-index:1;background:var(--bg)}
/* the shorthand above wipes a following band's own ground (image AND colour),
   so each band that can follow a stacked section gets its ground back in
   full — round 13: the old background-color:initial only restored the
   colour, which left a .media band transparent (app-dev, resources) */
[data-stack] + .hero,[data-stack] + .board{background:var(--gr-hero)}
[data-stack] + .orch{background:var(--gr-band)}
[data-stack] + .media{background:var(--field-media);background-size:180% 180%}
[data-stack] + footer{background:var(--gr-deep)}

/* ---- HUE VEIL (v2.3) ---------------------------------------------------
   The "aurora fade" between sections: one fixed layer carrying the palette's
   own colour field plus the grain tiles, bloomed by scroll VELOCITY and
   drifted by scroll POSITION. Injected by flow.js, so no page markup. It is
   soft-light and capped low so it never eats text contrast.
   Round 13: the layer is now static — flow.js drives it with transform and
   opacity only (it used to re-paint background-position every frame under a
   30px blur, with a CSS opacity transition fighting the per-frame writes),
   and it is visibility:hidden whenever it would be invisible, so at rest it
   costs nothing. */
.hue-veil{
  position:fixed;inset:-10%;z-index:3;pointer-events:none;opacity:0;
  background-image:var(--noise-fine),var(--field-media);
  background-size:140px 140px,220% 220%;
  background-blend-mode:overlay,normal;
  mix-blend-mode:soft-light;
  will-change:transform,opacity;
}

/* ---- CURSOR TITLE EFFECT — SCRAMBLE (round 13) ---------------------------
   One behaviour on every ground: the title's text cycles through a glyph set
   and settles left-to-right over 620ms, tinted with the counter-accent —
   --acc2 on light grounds, --acc2-on on dark (flow.js stamps data-ground).
   VISUAL ONLY: every text node is restored byte-exact on settle and on
   mouseleave. Titles only; anything inside a link, button or summary is
   skipped. Fine pointers only, never under reduced motion. The dark-ground
   pixel-invert overlay (rounds 6–12) is retired; see the brand lock. */
[data-cursor]{position:relative}
/* a scrambled line may not re-wrap: glyphs are width-matched in flow.js and
   this is the belt — the .ln box clips any spill for the 620ms it lasts */
.is-scrambling .ln__in{white-space:nowrap}

/* ---- CURSOR SYSTEM v2 — 1-bit vintage (round 9) ------------------------
   Fine pointers only, never under reduced motion. The pointer is a set of
   classic 1-bit bitmaps (original Mac / Windows 98 lineage) drawn by flow.js
   as crisp SVG at 2 css px per bit: arrow, pointing hand, I-beam,
   crosshair, grabber. Mac colouring on light grounds (ink glyph, paper halo)
   and Windows colouring on dark grounds (paper glyph, ink halo) — the glyph
   simply inverts when the ground under the pointer is dark. The dynamic
   layer stays in that idiom: Windows-style mouse TRAILS (three ghosts that
   only appear on fast moves and collapse when you stop), a retro TOOLTIP
   (paper box, 1px ink border, hard 2px shadow) for labels, and a 2px press
   nudge. Which glyph you get depends on what is under the pointer:
     hand      anything clickable (links, buttons, summaries, the board)
     ibeam     body copy (p, li, blockquote, table cells, captions)
     cross     titles that carry the pixel-scramble / scramble
     grab      the footer lockup (it spreads on hover)
     arrow     everything else
     native    form fields hand back to the OS cursor
   State classes on .cur: is-dark, is-down, is-tip, is-native, is-off. */
html.has-cur,html.has-cur *{cursor:none !important}
html.has-cur input,html.has-cur textarea,html.has-cur select{cursor:auto !important}
.cur{position:fixed;left:0;top:0;z-index:9000;pointer-events:none;opacity:1;transition:opacity .2s}
.cur.is-off,.cur.is-native{opacity:0}
.cur-main,.cur-trail{position:absolute;left:0;top:0;line-height:0}
.cur-main{transition:transform .08s steps(2)}          /* a press is a nudge, not a glide */
.cur.is-down .cur-main{transform:translate(1px,2px)}
.cur-trail{opacity:0;will-change:transform,opacity}
.cur-g{display:block}
.cur-g svg{display:block;image-rendering:pixelated;image-rendering:crisp-edges}
.cur.is-dark .cur-g svg{filter:invert(1)}
/* retro tooltip — appears instantly, disappears instantly, sits below-right
   of the hotspot the way OS tooltips do */
.cur-tip{
  position:absolute;left:20px;top:26px;display:none;
  padding:4px 7px 3px;background:var(--paper);color:#111;
  border:1px solid #111;box-shadow:2px 2px 0 #111;
  font-family:var(--mono);font-size:10px;line-height:1.3;letter-spacing:.12em;text-transform:uppercase;white-space:nowrap;
}
.cur.is-tip .cur-tip{display:block}
[data-cursor="scramble"].is-scrambling{color:var(--acc2)}
[data-cursor="scramble"][data-ground="dark"].is-scrambling{color:var(--acc2-on)}

/* ---- POINTER LAYER (v2.3) ---------------------------------------------
   flow.js writes --px/--py on .hero and --mx/--my on each [data-magnetic];
   the transforms themselves are declared here and composed from those props,
   so a JS pointer effect never seizes an element's transform and never
   collides with the reveal system. --pf sets each element's parallax factor
   (negative = counter-drift). Both are fine-pointer only and inert under
   reduced motion. */
[data-pointer]{
  transform:translate3d(calc(var(--px,0px) * var(--pf,1)),calc(var(--py,0px) * var(--pf,1)),0);
  will-change:transform;
}
[data-magnetic]{transform:translate3d(var(--mx,0px),var(--my,0px),0)}
@media (hover:hover) and (pointer:fine){[data-magnetic]{will-change:transform}}
.btn[data-magnetic]:active{transform:translate3d(var(--mx,0px),var(--my,0px),0) scale(.98)}

/* CTA — blue card with soft violet bloom */
.cta-final{padding:clamp(72px,9vw,128px) 0 clamp(96px,12vw,170px)}
.cta-card{
  background:var(--field-cta);
  color:var(--od);border-radius:28px;position:relative;overflow:hidden;
  padding:clamp(48px,7vw,92px) clamp(28px,5vw,84px);
  display:grid;grid-template-columns:1.5fr 1fr;gap:44px;align-items:center;
}
.cta-card .glow{width:min(640px,74vw);aspect-ratio:1;top:-52%;right:-14%;background:var(--cta-bloom)}
.cta-card>*{position:relative;z-index:1}
.cta-card>.glow{position:absolute}
.cta-card h2{font-weight:600;font-size:clamp(38px,5.8vw,84px);line-height:1;letter-spacing:-.025em;text-wrap:balance}
.cta-card p{color:rgba(var(--od-rgb),.99);margin-top:22px;max-width:40ch}
.cta-card .side{display:flex;flex-direction:column;gap:14px;align-items:flex-start}
.cta-card .label{color:rgba(var(--od-rgb),.99)}
/* the "contact box" side column + list — canonical here since 2026-08-23 so
   the card renders identically on every page (about and the blog shell used
   to carry their own, partly-missing, copies of these rules) */
.cta-list{list-style:none;display:grid;gap:14px;margin-top:30px;padding-top:26px;border-top:1px solid rgba(var(--od-rgb),.26)}
.cta-list b{display:block;font-weight:600;font-size:16px}
.cta-list span{color:rgba(var(--od-rgb),.78);font-size:15px}
.cta-side h3{font-size:clamp(24px,2.6vw,32px);font-weight:600;letter-spacing:-.02em;line-height:1.1}
.cta-side>p{color:rgba(var(--od-rgb),.8);font-size:15.5px;max-width:34ch}
.cta-warm{font-weight:600;color:var(--od)!important;margin-top:-4px}
.trust-row{display:flex;gap:26px;flex-wrap:wrap;margin-top:6px;padding-top:20px;border-top:1px solid rgba(var(--od-rgb),.26);width:100%}
.trust-row b{display:block;font-weight:600;font-size:15.5px}
.trust-row span{font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:rgba(var(--od-rgb),.72)}

/* FIXED FOOTER REVEAL — Monument's move, ink with soft glow.
   Round 9: a full-viewport reveal (100vh) so the lockup has real air — the
   mark and its fly-in animation sit centred in the free space between the
   link grid and the legal line, with generous minimum margins. Viewports
   too short to hold the content (≤1020px tall, and everything ≤900px wide)
   drop to a static footer; flow.js also flips html.foot-static if the
   content ever overflows. Mobile stays tight. */
.footer-spacer{height:100vh}
footer{
  position:fixed;left:0;right:0;bottom:0;z-index:1;height:100vh;
  background:var(--gr-deep);color:var(--od);display:flex;flex-direction:column;
  padding:clamp(56px,8vh,112px) 0 clamp(28px,4vh,48px);overflow:hidden;
}
footer>.wrap:last-of-type{
  flex:1;display:flex;flex-direction:column;
  padding-top:clamp(72px,10vh,160px);   /* minimum air above the lockup */
}
/* static-footer fallbacks use position:relative, NOT static: the aurora
   canvas and glow blobs inside are position:absolute, and a static footer
   stops being their containing block — they escape its overflow:hidden and
   push the document wider than the viewport (70px of horizontal scroll on
   phones, round 11). */
@media (max-height:1020px){
  .footer-spacer{display:none}
  footer{position:relative;height:auto}
}
html.foot-static .footer-spacer{display:none}
html.foot-static footer{position:relative;height:auto}
footer .fg1{width:min(900px,96vw);aspect-ratio:1;bottom:-52%;left:6%;background:rgba(var(--gl1-rgb),.24)}
footer .fg2{width:min(600px,66vw);aspect-ratio:1;top:-30%;right:-10%;background:rgba(var(--gl3-rgb),.16)}
footer .wrap{position:relative}
.foot-grid{display:grid;grid-template-columns:1.7fr 1fr 1fr 1fr;gap:40px}
.foot-brand h2{font-weight:600;font-size:clamp(26px,3vw,44px);line-height:1.08;letter-spacing:-.02em;max-width:15ch}
.foot-brand .foot-cta{margin-top:26px;display:flex;gap:12px;flex-wrap:wrap}
.foot-col .label{color:rgba(var(--od-rgb),.55);display:block;margin-bottom:16px}
.foot-col ul{list-style:none;display:flex;flex-direction:column;gap:10px}
.foot-col a{font-size:15.5px;color:rgba(var(--od-rgb),.85);transition:color .25s}
.foot-col a:hover{color:var(--acc3-on)}
.foot-word{
  font-weight:800;font-size:clamp(56px,12vw,186px);line-height:.85;letter-spacing:-.04em;
  color:var(--od);user-select:none;
  display:flex;align-items:center;gap:.1em;
  margin:auto 0;                        /* centred in whatever free space the reveal gives it */
}
/* ---- FOOTER LOCKUP MARK (round 8) --------------------------------------
   The prism mark, inline SVG, much larger than the wordmark's cap height,
   and alive: its six facets fly in from outside the mark and assemble as the
   footer reveals (flow.js writes --fp 0→1 on <footer> from the reveal
   progress), each facet then drifts on its own slow float, and the whole
   thing spreads apart a little on hover. Three nested groups per facet, one
   motion owner each: .pc-asm (assemble) > .pc-hov (hover) > .pc-fl (float). */
.foot-mark{height:1.32em;width:auto;display:block;flex:none;overflow:visible}
.pc-asm,.pc-hov,.pc-fl{transform-box:fill-box;transform-origin:center}
.pc-asm{
  transform:translate(calc(var(--dx) * 1px * (1 - var(--fp,1))),calc(var(--dy) * 1px * (1 - var(--fp,1))))
            rotate(calc(var(--r) * 1deg * (1 - var(--fp,1))));
  opacity:calc(.12 + .88 * var(--fp,1));
}
.pc-hov{transition:transform .7s cubic-bezier(.22,1,.36,1)}
.foot-word:hover .pc-hov{transform:translate(calc(var(--dx) * .09px),calc(var(--dy) * .09px)) rotate(calc(var(--r) * .6deg))}
.pc-fl{animation:pcFloat var(--fd,9s) ease-in-out var(--fo,0s) infinite alternate}
@keyframes pcFloat{from{transform:translate(0,0)}to{transform:translate(var(--fx,12px),var(--fy,-16px))}}
.foot-legal{
  display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;
  font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;
  color:rgba(var(--od-rgb),.5);padding-top:20px;border-top:1px solid rgba(var(--od-rgb),.18);
  margin-top:clamp(48px,8vh,110px);     /* minimum air below the lockup */
}


/* ==========================================================================
   SECTION SIGNATURES (v2.4) — the section-rhythm law
   No two sections on a page may share a signature. Each is a full visual +
   motion identity, not a tint change. Combine freely with [data-stack],
   [data-float], [data-band] and the hue veil. Counter-accents (--acc2/--acc3,
   and their -on variants for dark grounds) carry the differentiation so the
   palette itself never has to shift.
   ========================================================================== */

/* --- ink: a dark band dropped into the light run --- */
[data-sig="ink"]{
  background:var(--gr-band);color:var(--od);position:relative;overflow:hidden;
  border-top:1px solid rgba(var(--acc2-on-rgb),.4);
  border-bottom:1px solid rgba(var(--acc2-on-rgb),.4);
}
[data-sig="ink"] .wrap{position:relative;z-index:1}
[data-sig="ink"] .label{color:rgba(var(--od-rgb),.62)}
[data-sig="ink"] .sect-sticky p,[data-sig="ink"] .c-body,[data-sig="ink"] .row-det p{color:rgba(var(--od-rgb),.72)}
[data-sig="ink"] .rows{border-top-color:rgba(var(--od-rgb),.2)}
[data-sig="ink"] .row-item{border-bottom-color:rgba(var(--od-rgb),.2)}
[data-sig="ink"] .row-area{color:var(--acc3-on)}
[data-sig="ink"] .row-num{color:rgba(var(--od-rgb),.5)}
[data-sig="ink"] .row-item>summary::after{color:var(--acc2-on)}
[data-sig="ink"] .tag-list span{border-color:rgba(var(--od-rgb),.24);color:rgba(var(--od-rgb),.74)}
[data-sig="ink"] .sect-end{border-top-color:rgba(var(--od-rgb),.2)}
[data-sig="ink"] .btn-line{border-color:rgba(var(--od-rgb),.45);color:var(--od)}
[data-sig="ink"] .btn-line:hover{background:var(--od);border-color:var(--od);color:var(--gr-band)}

/* --- numerals: oversized counter-accent figures carry the section --- */
[data-sig="numerals"] .step{
  grid-template-columns:minmax(88px,13%) minmax(0,1fr);
  gap:clamp(18px,4vw,56px);padding:clamp(26px,3.2vw,46px) 0;
}
[data-sig="numerals"] .step .row-num{
  font-family:var(--sans);font-size:clamp(46px,7vw,124px);font-weight:600;
  letter-spacing:-.05em;line-height:.78;padding-top:0;
  color:rgba(var(--acc2-rgb),.32);
}
[data-sig="numerals"] .step h3{font-size:clamp(23px,2.8vw,40px);letter-spacing:-.025em}

/* --- paper: heavy grain on a true paper ground --- */
[data-sig="paper"]{
  position:relative;background-color:var(--surface);
  background-image:var(--noise-paper);background-size:300px 300px;
  background-blend-mode:multiply;     /* --noise-paper is range-compressed so
                                         the ground never drops below AA */
  border-top:1px solid var(--hairline);border-bottom:1px solid var(--hairline);
}
[data-sig="paper"] .card{background:transparent;border-color:var(--rule);border-radius:0}
[data-sig="paper"] .card p,[data-sig="paper"] .sect-sticky p,[data-sig="paper"] .callout p{color:var(--ink-hi)}
[data-sig="paper"] .label{color:var(--ink-hi)}
[data-sig="paper"] .card:hover{transform:translateY(-4px);box-shadow:0 18px 40px rgba(25,25,25,.1)}
[data-sig="paper"] .callout{background:rgba(var(--acc3-rgb),.05);border-color:rgba(var(--acc3-rgb),.22)}

/* --- elevate: the panel lifts off a counter-accent bloom --- */
[data-sig="elevate"]{
  position:relative;
  background:radial-gradient(ellipse 72% 58% at 68% 18%,rgba(var(--acc2-rgb),.11) 0%,rgba(var(--acc2-rgb),0) 70%);
}
[data-sig="elevate"] .price-card{
  border:1px solid rgba(var(--acc2-rgb),.2);
  box-shadow:0 44px 84px -26px rgba(25,25,25,.34),0 10px 24px -10px rgba(var(--acc2-rgb),.3);
}
[data-sig="elevate"] .opt{border-color:var(--rule)}
[data-sig="elevate"] .opt-price{color:var(--acc2)}

/* --- fit: who it's for (round 10, replaces the split card pair) ----------
   Asymmetric on purpose: the good-fit criteria are open ruled statements —
   no cards, no bullets, no numbers — and the not-a-fit list is a quieter
   counterpoint behind a single accent rule. Both stay real <ul>s for AEO. */
.fit-head{font-size:16px;font-weight:600;letter-spacing:-.01em}
.fit-for{list-style:none;margin-top:14px;border-top:1px solid var(--rule)}
.fit-for li{
  padding:17px 0;border-bottom:1px solid var(--rule);
  font-size:clamp(15.5px,1.3vw,18px);line-height:1.55;color:var(--ink-hi);max-width:62ch;
}
.fit-not{
  margin-top:clamp(30px,3.6vw,48px);
  padding:4px 0 4px clamp(20px,2.2vw,30px);border-left:2px solid rgba(var(--acc2-rgb),.5);
}
.fit-not h3{font-size:16px;font-weight:600;letter-spacing:-.01em}
.fit-not ul{list-style:none;display:grid;gap:12px;margin-top:14px}
.fit-not li{color:var(--muted);font-size:15px;line-height:1.55;max-width:58ch}
/* the same structure on an ink band (workflow-review) */
[data-sig="ink"] .fit-head,[data-sig="ink"] .fit-not h3{color:var(--od)}
[data-sig="ink"] .fit-for{border-top-color:rgba(var(--od-rgb),.18)}
[data-sig="ink"] .fit-for li{color:rgba(var(--od-rgb),.85);border-bottom-color:rgba(var(--od-rgb),.18)}
[data-sig="ink"] .fit-not{border-left-color:rgba(var(--acc3-on-rgb),.55)}
[data-sig="ink"] .fit-not li{color:rgba(var(--od-rgb),.62)}
/* safety: any light-surface card dropped on an ink band keeps dark ink */
[data-sig="ink"] .card{color:var(--ink)}
[data-sig="ink"] .card .label{color:var(--muted)}
[data-sig="ink"] .card p,[data-sig="ink"] .card li{color:var(--ink-hi)}

/* --- wash: light-ground aurora behind a statement --- */
[data-sig="wash"]{position:relative;overflow:hidden}
[data-sig="wash"] .aurora{opacity:.5;mix-blend-mode:multiply}
[data-sig="wash"] .wrap{position:relative;z-index:1}
[data-sig="wash"] .fr-out{border-left-color:rgba(var(--acc2-rgb),.5)}

/* --- rule: full-width oversized ruled rows, no sticky column --- */
[data-sig="rule"] .sect-grid{grid-template-columns:1fr;gap:clamp(20px,3vw,40px)}
[data-sig="rule"] .sect-sticky{position:static}
[data-sig="rule"] .faq-row h3{font-size:clamp(22px,3vw,44px);letter-spacing:-.025em;line-height:1.1}
[data-sig="rule"] .faq-row>summary{padding:clamp(22px,2.6vw,38px) 0}
[data-sig="rule"] .faq-row>summary::after{font-size:24px;color:var(--acc2)}
[data-sig="rule"] .faq-row:hover h3{color:var(--acc2)}
[data-sig="rule"] .faq-row>p{font-size:16.5px;max-width:70ch}

/* --- tint: pale counter-accent ground, borderless cards --- */
[data-sig="tint"]{background:linear-gradient(180deg,rgba(var(--acc2-rgb),.07) 0%,rgba(var(--acc3-rgb),.06) 100%)}
[data-sig="tint"] .card{background:var(--surface);border-color:transparent;box-shadow:0 10px 30px rgba(25,25,25,.06)}
[data-sig="tint"] .card:hover{box-shadow:0 22px 50px rgba(25,25,25,.12)}

/* --- black band contents (the marquee is no longer its only user) --- */
[data-band="black"] h2,[data-band="black"] h3{color:var(--od)}
[data-band="black"] .label{color:rgba(var(--od-rgb),.55)}
[data-band="black"] .tools-head p{color:rgba(var(--od-rgb),.76)}
[data-band="black"] .card{background:rgba(var(--od-rgb),.05);border-color:rgba(var(--od-rgb),.18);color:var(--od)}
[data-band="black"] .card p{color:rgba(var(--od-rgb),.72)}
[data-band="black"] .prod .badge{color:var(--acc3-on)}
[data-band="black"] .prod img{border-color:rgba(var(--od-rgb),.14);background:rgba(var(--od-rgb),.04)}
[data-band="black"] .sect-end{border-top-color:rgba(var(--od-rgb),.18)}
[data-band="black"] .btn-line{border-color:rgba(var(--od-rgb),.4);color:var(--od)}
[data-band="black"] .btn-line:hover{background:var(--od);border-color:var(--od);color:#000}

/* --- index: a dense mono inventory wall; the density IS the signature --- */
[data-sig="index"]{
  background:var(--surface);
  border-top:1px solid var(--hairline);border-bottom:1px solid var(--hairline);
}
.idx-head{max-width:62ch}
.idx-head h2{font-size:clamp(30px,3.6vw,58px);line-height:1;letter-spacing:-.03em;font-weight:600;margin-top:14px}
.idx-wall{
  margin-top:clamp(34px,4.4vw,60px);
  columns:3;column-gap:clamp(24px,3vw,52px);column-rule:1px solid var(--hairline);
}
.idx-group{break-inside:avoid;margin:0 0 clamp(26px,2.6vw,38px)}
.idx-cat{
  display:block;font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--acc2);
  padding-bottom:8px;margin-bottom:12px;border-bottom:1px solid rgba(var(--acc2-rgb),.3);
}
.idx-list{list-style:none;display:flex;flex-wrap:wrap;gap:5px}
.idx-list li{
  font-family:var(--mono);font-size:11.5px;line-height:1.35;letter-spacing:.01em;
  color:var(--ink-hi);background:var(--bg);
  border:1px solid var(--hairline);border-radius:4px;padding:5px 8px;
}
.idx-list li:hover{border-color:rgba(var(--acc2-rgb),.5);color:var(--acc2)}
.idx-foot{
  margin-top:clamp(10px,2vw,24px);padding-top:20px;border-top:1px solid var(--hairline);
  font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);
  display:flex;gap:24px;flex-wrap:wrap;
}
@media (max-width:1100px){.idx-wall{columns:2}}

@media (max-width:900px){
  .navlinks{display:none}
  .nav-actions .orc{display:none}
  .hero-foot{grid-template-columns:1fr}
  .sect-grid{grid-template-columns:1fr}
  .sect-sticky{position:static}
  .svc-card{grid-template-columns:minmax(0,1fr);position:static;transform:none !important}
  .svc-card .price{grid-column:1;text-align:left;padding-top:0}
  .stats{grid-template-columns:1fr}
  .stat{border-left:0;border-top:1px solid rgba(var(--od-rgb),.18);padding-left:0}
  .stat:first-child{border-top:0}
  .cards{grid-template-columns:1fr}
  .cta-card{grid-template-columns:1fr}
  .foot-grid{grid-template-columns:1fr 1fr;gap:32px}
  .footer-spacer{display:none}
  footer{position:relative;height:auto;padding:56px 0 28px}
  footer>.wrap:last-of-type{padding-top:44px}
  .foot-word{margin:0 0 24px}
  .foot-mark{height:1em}
  .foot-legal{margin-top:24px}
}

/* ---- MOBILE COMPACTION (round 11) --------------------------------------
   Phones only (≤560px) — the desktop and tablet layouts are untouched.
   Single-column pages get very tall: this tightens the vertical rhythm
   (section padding, card padding, list gaps) without dropping content.
   Keep every rule inside this query. */
@media (max-width:560px){
  .sect{padding:40px 0}
  .sect-grid{gap:26px}
  .sect-sticky h2{font-size:31px}
  .sect-sticky p{margin-top:12px}
  .statement{padding:40px 0 48px}
  .statement .label{margin-bottom:18px}
  .wordrv{font-size:28px}
  .orch{padding:56px 0}
  .media{padding:44px 0}
  .media-head{margin-bottom:18px}
  .cta-final{padding:48px 0 64px}
  .cta-card{padding:34px 22px;gap:26px}
  .cta-card h2{font-size:34px}
  .cta-card p{margin-top:14px}
  .cta-list{gap:11px;margin-top:20px;padding-top:18px}
  .svc-cards{gap:12px}
  .svc-card{padding:22px 20px 20px;border-radius:16px;gap:12px}
  .cards{gap:12px}
  .card{padding:22px 20px}
  .fit-for li{padding:13px 0}
  .fit-not{margin-top:26px}
  .fit-not ul{gap:9px;margin-top:11px}
  .idx-wall{columns:2;column-gap:14px;margin-top:22px}
  .idx-group{margin-bottom:18px}
  .idx-list{gap:4px}
  .idx-list li{font-size:11px;padding:4px 7px}
  .idx-cat{padding-bottom:6px;margin-bottom:9px}
  .idx-foot{margin-top:8px;padding-top:14px}
  .stats{margin:26px 0}
  .stat{padding:14px 0}
  .stat b{font-size:30px}
  .stat span{margin-top:6px}
  [data-sig="numerals"] .step{padding:20px 0;gap:10px}
  [data-sig="numerals"] .step .row-num{font-size:30px}
  [data-sig="numerals"] .step h3{font-size:21px}
  footer{padding:40px 0 20px}
  footer>.wrap:last-of-type{padding-top:32px}
  /* phones: two 1fr columns can't shrink below the CTA buttons' min width,
     which was pushing the whole document past the viewport (horizontal
     scroll + clipped text). Brand block goes full-width; the link columns
     stay two-up beneath it. */
  .foot-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:22px}
  .foot-brand{grid-column:1 / -1}
  .foot-brand .foot-cta{margin-top:18px}
  .hero{padding:112px 0 40px}
  .hero .label{margin-bottom:22px}
  .hero-foot{margin-top:26px;padding-top:20px;gap:20px}
}

/* ---- cross-document view transitions (round 12; dip-to-ground round 13) ----
   Same-origin navigations DIP through the page ground instead of
   hard-loading: the old page settles into the ground colour (fade + 2%
   scale), the new page rises out of it. flow.js parks every reveal until the
   dip has landed (html.vt-in), so the choreography is dip → land → type
   rises, never a crossfade with reveals mushing through it. Progressive
   enhancement: unsupported browsers and reduced-motion users get the normal
   instant navigation. Pairs with initSpeculation() in flow.js and the
   <link rel="expect" blocking="render"> in each head, which stops Chrome
   snapshotting a half-parsed page. */
@media (prefers-reduced-motion:no-preference){
  @view-transition{navigation:auto}
  ::view-transition{background:var(--gr-hero)}
  ::view-transition-old(root){animation:vt-out .26s cubic-bezier(.4,0,.6,1) both}
  ::view-transition-new(root){animation:vt-in .5s cubic-bezier(.16,.84,.28,1) .2s both}
}
@keyframes vt-out{to{opacity:0;transform:scale(.98)}}
@keyframes vt-in{from{opacity:0;transform:translateY(16px)}}

/* odometer spans must escape the .stat span label styling (prism.css:610) */
.stat b span{display:inline;margin:0;font-family:inherit;font-size:inherit;letter-spacing:inherit;text-transform:none;color:inherit}
.stat b .od{display:inline-flex;height:1em;overflow:hidden}
.stat b .od-reel{display:flex;flex-direction:column;line-height:1}
.stat b .od-reel span{display:block;height:1em}
