/* ==========================================================================
   Rubikal — ONE-PAGE EXPERIENCE  ·  assets/css/one.css
   A self-contained design system for the flagship single page (en/index.html).
   Direction: "precision-engineered cinematic" — deep blue-black space, film
   grain, HUD mono labels, oversized display type, hairline rules. The tri-
   colour cube is the only fully-saturated object; UI colour is rationed.
   Old pages keep tokens.css/main.css; this file owns the new page alone.
   ========================================================================== */

/* --------------------------------------------------------------------------
   0 · FONTS (self-hosted, variable)
   -------------------------------------------------------------------------- */
/* The three Latin faces are subset to the glyphs this site actually uses
   (Latin + punctuation + currency + arrows + the handful of symbols in CSS
   content), which halves them: 164,396 → 82,232 bytes. Arabic is deliberately
   absent — Tajawal owns it. The full faces stay in assets/fonts/ as the source
   for re-subsetting; they are never served. Regenerate with:

     pyftsubset assets/fonts/<face>.woff2 \
       --output-file=assets/fonts/<face>-sub.woff2 --flavor=woff2 \
       --layout-features='*' --name-IDs='*' --notdef-outline \
       --unicodes="$(cat scripts/subset-unicodes.txt)"

   --layout-features and --name-IDs keep kerning/ligatures and the licence
   records; the variable weight axes (Clash 200-700, Satoshi 300-900) survive,
   which the fractional weights on this page depend on. */
@font-face {
  font-family: "Clash Display";
  src: url("../fonts/clash-display-variable-sub.woff2") format("woff2");
  font-weight: 200 700;
  font-display: swap;
}
@font-face {
  font-family: "Satoshi";
  src: url("../fonts/satoshi-variable-sub.woff2") format("woff2");
  font-weight: 300 900;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("../fonts/jetbrains-mono-400-sub.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}

/* Arabic. Clash/Satoshi/JetBrains carry zero Arabic glyphs (verified by cmap),
   so the Arabic one-pager pairs Clash with Tajawal: the unicode-range keeps
   these faces off the English page, and per-character fallback routes Arabic
   runs here while Latin runs (brand names, MVP, URLs) stay on Clash/Satoshi.
   Display weights snap to 700/800 — Clash's 560-620 has no Tajawal equivalent. */
@font-face {
  font-family: "Tajawal";
  src: url("../fonts/tajawal-400.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC, U+102E0-102FB, U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF;
}
@font-face {
  font-family: "Tajawal";
  src: url("../fonts/tajawal-500.woff2") format("woff2");
  font-weight: 500;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC, U+102E0-102FB, U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF;
}
@font-face {
  font-family: "Tajawal";
  src: url("../fonts/tajawal-700.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC, U+102E0-102FB, U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF;
}
@font-face {
  font-family: "Tajawal";
  src: url("../fonts/tajawal-800.woff2") format("woff2");
  font-weight: 800;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC, U+102E0-102FB, U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF;
}

/* Metric-compatible stand-in for Tajawal, so the swap cannot move layout.
   Calibrated in the browser, not from a font file: Chrome will not match
   local("Geeza Pro") — macOS keeps its Arabic system faces out of local() —
   so the candidate that actually wins is Tahoma, which also ships on Windows.
   Calibrated on real prose, not on a letter sample: Tahoma's space glyph is
   ~50% wider than Tajawal's, so matching the letters (107.9%) still wrapped
   paragraphs a line early. Measured on the hero lead at 100px — Tajawal 7051px
   vs stand-in 7800px — the ratio that makes running Arabic text occupy the same
   width is size-adjust 97.5%, with Tajawal's own metrics (upem 1000, typo asc
   643 / desc -357 / gap 200) divided by that factor. The original 123.7% came
   from Arial, which never renders here: it left the stand-in ~15% too wide, the
   hero lead wrapped to five lines instead of four, and the hero grid moved when
   Tajawal arrived. Where none of these faces exist (Android, most Linux) the
   platform's own Arabic font renders unadjusted — nothing to calibrate against
   without shipping a second file, which is why the hero also reserves its box. */
@font-face {
  font-family: "Tajawal Fallback";
  src: local("Tahoma"), local("Segoe UI"), local("Noto Sans Arabic"), local("Geeza Pro");
  size-adjust: 97.5%;
  ascent-override: 65.9%;
  descent-override: 36.6%;
  line-gap-override: 20.5%;
}

/* --------------------------------------------------------------------------
   1 · TOKENS
   -------------------------------------------------------------------------- */
:root {
  /* Brand — sRGB with wide-gamut upgrades */
  --blue:   #1E60FD;
  --pink:   #FF0054;
  --yellow: #F8CE3A;
  --violet: #6A47F0;

  /* Space (page) ramp — blue-black, never pure black */
  --void-950: #04050A;
  --void-900: #060810;
  --void-850: #090B16;
  --void-800: #0D101E;
  --void-700: #141830;
  --paper:    #F3F0E9;   /* the one light act */
  --paper-2:  #EAE6DB;

  --fg:        #EAECF6;
  --fg-strong: #FFFFFF;
  --muted:     #8E93AD;
  --faint:     #575D78;   /* decoration only — below 4.5:1 on the void ramp */
  /* --blue is a UI colour, not a text colour: at #1E60FD it measures 4.02:1 on
     --void-950. Small text that must be read uses this lifted sibling, which
     clears 4.5:1 on every surface in the ramp (7.2:1 worst case). */
  --blue-ink:  #6C9FFF;

  --line:        rgb(255 255 255 / .08);
  --line-strong: rgb(255 255 255 / .16);

  --glow-blue: 0 0 90px -18px rgb(30 96 253 / .55);

  /* Type */
  --f-display: "Clash Display", "Tajawal", system-ui, sans-serif;
  --f-body: "Satoshi", "Tajawal", system-ui, sans-serif;
  --f-mono: "JetBrains Mono", ui-monospace, "SF Mono", monospace;

  --t-hero: clamp(2.7rem, 6.6vw, 6.3rem);
  --t-h2:   clamp(2.1rem, 4.6vw, 4rem);
  --t-h3:   clamp(1.25rem, 1.9vw, 1.6rem);
  --t-lead: clamp(1.06rem, 1.45vw, 1.32rem);
  --t-body: 1.05rem;
  --t-sm:   .92rem;
  --t-mono: .74rem;

  /* Rhythm */
  --sect: clamp(96px, 12vw, 190px);
  --gut:  clamp(20px, 4.5vw, 72px);
  --maxw: 1440px;
  --hdr: 72px;

  /* Motion */
  --snap: cubic-bezier(.83, 0, .17, 1);          /* quarter-turn feel */
  --out:  cubic-bezier(.16, 1, .3, 1);
  --spring: cubic-bezier(.34, 1.45, .5, 1);

  --r-sm: 10px;
  --r-md: 16px;
  --r-lg: 24px;
  --r-xl: 36px;
}

/* Wide-gamut accents where supported */
@supports (color: color(display-p3 0 0 0)) {
  :root {
    --blue:   color(display-p3 .18 .38 1);
    --pink:   color(display-p3 1 .08 .36);
    --yellow: color(display-p3 .98 .81 .27);
  }
}

/* --------------------------------------------------------------------------
   2 · BASE
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }

html {
  scroll-behavior: smooth;
  scrollbar-gutter: stable;
  -webkit-text-size-adjust: 100%;
}
html:has(dialog[open]) { overflow: hidden; }

body {
  margin: 0;
  background: var(--void-950);
  color: var(--fg);
  font-family: var(--f-body);
  font-size: var(--t-body);
  line-height: 1.65;
  font-weight: 420;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

h1, h2, h3, h4 { margin: 0; font-family: var(--f-display); color: var(--fg-strong); line-height: 1.02; letter-spacing: -.015em; text-wrap: balance; }
p { margin: 0; text-wrap: pretty; }
a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }
/* <picture> wrappers must not become the flex/grid item — the <img> stays
   the box every layout rule in this file already targets. */
picture { display: contents; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; padding: 0; }
::selection { background: var(--blue); color: #fff; }

:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; border-radius: 4px; }

.skip-link {
  position: fixed; inset-block-start: -60px; inset-inline-start: 16px;
  background: var(--blue); color: #fff; padding: 10px 18px; border-radius: 8px;
  z-index: 200; transition: inset-block-start .25s var(--out);
}
.skip-link:focus-visible { inset-block-start: 12px; }

.container { max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gut); }

/* Film grain — static texture, normal blending: near-identical look at a
   fraction of the compositing cost (no animation, no blend-mode) */
.grain {
  position: fixed; inset: 0; z-index: 90; pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.72' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
  opacity: .035;
}

/* Scroll progress — CSS scroll-driven where supported (no JS) */
.progress {
  position: fixed; inset-inline: 0; inset-block-start: 0; block-size: 2px; z-index: 130;
  background: linear-gradient(90deg, var(--blue), var(--violet) 52%, var(--pink));
  transform-origin: 0 50%; transform: scaleX(0);
  display: none;
}
@supports (animation-timeline: scroll()) {
  .progress { display: block; animation: progress-fill linear both; animation-timeline: scroll(root); }
  @keyframes progress-fill { to { transform: scaleX(1); } }
}

/* WebGL stage — fixed behind everything */
.stage {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  opacity: 0; transition: opacity .8s var(--out);
}
.stage.is-on { opacity: 1; }
.stage canvas { width: 100%; height: 100%; display: block; }

/* Aurora backwash behind the stage */
.aurora {
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(42% 55% at 78% 18%, rgb(30 96 253 / .16), transparent 70%),
    radial-gradient(34% 44% at 12% 82%, rgb(255 0 84 / .09), transparent 72%),
    radial-gradient(30% 38% at 55% 108%, rgb(106 71 240 / .12), transparent 75%);
}

main { position: relative; z-index: 1; }

/* --------------------------------------------------------------------------
   3 · HUD FURNITURE (labels, rules, section headers)
   -------------------------------------------------------------------------- */
.hud {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--f-mono); font-size: var(--t-mono);
  letter-spacing: .22em; text-transform: uppercase; color: var(--muted);
}
.hud b { white-space: nowrap; }
.hud::before { content: ""; inline-size: 26px; block-size: 1px; background: linear-gradient(90deg, var(--blue), transparent); }
.hud b { color: var(--blue-ink); font-weight: 400; }

.sect { padding-block: var(--sect); position: relative; }
/* (deliberately no content-visibility: its estimated placeholder heights
   shift real layout as sections enter view — the jank costs more than the
   paint saving on a page this size) */
.sect-head { max-width: 880px; margin-block-end: clamp(40px, 6vw, 84px); }
.sect-head h2 { font-size: var(--t-h2); font-weight: 570; margin-block-start: 18px; }
.sect-head .lead { margin-block-start: 18px; }

.lead { font-size: var(--t-lead); line-height: 1.55; color: var(--muted); font-weight: 430; }
.lead strong, .lead b { color: var(--fg); font-weight: 560; }

/* Inline highlight: the cube's rarest hue. (Replaces an animated blue→violet
   →pink gradient — the one true slop signal on a page whose colour is
   rationed. Yellow is otherwise only the badge dot and the Friday node.) */
.hi { color: var(--yellow); font-style: normal; }

.hairline { border: 0; block-size: 1px; margin: 0; background: var(--line); }

/* --------------------------------------------------------------------------
   4 · BUTTONS
   -------------------------------------------------------------------------- */
.btn {
  --btn-bg: var(--blue);
  position: relative; isolation: isolate;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  font-family: var(--f-body); font-weight: 560; font-size: 1rem;
  padding: 15px 28px; border-radius: 999px;
  color: #fff; background: var(--btn-bg);
  transition: transform .3s var(--spring), box-shadow .3s var(--out), background-color .3s;
  will-change: transform;
}
.btn .arr { transition: transform .3s var(--spring); display: inline-block; }
.btn:hover .arr, .btn:focus-visible .arr { transform: translateX(5px); }
.btn-primary { box-shadow: 0 10px 34px -12px rgb(30 96 253 / .65), inset 0 1px 0 rgb(255 255 255 / .18); }
.btn-primary:hover { background: #1A56E8; box-shadow: 0 14px 44px -12px rgb(30 96 253 / .85), inset 0 1px 0 rgb(255 255 255 / .2); }
.btn-ghost {
  background: rgb(255 255 255 / .05); color: var(--fg);
  box-shadow: inset 0 0 0 1px var(--line-strong);
  backdrop-filter: blur(8px);
}
.btn-ghost:hover { background: rgb(255 255 255 / .09); box-shadow: inset 0 0 0 1px rgb(255 255 255 / .3); }
.btn-lg { padding: 18px 34px; font-size: 1.06rem; }
.btn-sm { padding: 10px 20px; font-size: .92rem; }
.btn-wa { gap: 9px; }
.btn-wa svg { flex: none; }

.link-arrow {
  display: inline-flex; align-items: center; gap: 8px; font-weight: 560; color: var(--fg-strong);
}
.link-arrow .arr { transition: transform .3s var(--spring); }
.link-arrow:hover .arr { transform: translateX(5px); }

/* --------------------------------------------------------------------------
   5 · HEADER + NAV
   -------------------------------------------------------------------------- */
.hdr {
  position: fixed; inset-inline: 0; inset-block-start: 0; z-index: 120;
  transition: transform .45s var(--out);
}
.hdr-in {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  max-width: calc(var(--maxw) + 40px); margin-inline: auto;
  padding: 14px var(--gut);
  transition: background-color .4s, backdrop-filter .4s, box-shadow .4s, padding .4s var(--out);
}
.hdr.is-scrolled .hdr-in {
  /* solid tint, no backdrop-filter — blur behind a sticky header repaints
     on every scrolled frame and is a main source of scroll jank */
  background: rgb(7 9 18 / .94);
  box-shadow: 0 1px 0 var(--line);
  padding-block: 10px;
}
.hdr.is-hidden { transform: translateY(-110%); }

.brand { display: inline-flex; align-items: center; }
.brand img { block-size: 34px; inline-size: auto; }

.nav { display: flex; align-items: center; gap: 4px; }
.nav a {
  position: relative; padding: 9px 14px; font-size: .95rem; font-weight: 500; color: var(--muted);
  border-radius: 999px; transition: color .25s;
}
.nav a::after {
  content: ""; position: absolute; inset-inline: 14px; inset-block-end: 5px; block-size: 1px;
  background: var(--blue); transform: scaleX(0); transform-origin: 0 50%; transition: transform .3s var(--out);
}
.nav a:hover, .nav a.is-live { color: var(--fg-strong); }
.nav a:hover::after, .nav a.is-live::after { transform: scaleX(1); }

.hdr-end { display: flex; align-items: center; gap: 14px; }
.lang {
  font-family: var(--f-mono); font-size: .8rem; color: var(--muted); letter-spacing: .04em;
  padding: 8px 12px; border-radius: 999px; box-shadow: inset 0 0 0 1px var(--line);
  transition: color .25s, box-shadow .25s;
}
.lang:hover { color: var(--fg-strong); box-shadow: inset 0 0 0 1px var(--line-strong); }

.burger { display: none; position: relative; inline-size: 44px; block-size: 44px; border-radius: 50%; box-shadow: inset 0 0 0 1px var(--line-strong); }
.burger span {
  position: absolute; inset-inline: 13px; block-size: 1.6px; background: var(--fg);
  transition: transform .35s var(--snap), opacity .25s;
}
.burger span:nth-child(1) { inset-block-start: 17px; }
.burger span:nth-child(2) { inset-block-start: 26px; }

/* Mobile nav dialog */
.sheet {
  inset: 0; inline-size: 100%; block-size: 100dvh; max-inline-size: none; max-block-size: none;
  border: 0; margin: 0; padding: 0; background: rgb(4 5 10 / .92);
  -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px); color: var(--fg);
}
.sheet::backdrop { background: transparent; }
.sheet-in { display: flex; flex-direction: column; gap: 6px; padding: calc(var(--hdr) + 24px) 28px 40px; }
.sheet a.big {
  font-family: var(--f-display); font-size: clamp(2rem, 9vw, 3rem); font-weight: 560;
  color: var(--fg-strong); padding-block: 10px; border-block-end: 1px solid var(--line);
  display: flex; justify-content: space-between; align-items: center;
}
.sheet a.big small { font-family: var(--f-mono); font-size: .72rem; color: var(--muted); letter-spacing: .2em; }
.sheet-foot { margin-block-start: 28px; display: flex; flex-wrap: wrap; gap: 12px; }
.sheet-x { position: fixed; inset-block-start: 16px; inset-inline-end: 18px; inline-size: 46px; block-size: 46px; border-radius: 50%; box-shadow: inset 0 0 0 1px var(--line-strong); font-size: 1.5rem; line-height: 1; color: var(--fg); }
.sheet[open] { animation: sheet-in .45s var(--out); }
@keyframes sheet-in { from { opacity: 0; transform: translateY(-3%); } }

/* --------------------------------------------------------------------------
   5b · SIGNATURE MOVES
   Three grammars borrowed from the object the brand is named after. All of it
   is decoration: every rule sits behind prefers-reduced-motion: no-preference,
   and nothing here carries text or meaning.
   -------------------------------------------------------------------------- */

/* THE QUARTER TURN. The cube solves in quarter turns, so that is the hover
   grammar: a 6px tri-colour chip that snaps 90° with the same --snap curve the
   FAQ control already used. */
.nav a, .foot-col a, .link-arrow, .sheet a.big { --turn: 0deg; }
.nav a::before, .foot-col a::before {
  content: ""; position: absolute; inset-block-start: 50%; inset-inline-start: 0;
  inline-size: 6px; block-size: 6px; translate: 0 -50%;
  background: conic-gradient(from -45deg, var(--blue) 0 33%, var(--pink) 0 66%, var(--yellow) 0);
  opacity: 0; rotate: var(--turn);
  transition: opacity .25s var(--out), rotate .45s var(--snap);
}
.nav a { padding-inline: 16px 14px; }
.nav a::before { inset-inline-start: 4px; }
.foot-col a { position: relative; padding-inline-start: 0; transition: color .25s, padding-inline-start .3s var(--snap); }
.foot-col a:hover { padding-inline-start: 14px; }
@media (prefers-reduced-motion: no-preference) {
  .nav a:hover::before, .nav a.is-live::before, .foot-col a:hover::before { opacity: 1; --turn: 90deg; }
}
/* the FAQ control and the burger take the same quarter turn on hover */
@media (prefers-reduced-motion: no-preference) {
  .faq-list summary { --turn: 0deg; }
  .faq-list summary:hover .pm { rotate: 90deg; }
  .faq-list summary .pm { transition: rotate .45s var(--snap), box-shadow .3s; }
  .burger:hover span:nth-child(1) { transform: translateY(2px) rotate(90deg) scaleX(.55); }
  .burger:hover span:nth-child(2) { transform: translateY(-2px) rotate(90deg) scaleX(.55); }
}

/* THE DATA PULSE. The cube's seams carry pulses of light; on hover a 1px
   tri-colour dash travels the same way along a link's hairline. One rule for
   the nav and the footer, sharing the ::after surface the nav already had. */
.foot-col a::after {
  content: ""; position: absolute; inset-inline: 0; inset-block-end: -3px; block-size: 1px;
  background: var(--line-strong); transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .3s var(--out);
}
.foot-col a:hover::after { transform: scaleX(1); }
@media (prefers-reduced-motion: no-preference) {
  .nav a:hover::after, .foot-col a:hover::after {
    background-image: linear-gradient(90deg, var(--blue) 0 18%, var(--pink) 18% 36%, var(--yellow) 36% 54%, transparent 54%);
    background-size: 260% 100%; background-repeat: repeat-x;
    animation: pulse-travel 1.15s linear infinite;
  }
  @keyframes pulse-travel { from { background-position: 0 0; } to { background-position: -260% 0; } }
}

/* --------------------------------------------------------------------------
   6 · HERO
   -------------------------------------------------------------------------- */
.hero { min-block-size: 100svh; display: grid; align-items: center; padding-block: calc(var(--hdr) + 40px) 60px; position: relative; }
/* The reserved hero box. The hero is exactly 100svh and centres this grid, so
   any change in the grid's own height moves it — which is how a late webfont
   swap shows up as layout shift (measured as the culprit on /ar/). The
   reservation is viewport-derived, comfortably above the settled content height
   at every breakpoint (610-653px measured at 390-1920px wide) and always below
   the hero's own height, so the box is stable whichever face renders first. */
.hero-grid {
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr); gap: 40px;
  align-items: center; align-content: center;
  min-block-size: min(76svh, 700px);
}

.hero-copy { max-width: 760px; }
.hero-badge {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--f-mono); font-size: .76rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--fg); padding: 9px 16px; border-radius: 999px;
  background: rgb(255 255 255 / .04); box-shadow: inset 0 0 0 1px var(--line);
  margin-block-end: 26px;
}
.hero-badge .dot { inline-size: 7px; block-size: 7px; border-radius: 50%; background: var(--yellow); box-shadow: 0 0 12px 1px rgb(248 206 58 / .8); }
@media (prefers-reduced-motion: no-preference) {
  .hero-badge .dot { animation: pulse 2.2s ease-in-out infinite; }
  @keyframes pulse { 50% { opacity: .35; } }
}

.hero h1 {
  font-size: var(--t-hero); font-weight: 590; letter-spacing: -.025em; line-height: .98;
  margin-block-end: 26px;
}
.hero h1 .line { display: block; overflow: clip; padding-block-end: .06em; margin-block-end: -.06em; }
.hero h1 .ln { display: block; }
.hero .lead { max-width: 560px; }

.hero-cta { display: flex; flex-wrap: wrap; gap: 14px; margin-block-start: 38px; }

/* Tertiary beat: what the primary CTA costs you, then the work link */
.hero-tert { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 24px; margin-block-start: 24px; }
.hero-note { font-family: var(--f-mono); font-size: var(--t-mono); letter-spacing: .18em; text-transform: uppercase; color: var(--muted); }
.hero-tert .link-arrow { font-size: .95rem; font-weight: 540; color: var(--muted); transition: color .25s; }
.hero-tert .link-arrow:hover { color: var(--fg-strong); }

/* Right column — reserved for the WebGL cube; fallback art lives here */
.hero-stage { position: relative; min-block-size: min(56vw, 560px); }
.gl-fallback {
  position: absolute; inset: 0; display: none; place-items: center;
}
.gl-fallback svg { inline-size: min(46%, 240px); block-size: auto; filter: drop-shadow(0 30px 60px rgb(30 96 253 / .35)); }
@media (prefers-reduced-motion: no-preference) {
  .gl-fallback svg { animation: floaty 7s ease-in-out infinite; }
  @keyframes floaty { 50% { transform: translateY(-16px) rotate(2deg); } }
}
html.no-gl .gl-fallback { display: grid; }

/* (scroll hint removed — it collided with the proof chips; the progress
   bar and section rail already communicate scrollability) */

/* --------------------------------------------------------------------------
   6b · READOUT (proof, below the fold)
   An instrument-panel strip, not a chip row: mono keys, Clash Display values
   in tabular-nums, hairline cells. The H1 owns the hero column instead.
   -------------------------------------------------------------------------- */
.readout { border-block-start: 1px solid var(--line); }
.readout-in {
  display: grid; grid-template-columns: repeat(3, 1fr);
  padding-block: clamp(22px, 3vw, 34px);
}
.ro {
  display: grid; align-content: start; gap: 6px;
  padding-inline-end: clamp(16px, 3vw, 44px);
}
.ro + .ro { border-inline-start: 1px solid var(--line); padding-inline-start: clamp(20px, 3.5vw, 52px); }
.ro-k { font-family: var(--f-mono); font-size: var(--t-mono); letter-spacing: .22em; text-transform: uppercase; color: var(--muted); }
.ro-v {
  font-family: var(--f-display); font-weight: 590; font-size: clamp(1.6rem, 2.6vw, 2.2rem);
  line-height: 1; letter-spacing: -.02em; color: var(--fg-strong);
  font-variant-numeric: tabular-nums;
}
.ro-u { font-size: .5em; font-weight: 500; color: var(--blue-ink); margin-inline-start: .3em; letter-spacing: 0; }
.ro-n { font-size: .84rem; color: var(--muted); }
a.ro .arr { display: inline-block; color: var(--faint); transition: transform .3s var(--spring), color .3s; }
a.ro:hover .ro-v { color: var(--yellow); }
a.ro:hover .arr { transform: translateX(4px); color: var(--fg); }

/* --------------------------------------------------------------------------
   7 · MARQUEE (clients)
   -------------------------------------------------------------------------- */
.marquee-wrap { padding-block: clamp(40px, 6vw, 72px); border-block: 1px solid var(--line); }
.marquee-label { display: flex; justify-content: center; text-align: center; margin-block-end: 34px; }
.marquee {
  overflow: clip; display: flex;
  mask: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  -webkit-mask: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.marquee-track {
  display: flex; align-items: center; gap: clamp(48px, 6vw, 96px);
  padding-inline-end: clamp(48px, 6vw, 96px);
  flex: none; min-inline-size: max-content;
  animation: slide 70s linear infinite;   /* one row, unhurried */
}
.marquee:hover .marquee-track { animation-play-state: paused; }
@keyframes slide { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) {
  .marquee-track { animation: none; }
  .marquee { flex-wrap: wrap; justify-content: center; mask: none; -webkit-mask: none; }
}
/* The cap is the point. Locking height alone lets an ultra-wide wordmark run to
   its own aspect ratio — Vestaboard (320x28) reached 343px beside a 167px
   WileyPLUS — so the row reads as logos at different scales rather than one
   set. 168px is the WileyPLUS/GEA cluster the eye already uses as the norm;
   object-fit: contain lets anything wider sit down inside it in proportion.
   Same cap the Work and About grids have carried in main.css all along. */
.marquee img {
  block-size: clamp(22px, 2.6vw, 30px); inline-size: auto; flex: none;
  max-inline-size: 168px; object-fit: contain;
  filter: grayscale(1) brightness(3.2) contrast(.72);
  opacity: .5; transition: opacity .3s, filter .3s;
}
.marquee img:hover { opacity: 1; filter: grayscale(0) brightness(1); }

/* --------------------------------------------------------------------------
   8 · SPRINT STRIP (idea → prototype in days)
   -------------------------------------------------------------------------- */
.sprint { position: relative; }
.sprint-card {
  position: relative; overflow: clip;
  border-radius: var(--r-xl);
  background: linear-gradient(140deg, var(--void-800), var(--void-900) 60%);
  box-shadow: inset 0 0 0 1px var(--line), 0 40px 90px -50px rgb(0 0 0 / .8);
  padding: clamp(30px, 5vw, 64px);
}
.sprint-card::before {
  content: ""; position: absolute; inset: -1px; border-radius: inherit; pointer-events: none;
  background:
    radial-gradient(52% 70% at 12% 0%, rgb(30 96 253 / .16), transparent 65%),
    radial-gradient(40% 60% at 95% 100%, rgb(255 0 84 / .1), transparent 70%);
}
.sprint-grid { position: relative; display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); gap: clamp(28px, 4vw, 64px); align-items: center; }
.sprint h2 { font-size: clamp(1.9rem, 3.4vw, 3rem); font-weight: 570; margin-block: 16px 14px; }
.sprint p.lead { font-size: 1.08rem; }
.sprint-grid .hero-cta { margin-block-start: 28px; }

.week { display: grid; gap: 0; position: relative; }
.day {
  display: grid; grid-template-columns: 84px 1fr; gap: 18px; align-items: start;
  padding-block: 13px; position: relative;
}
.day + .day { border-block-start: 1px dashed rgb(255 255 255 / .07); }
.day .d {
  font-family: var(--f-mono); font-size: .72rem; letter-spacing: .18em; color: var(--muted);
  padding-block-start: 4px; text-transform: uppercase;
}
.day .t { font-weight: 560; color: var(--fg-strong); }
.day .s { display: block; font-size: .9rem; color: var(--muted); font-weight: 420; margin-block-start: 2px; }
.day.fri .t { color: var(--yellow); }
.day .node {
  position: absolute; inset-inline-start: 62px; inset-block-start: 20px;
  inline-size: 7px; block-size: 7px; border-radius: 50%;
  background: var(--blue); box-shadow: 0 0 0 4px rgb(30 96 253 / .15);
}
.day.fri .node { background: var(--yellow); box-shadow: 0 0 0 4px rgb(248 206 58 / .18), 0 0 18px rgb(248 206 58 / .8); }

/* --------------------------------------------------------------------------
   9 · SERVICES
   -------------------------------------------------------------------------- */
.svc-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
.svc {
  position: relative; overflow: clip; border-radius: var(--r-lg);
  background: rgb(255 255 255 / .025);
  box-shadow: inset 0 0 0 1px var(--line);
  padding: clamp(26px, 3.4vw, 46px);
  transition: transform .45s var(--out), box-shadow .45s var(--out), background-color .45s;
}
.svc:hover { transform: translateY(-6px); background: rgb(255 255 255 / .04); box-shadow: inset 0 0 0 1px var(--line-strong), 0 30px 70px -40px rgb(0 0 0 / .9); }
.svc::after {   /* pointer spotlight */
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0; transition: opacity .4s;
  background: radial-gradient(420px 320px at var(--mx, 50%) var(--my, 0%), rgb(30 96 253 / .1), transparent 65%);
}
.svc:hover::after { opacity: 1; }
.svc .no {
  font-family: var(--f-mono); font-size: .76rem; letter-spacing: .22em; color: var(--muted);
}
.svc h3 { font-size: clamp(1.5rem, 2.3vw, 2rem); font-weight: 570; margin-block: 14px 12px; }
.svc p { color: var(--muted); max-width: 52ch; }
.svc-tags { display: flex; flex-wrap: wrap; gap: 8px; margin-block-start: 22px; }
.tag {
  font-family: var(--f-mono); font-size: .72rem; letter-spacing: .06em; color: var(--muted);
  padding: 7px 12px; border-radius: 999px; box-shadow: inset 0 0 0 1px var(--line);
}
.svc .link-arrow { margin-block-start: 26px; }
.svc-consult {
  grid-column: 1 / -1; display: grid; grid-template-columns: 1fr auto; gap: 24px; align-items: center;
  border-radius: var(--r-lg); padding: clamp(24px, 3vw, 38px) clamp(26px, 3.4vw, 46px);
  background: linear-gradient(120deg, rgb(30 96 253 / .12), rgb(106 71 240 / .08) 55%, rgb(255 0 84 / .07));
  box-shadow: inset 0 0 0 1px rgb(94 133 255 / .25);
}
.svc-consult h3 { font-size: 1.35rem; font-weight: 570; }
.svc-consult p { color: var(--muted); margin-block-start: 6px; max-width: 60ch; }

/* Maturity path — the sprint week's grammar (dashed hairline + node dots)
   applied to the tiers, so they read as a route through the work rather than
   a SaaS pricing grid. No boxes, no "most common" highlight card. */
.path {
  position: relative; display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(22px, 3vw, 48px); margin-block-start: 60px; padding-block-start: 34px;
}
.path::before {
  content: ""; position: absolute; inset-block-start: 5px; inset-inline: 0;
  border-block-start: 1px dashed rgb(255 255 255 / .1);
}
.tier { position: relative; }
.tier .node {
  position: absolute; inset-block-start: -33px; inset-inline-start: 0;
  inline-size: 9px; block-size: 9px; border-radius: 50%;
  background: var(--blue); box-shadow: 0 0 0 4px rgb(30 96 253 / .15);
}
.tier.mid .node { background: var(--yellow); box-shadow: 0 0 0 4px rgb(248 206 58 / .18), 0 0 18px rgb(248 206 58 / .7); }
.tier .hud { margin-block-end: 14px; }
.tier h4 { font-size: 1.2rem; font-weight: 570; }
.tier .tier-lead { font-size: .93rem; color: var(--muted); margin-block: 8px 16px; }
.tier ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 9px; }
.tier li { display: flex; gap: 10px; font-size: .93rem; color: var(--fg); }
.tier li::before { content: "→"; color: var(--blue); flex: none; }
.tier-cta { margin-block-start: 22px; font-size: .95rem; color: var(--fg); }
.tier-cta:hover { color: var(--fg-strong); }

/* --------------------------------------------------------------------------
   10 · PROCESS (pinned act)
   -------------------------------------------------------------------------- */
.process { position: relative; }
/* Not pinned any more — an ordinary section with ordinary padding */
.process-stage { padding-block: var(--sect); }
.process-grid { display: grid; grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr); gap: 40px; align-items: stretch; }
.process .sect-head { margin-block-end: 34px; }
.steps { display: grid; gap: 0; counter-reset: step; position: relative; }
/* progress rail behind the number chips — fills as the act plays */
.rail-line {
  position: absolute; inset-block: 30px; inset-inline-start: 21px; inline-size: 2px; z-index: 0;
  background: var(--line); border-radius: 2px;
}
.rail-line i {
  position: absolute; inset: 0; transform: scaleY(0); transform-origin: top;
  background: linear-gradient(180deg, var(--blue), var(--violet));
  box-shadow: 0 0 14px rgb(30 96 253 / .65); border-radius: inherit;
}
html:not(.js) .rail-line { display: none; }
/* The act powers up through colour, the number chip, the nudge and the rail —
   not through opacity. The old .16/.45 ramp put step copy at 1.2:1 and 2.1:1,
   and with JS disabled nothing ever became live, so the whole act read as
   greyed-out placeholder text. Every state is legible now. */
.step {
  position: relative; padding-block: 22px; padding-inline: 66px 0; opacity: .85;
  transition: opacity .45s var(--out), transform .45s var(--out);
}
.step + .step { border-block-start: 1px solid var(--line); }
.step.is-past { opacity: .92; }
.step.is-live { opacity: 1; transform: translateX(8px); }
.step h3 { color: var(--muted); transition: color .45s var(--out); }
.step.is-past h3 { color: var(--fg); }
.step.is-live h3 { color: var(--fg-strong); }
.step.is-past .k {
  color: #9db4ff; background: #111c3a;
  box-shadow: inset 0 0 0 1.5px rgb(94 133 255 / .5);
}
.step .k {
  position: absolute; inset-inline-start: 0; inset-block-start: 20px; z-index: 1;
  inline-size: 44px; block-size: 44px; border-radius: 12px;
  display: grid; place-items: center;
  font-family: var(--f-mono); font-size: .8rem; color: var(--muted);
  box-shadow: inset 0 0 0 1px var(--line-strong);
  transition: color .35s, box-shadow .35s, background-color .35s, scale .35s var(--spring);
  /* opaque so the glowing progress rail passes behind, not through */
  background: #0a0c17;
}
/* live chip: solid fill + lift (the old quarter-turn belonged to the Rubik
   metaphor and read as a glitch mid-transition) */
.step.is-live .k { color: #fff; background: var(--blue); box-shadow: 0 8px 26px -8px rgb(30 96 253 / .8); scale: 1.08; }
.step .k i { font-style: normal; }
.step h3 { font-size: clamp(1.3rem, 2vw, 1.7rem); font-weight: 570; }
.step p { color: var(--muted); margin-block-start: 6px; max-width: 52ch; }
.process-cube { position: relative; min-block-size: min(52vw, 520px); }
/* Giant step counter — the act's clearest progress signal. It sticks near
   the top of the viewport while the steps scroll past, which keeps it well
   clear of the WebGL cube (which sits vertically centred). */
.process-count {
  position: sticky; inset-block-start: calc(var(--hdr) + 34px);
  display: flex; align-items: baseline; justify-content: flex-end; gap: 10px;
  font-family: var(--f-display); padding-inline-end: 4%;
}
.process-count b {
  display: inline-block; font-size: clamp(3rem, 5vw, 4.6rem); font-weight: 620;
  letter-spacing: -.02em; line-height: 1; color: var(--fg-strong);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 34px rgb(30 96 253 / .5), 0 0 90px rgb(4 5 10 / .9);
}
.process-count span {
  font-family: var(--f-mono); font-size: .9rem; letter-spacing: .22em; color: var(--muted);
}
.process-count.is-flip b { animation: count-flip .42s var(--out); }
@keyframes count-flip { from { opacity: 0; transform: translateY(38%); } }
html:not(.js) .process-count { display: none; }
.process-note {
  position: absolute; inset-block-end: 6%; inset-inline: 0; text-align: center;
  font-family: var(--f-mono); font-size: .72rem; letter-spacing: .26em; text-transform: uppercase; color: var(--muted);
}
/* Without WebGL the cube column is dead weight — let the steps breathe */
html.no-gl .process-cube { display: none; }
html.no-gl .process-grid { grid-template-columns: minmax(0, 1fr); max-width: 880px; }

/* --------------------------------------------------------------------------
   11 · WORK (the paper act)
   -------------------------------------------------------------------------- */
.work { background: var(--paper); color: #14151E; border-radius: clamp(24px, 4vw, 56px); position: relative; z-index: 2; }
/* The dark acts have film grain; without it the paper act reads as SaaS white
   rather than archival stock. Same feTurbulence, sepia-tinted and half as loud. */
.work::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none; border-radius: inherit;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.72' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23p)' opacity='.5'/%3E%3C/svg%3E");
  opacity: .04; mix-blend-mode: multiply; filter: sepia(1);
}
.work > * { position: relative; z-index: 1; }
.work .hud { color: #6B6455; }
.work .hud b { color: #B0331E; }
.work .hud::before { background: linear-gradient(90deg, #B0331E, transparent); }
.work h2, .work h3 { color: #0F1017; }
.work .lead { color: #57544B; }

.case-rows { display: grid; gap: clamp(18px, 2.4vw, 28px); }
.case {
  display: grid; grid-template-columns: minmax(0, 1.02fr) minmax(0, .98fr);
  gap: clamp(22px, 3.5vw, 56px); align-items: center;
  background: #FFFDF8; border-radius: var(--r-lg);
  box-shadow: 0 1px 0 rgb(20 21 30 / .06), 0 24px 60px -42px rgb(20 21 30 / .35);
  padding: clamp(20px, 2.6vw, 34px);
  transition: transform .45s var(--out), box-shadow .45s var(--out);
}
.case:hover { transform: translateY(-5px); box-shadow: 0 1px 0 rgb(20 21 30 / .06), 0 40px 90px -46px rgb(20 21 30 / .5); }
.case:nth-child(even) .case-media { order: 1; }
.case-media { overflow: clip; border-radius: var(--r-md); aspect-ratio: 16 / 10.6; position: relative; background: #E8E4D8; }
.case-media img { inline-size: 100%; block-size: 100%; object-fit: cover; transition: transform .8s var(--out), filter .8s; }
.case:hover .case-media img { transform: scale(1.045); }
.case-body { padding-block: 8px; }
/* Dossier spine: every case gets a file number on a ruler, the way a physical
   project folder would be labelled. Static text, logical properties, mirrors. */
.case-spine {
  display: flex; align-items: center; gap: 12px;
  font-family: var(--f-mono); font-size: .66rem; letter-spacing: .2em; text-transform: uppercase;
  color: #6B6455; margin-block-end: 12px;
}
.case-spine::after {
  content: ""; flex: 1; block-size: 7px;
  background-image: repeating-linear-gradient(90deg, rgb(20 21 30 / .28) 0 1px, transparent 1px 9px);
  background-position: 0 100%; background-repeat: repeat-x; background-size: 100% 7px;
  border-block-end: 1px solid rgb(20 21 30 / .18);
}
.case-body .hud { margin-block-end: 14px; }
.case h3 { font-size: clamp(1.5rem, 2.6vw, 2.2rem); font-weight: 580; letter-spacing: -.01em; }
.case p { color: #57544B; margin-block-start: 10px; max-width: 54ch; }
.case-stat { display: flex; gap: 30px; margin-block-start: 20px; }
.case-stat div b { display: block; font-family: var(--f-display); font-weight: 620; font-size: clamp(1.4rem, 2.4vw, 2rem); color: #0F1017; letter-spacing: -.01em; }
.case-stat div span { font-size: .84rem; color: #6B6455; }
.case .link-arrow { margin-block-start: 22px; color: #B0331E; }
.work-more { margin-block-start: 40px; display: flex; justify-content: center; }
.work-more .btn-ghost { color: #14151E; box-shadow: inset 0 0 0 1px rgb(20 21 30 / .22); background: transparent; backdrop-filter: none; }
.work-more .btn-ghost:hover { background: rgb(20 21 30 / .05); box-shadow: inset 0 0 0 1px rgb(20 21 30 / .4); }

/* --------------------------------------------------------------------------
   12 · STATS
   -------------------------------------------------------------------------- */
.stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; text-align: start; }
.stat { padding: 26px 0 0; border-block-start: 1px solid var(--line-strong); }
.stat b {
  display: block; font-family: var(--f-display); font-weight: 620; letter-spacing: -.02em;
  font-size: clamp(2.6rem, 5.4vw, 4.6rem); color: var(--fg-strong); line-height: 1;
  font-variant-numeric: tabular-nums;
}
.stat b .u { color: var(--blue-ink); }
.stat > span { display: block; margin-block-start: 10px; color: var(--muted); font-size: .95rem; }

/* --------------------------------------------------------------------------
   13 · TESTIMONIALS
   -------------------------------------------------------------------------- */
.proof-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 20px; margin-block-start: var(--sect); }
.proof-head .sect-head { margin-block-end: 0; }
.clutch {
  display: inline-flex; align-items: center; gap: 10px; padding: 12px 18px; border-radius: 999px;
  box-shadow: inset 0 0 0 1px var(--line-strong); font-size: .92rem; color: var(--fg);
  transition: box-shadow .3s, background-color .3s;
}
.clutch:hover { background: rgb(255 255 255 / .05); box-shadow: inset 0 0 0 1px rgb(255 255 255 / .32); }
.clutch b { font-family: var(--f-display); font-weight: 620; font-size: 1.06rem; font-variant-numeric: tabular-nums; color: var(--fg-strong); }

.t-rail-wrap { position: relative; margin-block-start: 48px; }
.t-rail {
  display: grid; grid-auto-flow: column; grid-auto-columns: min(430px, 82vw);
  gap: 18px; overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; padding-block-end: 18px;
  scrollbar-width: none;
  mask: linear-gradient(90deg, #000 92%, transparent);
  -webkit-mask: linear-gradient(90deg, #000 92%, transparent);
}
.t-rail::-webkit-scrollbar { display: none; }
.t-card {
  scroll-snap-align: start;
  display: flex; flex-direction: column; gap: 22px; justify-content: space-between;
  border-radius: var(--r-lg); padding: 30px;
  background: rgb(255 255 255 / .025); box-shadow: inset 0 0 0 1px var(--line);
}
.t-card blockquote { margin: 0; font-size: 1.08rem; line-height: 1.6; color: var(--fg); font-weight: 450; }
.t-card blockquote::before { content: "“"; display: block; font-family: var(--f-display); font-size: 3rem; line-height: .6; color: var(--blue); margin-block-end: 14px; }
.t-card.mcd blockquote::before { color: var(--yellow); }
.t-who { display: flex; align-items: center; gap: 13px; }
.t-who img { inline-size: 44px; block-size: 44px; border-radius: 50%; object-fit: cover; }
/* the McDonald's card carries a logo, not a portrait */
.t-card.mcd .t-who img { border-radius: 10px; object-fit: contain; background: rgb(255 255 255 / .06); padding: 8px; }
.t-who .n { font-weight: 620; color: var(--fg-strong); font-size: .96rem; }
.t-who .r { font-size: .82rem; color: var(--muted); }
.t-who a.li { margin-inline-start: auto; color: var(--muted); transition: color .25s; }
.t-who a.li:hover { color: #fff; }
.t-nav { display: flex; gap: 10px; justify-content: flex-end; margin-block-start: 10px; }
.t-btn {
  inline-size: 46px; block-size: 46px; border-radius: 50%;
  box-shadow: inset 0 0 0 1px var(--line-strong); color: var(--fg);
  display: grid; place-items: center; transition: background-color .25s, box-shadow .25s;
}
.t-btn:hover { background: rgb(255 255 255 / .07); }
.t-btn:disabled { opacity: .3; cursor: default; }

/* --------------------------------------------------------------------------
   14 · GUARANTEES
   -------------------------------------------------------------------------- */
.guar { position: relative; }
/* A ledger, not an icon grid: four numbered terms, mono numerals, hairlines.
   The other four risk-removers live in the FAQ, where they are read. */
.ledger { display: grid; grid-template-columns: 1fr 1fr; border-block-start: 1px solid var(--line-strong); }
.led {
  display: grid; grid-template-columns: auto 1fr; gap: 20px;
  padding-block: 26px 30px; padding-inline-end: clamp(16px, 3vw, 44px);
  border-block-end: 1px solid var(--line);
}
.led:nth-child(2n) { border-inline-start: 1px solid var(--line); padding-inline-start: clamp(24px, 4vw, 56px); }
.led-n {
  font-family: var(--f-mono); font-size: var(--t-mono); letter-spacing: .22em;
  color: var(--blue-ink); font-variant-numeric: tabular-nums; padding-block-start: 5px;
}
.led h3 { font-family: var(--f-body); font-size: 1.06rem; font-weight: 590; color: var(--fg-strong); }
.led p { font-size: .9rem; color: var(--muted); margin-block-start: 7px; line-height: 1.55; max-width: 48ch; }

/* --------------------------------------------------------------------------
   15 · PLANNER (lead magnet)
   -------------------------------------------------------------------------- */
.planner-shell {
  border-radius: var(--r-xl); overflow: clip; position: relative;
  background:
    radial-gradient(60% 90% at 85% -10%, rgb(30 96 253 / .16), transparent 60%),
    radial-gradient(50% 70% at 0% 110%, rgb(255 0 84 / .1), transparent 65%),
    var(--void-900);
  box-shadow: inset 0 0 0 1px var(--line-strong);
  padding: clamp(28px, 4.5vw, 60px);
}
.planner-grid { display: grid; grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr); gap: clamp(30px, 4.5vw, 70px); }
.planner-shell h2 { font-size: clamp(1.9rem, 3.2vw, 2.8rem); margin-block-start: 16px; }
.planner-shell .lead { margin-block-start: 14px; }
.planner-q { margin-block-start: 34px; }
.planner-q .q {
  font-family: var(--f-display); font-weight: 570; font-size: 1.3rem; color: var(--fg-strong);
  margin-block-end: 16px; display: flex; gap: 12px; align-items: baseline;
}
.planner-q .q .qn { font-family: var(--f-mono); font-size: .74rem; color: var(--blue-ink); letter-spacing: .2em; }
.opts { display: flex; flex-wrap: wrap; gap: 10px; }
.opt { position: relative; }
.opt input { position: absolute; opacity: 0; inset: 0; cursor: pointer; }
.opt label, .opt .lbl {
  display: inline-flex; padding: 11px 18px; border-radius: 999px; cursor: pointer;
  font-size: .95rem; font-weight: 500; color: var(--muted);
  box-shadow: inset 0 0 0 1px var(--line); background: rgb(255 255 255 / .02);
  transition: color .25s, box-shadow .25s, background-color .25s, transform .25s var(--spring);
}
.opt:hover .lbl { color: var(--fg); box-shadow: inset 0 0 0 1px var(--line-strong); }
.opt input:checked + .lbl {
  color: #fff; background: rgb(30 96 253 / .18);
  box-shadow: inset 0 0 0 1.5px var(--blue); transform: scale(1.03);
}
.opt input:focus-visible + .lbl { outline: 2px solid var(--blue); outline-offset: 2px; }

.plan-out { position: relative; border-radius: var(--r-lg); background: rgb(255 255 255 / .03); box-shadow: inset 0 0 0 1px var(--line-strong); padding: clamp(24px, 3vw, 40px); display: grid; align-content: start; gap: 20px; min-block-size: 420px; }
.plan-out .hud { margin-block-end: -6px; }
.plan-name { font-family: var(--f-display); font-weight: 590; font-size: clamp(1.7rem, 2.6vw, 2.4rem); color: var(--fg-strong); }
.plan-tl { display: grid; gap: 8px; }
.plan-tl .bar { position: relative; block-size: 8px; border-radius: 99px; background: rgb(255 255 255 / .07); overflow: clip; }
.plan-tl .bar i {
  position: absolute; inset-block: 0; inset-inline-start: 0; inline-size: var(--w, 30%);
  border-radius: inherit; background: linear-gradient(90deg, var(--blue), var(--violet));
  transition: inline-size .8s var(--out);
}
.plan-tl .lab { display: flex; justify-content: space-between; font-family: var(--f-mono); font-size: .7rem; letter-spacing: .12em; color: var(--muted); text-transform: uppercase; }
.plan-team { display: flex; flex-wrap: wrap; gap: 8px; }
.plan-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 10px; }
.plan-list li { display: flex; gap: 10px; font-size: .95rem; color: var(--fg); }
.plan-list li::before { content: "✓"; color: var(--yellow); flex: none; font-weight: 700; }
.plan-desc { color: var(--muted); font-size: .98rem; }
.plan-cta { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin-block-start: 6px; }
.plan-foot { font-size: .8rem; color: var(--muted); }
.plan-foot b { color: var(--yellow); font-weight: 560; }

/* Tertiary: WhatsApp the plan. Mono/neutral — the dock's rule applies here. */
.plan-wa, .plan-tert {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--f-mono); font-size: .74rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted); padding: 10px 4px; transition: color .25s;
}
.plan-wa svg { flex: none; }
.plan-wa:hover, .plan-tert:hover { color: var(--fg-strong); }

/* Micro-conversion: mail a copy of the plan. The plan itself is never gated. */
.plan-mail { display: grid; gap: 12px; margin-block-start: -6px; }
.plan-mail-row { display: grid; grid-template-columns: 1fr 1fr auto; gap: 12px; align-items: start; }
.plan-mail .field input { padding: 13px 14px 12px; font-size: .95rem; }
.plan-mail .field label { inset-block-start: 13px; font-size: .95rem; }
.plan-mail .field:has(input:focus) label,
.plan-mail .field:has(input:not(:placeholder-shown)) label { background: var(--void-800); }
.plan-mail-note { font-size: .78rem; color: var(--muted); }
.plan-mail-state { font-size: .9rem; color: var(--yellow); display: none; }
.plan-mail.is-sent .plan-mail-row, .plan-mail.is-sent .plan-mail-note { display: none; }
.plan-mail.is-sent .plan-mail-state, .plan-mail.is-error .plan-mail-state { display: block; }
.plan-mail.is-error .plan-mail-state { color: var(--pink); }
.plan-mail.is-sending .btn { opacity: .6; pointer-events: none; }

/* Honeypot — off-screen but not display:none, which some bots skip */
.hp { position: absolute; opacity: 0; pointer-events: none; }

/* --------------------------------------------------------------------------
   16 · STUDIO / ABOUT STRIP
   -------------------------------------------------------------------------- */
.studio-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(30px, 5vw, 80px); align-items: start; }
.studio-grid h2 { font-size: var(--t-h2); font-weight: 570; margin-block-start: 16px; }
.studio-grid .lead { margin-block-start: 18px; }
.studio-grid .lead + .lead { margin-block-start: 14px; }
.studio-note { margin-block-start: 22px; color: var(--muted); font-size: .95rem; }
.city-list { display: grid; gap: 0; }
.city { display: grid; grid-template-columns: 1fr auto; align-items: center; padding-block: 20px; border-block-end: 1px solid var(--line); }
.city:first-child { border-block-start: 1px solid var(--line); }
.city .nm { font-family: var(--f-display); font-weight: 570; font-size: clamp(1.4rem, 2.4vw, 2rem); color: var(--fg-strong); display: flex; align-items: baseline; gap: 14px; }
.city .ad { font-size: .86rem; color: var(--muted); font-weight: 420; }
/* Real coordinates beside the live clocks — the studio list reads as an
   instrument panel rather than an address block. */
.city .nm { flex-wrap: wrap; }
.city .coord { flex-basis: 100%; font-family: var(--f-mono); font-size: .68rem; letter-spacing: .12em; color: var(--muted); margin-block-start: 4px; font-variant-numeric: tabular-nums; }
.city .tm { font-family: var(--f-mono); font-size: .95rem; color: var(--blue-ink); font-variant-numeric: tabular-nums; }
/* "next" city reads quieter than the live ones — via colour, not opacity,
   which used to drag its clock to 1.92:1 and its tag to 4.42:1 */
.city.soon .nm { color: var(--muted); }
.city.soon .tm { color: var(--muted); }
.city .soon-tag { font-family: var(--f-mono); font-size: .66rem; letter-spacing: .2em; color: var(--yellow); text-transform: uppercase; }

/* --------------------------------------------------------------------------
   17 · FAQ
   -------------------------------------------------------------------------- */
.faq-list { max-width: 900px; }
.faq-list details { border-block-end: 1px solid var(--line); }
.faq-list details:first-child { border-block-start: 1px solid var(--line); }
.faq-list summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding-block: 24px; font-family: var(--f-display); font-weight: 560; font-size: clamp(1.1rem, 1.8vw, 1.45rem); color: var(--fg-strong);
  transition: color .3s;
}
.faq-list summary::-webkit-details-marker { display: none; }
.faq-list summary:hover { color: var(--blue-ink); }
.faq-list summary .pm { position: relative; inline-size: 34px; block-size: 34px; flex: none; border-radius: 50%; box-shadow: inset 0 0 0 1px var(--line-strong); }
.faq-list summary .pm::before, .faq-list summary .pm::after {
  content: ""; position: absolute; inset-block-start: 50%; inset-inline-start: 50%;
  inline-size: 12px; block-size: 1.6px; background: currentColor; translate: -50% -50%;
  transition: rotate .4s var(--snap);
}
.faq-list summary .pm::after { rotate: 90deg; }
.faq-list details[open] summary .pm::after { rotate: 0deg; }
.faq-list details[open] summary { color: var(--blue-ink); }
.faq-a { padding-block: 0 26px; color: var(--muted); max-width: 66ch; }
.faq-a a { color: var(--fg); text-decoration: underline; text-underline-offset: 3px; }
@supports (interpolate-size: allow-keywords) {
  .faq-list details::details-content {
    block-size: 0; overflow: clip; interpolate-size: allow-keywords;
    transition: block-size .5s var(--out), content-visibility .5s allow-discrete;
  }
  .faq-list details[open]::details-content { block-size: auto; }
}

/* The full stop that answers the cube's heartbeat (one.js listens for
   rbk:beat). Inherits its own colour so it is invisible until it pulses. */
.beat { color: var(--yellow); }
@media (prefers-reduced-motion: no-preference) {
  .beat.is-beat { animation: beat-echo .62s var(--out); }
  @keyframes beat-echo {
    0%   { text-shadow: none; }
    28%  { text-shadow: 0 0 20px rgb(248 206 58 / .85), 0 0 46px rgb(248 206 58 / .35); }
    100% { text-shadow: none; }
  }
}

/* --------------------------------------------------------------------------
   18 · CONTACT
   -------------------------------------------------------------------------- */
.contact { position: relative; }
.contact-grid { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: clamp(30px, 5vw, 80px); align-items: start; }

.cform { display: grid; gap: 18px; }
.field { position: relative; }
.field input, .field select, .field textarea {
  inline-size: 100%; padding: 17px 16px 15px; border-radius: var(--r-sm);
  background: rgb(255 255 255 / .03); color: var(--fg-strong);
  border: 1px solid var(--line); font: inherit; font-size: 1rem;
  transition: border-color .3s, background-color .3s, box-shadow .3s;
}
.field textarea { min-block-size: 130px; resize: vertical; field-sizing: content; max-block-size: 320px; }
.field input:hover, .field textarea:hover, .field select:hover { border-color: var(--line-strong); }
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none; border-color: var(--blue); background: rgb(30 96 253 / .05);
  box-shadow: 0 0 0 3px rgb(30 96 253 / .18);
}
/* Labels are the field's only visible name — they read as text, so they take a
   text-grade colour, resting and floated alike. */
.field label {
  position: absolute; inset-inline-start: 16px; inset-block-start: 16px; pointer-events: none;
  color: var(--muted); transition: all .25s var(--out); font-size: 1rem; background: transparent;
}
.field:has(input:focus) label, .field:has(input:not(:placeholder-shown)) label,
.field:has(textarea:focus) label, .field:has(textarea:not(:placeholder-shown)) label {
  inset-block-start: -8px; font-size: .72rem; color: var(--blue-ink);
  background: var(--void-950); padding-inline: 6px; border-radius: 4px; font-family: var(--f-mono); letter-spacing: .08em;
}
.cform .row { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.cform-foot { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.cform-note { font-size: .84rem; color: var(--muted); }
.cform-note b { color: var(--yellow); font-weight: 560; }
.form-state { font-size: .95rem; display: none; align-items: center; gap: 10px; }
.form-state a { text-decoration: underline; text-underline-offset: 3px; }
.cform.is-success .form-state.ok { display: flex; color: var(--yellow); }
.cform.is-error .form-state.err { display: flex; color: var(--pink); }
.cform.is-sending .btn-primary { opacity: .6; pointer-events: none; }

.book-card {
  border-radius: var(--r-lg); padding: clamp(26px, 3vw, 40px);
  background: linear-gradient(150deg, rgb(30 96 253 / .14), rgb(255 255 255 / .02) 58%);
  box-shadow: inset 0 0 0 1px rgb(94 133 255 / .28);
  display: grid; gap: 16px;
}
.book-card h3 { font-size: 1.5rem; font-weight: 580; }
.book-card p { color: var(--muted); }
.alt-contact { display: grid; gap: 12px; margin-block-start: 26px; }
.alt-line { display: flex; align-items: center; gap: 12px; font-size: .95rem; color: var(--muted); }
.alt-line a { color: var(--fg); font-weight: 540; transition: color .25s; }
.alt-line a:hover { color: var(--blue-ink); }
.alt-line .alt-meta { color: var(--muted); }
.alt-line svg { flex: none; color: var(--faint); }

/* --------------------------------------------------------------------------
   19 · FOOTER
   -------------------------------------------------------------------------- */
/* The footer as an engineering title block: hairline grid, numbered sections,
   the drawing's own metadata along the bottom rule. */
.foot { border-block-start: 1px solid var(--line); padding-block: 56px 40px; position: relative; z-index: 1; background: var(--void-950); }
.foot-grid { display: grid; grid-template-columns: 1.3fr 1fr 1fr 1fr; gap: 34px; }
/* The title block's hairline grid only makes sense while the four columns sit
   on one row; below that the columns wrap and a rule would land mid-row. */
@media (min-width: 1101px) {
  .foot-grid { gap: 0; }
  .foot-grid > * + * { border-inline-start: 1px solid var(--line); padding-inline-start: clamp(18px, 2.6vw, 34px); }
  .foot-grid > *:not(:last-child) { padding-inline-end: clamp(18px, 2.6vw, 34px); }
}
/* the section marker is a numeral, so it takes the numeral colour the rest of
   the page uses (--faint would be 3.14:1 — decoration only) */
.foot-h .sec { color: var(--blue-ink); margin-inline-end: 8px; }
.foot-brand img { block-size: 32px; inline-size: auto; }
.foot-brand p { color: var(--muted); font-size: .92rem; max-width: 34ch; margin-block-start: 16px; }
/* labelled with <p class="foot-h">, not a heading: they are column labels, and
   an <h5> after the page's h2s is a heading-order violation */
.foot .foot-h { font-family: var(--f-mono); font-weight: 400; font-size: .72rem; letter-spacing: .22em; text-transform: uppercase; color: var(--muted); margin: 0 0 16px; }
.foot-col { display: grid; gap: 10px; align-content: start; justify-items: start; }
.foot-col a { color: var(--muted); font-size: .95rem; transition: color .25s; }
.foot-col a:hover { color: var(--fg-strong); }
.foot-soon { color: var(--muted); font-size: .95rem; }
.foot-bottom { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px; margin-block-start: 48px; padding-block-start: 24px; border-block-start: 1px solid var(--line); font-size: .84rem; color: var(--muted); }
.socials { display: flex; gap: 8px; }
.socials a { inline-size: 38px; block-size: 38px; display: grid; place-items: center; border-radius: 50%; color: var(--muted); box-shadow: inset 0 0 0 1px var(--line); transition: color .25s, box-shadow .25s, transform .25s var(--spring); }
.socials a:hover { color: #fff; box-shadow: inset 0 0 0 1px var(--line-strong); transform: translateY(-2px); }
.cookie-btn { color: var(--muted); text-decoration: underline; text-underline-offset: 3px; }
.cookie-btn:hover { color: var(--fg); }

/* --------------------------------------------------------------------------
   20 · FLOATING DOCK
   -------------------------------------------------------------------------- */
.dock {
  /* inline-end offset leaves room for the HubSpot chat launcher (via GTM) */
  position: fixed; inset-block-end: 22px; inset-inline-end: 92px; z-index: 110;
  display: flex; gap: 10px; align-items: center;
  translate: 0 90px; opacity: 0; transition: translate .5s var(--spring), opacity .4s;
}
.dock.is-in { translate: 0 0; opacity: 1; }
.dock .btn-primary { box-shadow: 0 16px 44px -12px rgb(30 96 253 / .9); }
/* WhatsApp control: same function, inside the rationed palette (the brand
   green was the one off-system colour on the page) */
.dock-wa {
  inline-size: 52px; block-size: 52px; border-radius: 50%; display: grid; place-items: center;
  background: rgb(255 255 255 / .06); color: var(--fg); backdrop-filter: blur(10px);
  box-shadow: inset 0 0 0 1px var(--line-strong);
  transition: transform .3s var(--spring), background-color .3s, box-shadow .3s;
}
.dock-wa:hover { transform: translateY(-3px); background: rgb(255 255 255 / .1); box-shadow: inset 0 0 0 1px rgb(255 255 255 / .3); }
/* The consent banner owns the bottom of the viewport while it is up, at both
   breakpoints: banner inset + its measured height (set by consent.js) + gap. */
html.consent-open .dock { inset-block-end: calc(16px + var(--consent-h, 96px) + 18px); }

/* --------------------------------------------------------------------------
   21 · CONSENT BANNER (markup generated by consent.js)
   -------------------------------------------------------------------------- */
.consent-banner {
  position: fixed; inset-inline: 16px; inset-block-end: 16px; z-index: 140;
  margin-inline: auto; max-inline-size: 640px;
  display: flex; flex-wrap: wrap; gap: 14px; align-items: center; justify-content: space-between;
  background: rgb(13 16 30 / .92); -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
  border-radius: var(--r-md); box-shadow: inset 0 0 0 1px var(--line-strong), 0 30px 70px -30px rgb(0 0 0 / .8);
  padding: 18px 20px;
  translate: 0 20px; opacity: 0; transition: translate .4s var(--out), opacity .4s;
}
.consent-banner.is-in { translate: 0 0; opacity: 1; }
.consent-text { font-size: .88rem; color: var(--muted); max-width: 46ch; }
.consent-actions { display: flex; gap: 10px; }
.consent-btn { padding: 10px 20px; font-size: .9rem; }

/* --------------------------------------------------------------------------
   22 · SECTION INDEX RAIL (desktop)
   -------------------------------------------------------------------------- */
.rail { position: fixed; inset-inline-end: 20px; inset-block-start: 50%; translate: 0 -50%; z-index: 100; display: grid; gap: 12px; }
.rail a { position: relative; inline-size: 10px; block-size: 10px; display: grid; place-items: center; }
.rail a i { inline-size: 5px; block-size: 5px; border-radius: 50%; background: var(--faint); transition: background-color .3s, transform .3s var(--spring); }
.rail a:hover i, .rail a.is-live i { background: var(--fg-strong); transform: scale(1.7); }
.rail a.is-live i { background: var(--blue); box-shadow: 0 0 10px rgb(30 96 253 / .9); }
.rail a span {
  position: absolute; inset-inline-end: 22px; inset-block-start: 50%; translate: 0 -50%;
  font-family: var(--f-mono); font-size: .66rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--fg); background: rgb(13 16 30 / .9); padding: 6px 10px; border-radius: 6px;
  white-space: nowrap; opacity: 0; pointer-events: none; transition: opacity .25s;
  box-shadow: inset 0 0 0 1px var(--line);
}
.rail a:hover span { opacity: 1; }

/* --------------------------------------------------------------------------
   23 · REVEALS — pure CSS transitions, toggled by an IntersectionObserver.
   The hidden states are gated behind html.js, which one.js adds as its FIRST
   statement. If the script fails to load, parse, or run, the class is never
   added and every element is simply visible — content can never get stuck
   hidden the way a JS "from" animation can.
   -------------------------------------------------------------------------- */
html.js [data-rv] {
  opacity: 0; transform: translateY(16px);
  transition: opacity .5s var(--out), transform .5s var(--out);
}
html.js [data-rv].is-in { opacity: 1; transform: none; }

/* Hero intro — same mechanism, staggered with transition delays.
   The hidden state is written as :not(.hero-in) rather than as a pair of
   competing rules. The pair looked equivalent but was not: `html.js .hero h1
   .ln` carries one more element selector than `.hero-in .hero h1 .ln`, so it
   won the cascade and the intro never actually landed — the badge stayed at
   opacity 0 and the headline stayed translated out of its clip mask for every
   visitor with JS and normal motion settings. Keep the negation. */
html.js .hero-badge, html.js .hero .lead,
html.js .hero-cta, html.js .hero-tert {
  transition: opacity .6s var(--out), transform .6s var(--out);
}
html.js body:not(.hero-in) .hero-badge, html.js body:not(.hero-in) .hero .lead,
html.js body:not(.hero-in) .hero-cta, html.js body:not(.hero-in) .hero-tert {
  opacity: 0; transform: translateY(14px);
}
html.js .hero h1 .ln { transition: transform .9s var(--out); }
html.js body:not(.hero-in) .hero h1 .ln { transform: translateY(108%); }
.hero-in .hero h1 .line:nth-child(2) .ln { transition-delay: .09s; }
.hero-in .hero h1 .line:nth-child(3) .ln { transition-delay: .18s; }
.hero-in .hero .lead   { transition-delay: .30s; }
.hero-in .hero-cta     { transition-delay: .40s; }
.hero-in .hero-tert    { transition-delay: .50s; }

/* --------------------------------------------------------------------------
   24 · RESPONSIVE
   -------------------------------------------------------------------------- */
@media (max-width: 1100px) {
  .rail { display: none; }
  .hero-grid { grid-template-columns: 1fr; }
  .hero-stage { min-block-size: 0; position: absolute; inset: 0; z-index: -1; opacity: .5; }
  .stats { grid-template-columns: repeat(3, 1fr); gap: 34px 20px; }
  .planner-grid, .process-grid, .sprint-grid, .contact-grid, .studio-grid { grid-template-columns: 1fr; }
  .process-cube { display: none; }
  .svc-grid { grid-template-columns: 1fr; }
  /* the path turns vertical: dashed hairline per row, node in the gutter */
  .path { grid-template-columns: 1fr; gap: 0; margin-block-start: 44px; padding-block-start: 0; }
  .path::before { display: none; }
  .tier { padding-block: 26px 30px; padding-inline-start: 26px; border-block-start: 1px dashed rgb(255 255 255 / .1); }
  .tier .node { inset-block-start: 33px; }
  .foot-grid { grid-template-columns: 1fr 1fr; }
}
/* C2: park the fallback cube out of the copy's way on narrow screens — it used
   to sit centred behind the hero lead at 390px. */
@media (max-width: 900px) {
  .hero-stage { opacity: .3; }
  .gl-fallback { place-items: end center; padding-block-end: 4%; }
  .gl-fallback svg { inline-size: min(34%, 132px); filter: drop-shadow(0 16px 34px rgb(30 96 253 / .3)); }
}
@media (max-width: 860px) {
  .nav { display: none; }
  .burger { display: block; }
  .hdr .btn-book { display: none; }
  .case, .case:nth-child(even) { grid-template-columns: 1fr; }
  .case:nth-child(even) .case-media { order: 0; }
  .dock { inset-inline: 14px; inset-block-end: 14px; justify-content: stretch; }
  .dock .btn-primary { flex: 1; justify-content: center; }
  .cform .row { grid-template-columns: 1fr; }
  .work { border-radius: clamp(18px, 3vw, 28px); }
  .ledger { grid-template-columns: 1fr; }
  .led { padding-inline-end: 0; }
  .led:nth-child(2n) { border-inline-start: 0; padding-inline-start: 0; }
  .stats { grid-template-columns: 1fr; gap: 26px; }
  .readout-in { grid-template-columns: 1fr; gap: 22px; }
  .ro { padding-inline-end: 0; }
  .ro + .ro { border-inline-start: 0; padding-inline-start: 0; border-block-start: 1px solid var(--line); padding-block-start: 20px; }
  .plan-mail-row { grid-template-columns: 1fr; }
  /* the sprint HUD is the one label long enough to break at card width: the
     nowrap <b> takes the whole line and the descriptive half stacks beside it.
     Let the line break instead. */
  .sprint .hud { flex-wrap: wrap; }
  .sprint .hud b { white-space: normal; }
}

/* --------------------------------------------------------------------------
   25 · ARABIC / RTL
   Layout mirrors on its own — this file is authored in logical properties. What
   is left is what logical properties cannot express: the type pairing, the
   direction of glyphs and gradients, and the sign of a few nudges.
   -------------------------------------------------------------------------- */
[dir="rtl"] {
  /* Tajawal first so Arabic never waits on a face that cannot render it; the
     Latin faces stay in the stack for Latin runs. Mono stays Latin: Arabic has
     no uppercase and letter-spacing breaks its joining. */
  --f-display: "Tajawal", "Tajawal Fallback", "Clash Display", system-ui, sans-serif;
  --f-body: "Tajawal", "Tajawal Fallback", "Satoshi", system-ui, sans-serif;
}

/* Type retune. Arabic ascenders and tashkeel need vertical room, and the hero
   lines clip their overflow, so the display line-height goes 0.98 → 1.3. */
[dir="rtl"] h1, [dir="rtl"] h2, [dir="rtl"] h3, [dir="rtl"] h4 { line-height: 1.3; letter-spacing: 0; }
[dir="rtl"] body { line-height: 1.8; }
[dir="rtl"] .hero h1 { line-height: 1.3; letter-spacing: 0; font-weight: 800; }
[dir="rtl"] .hero h1 .line { padding-block-end: .2em; margin-block-end: -.2em; }
[dir="rtl"] .sect-head h2, [dir="rtl"] .sprint h2, [dir="rtl"] .planner-shell h2,
[dir="rtl"] .studio-grid h2 { font-weight: 700; }
[dir="rtl"] .plan-name, [dir="rtl"] .city .nm, [dir="rtl"] .case h3,
[dir="rtl"] .chip b, [dir="rtl"] .ro-v { font-weight: 700; }
[dir="rtl"] .lead, [dir="rtl"] .step p, [dir="rtl"] .svc p, [dir="rtl"] .led p { letter-spacing: 0; }

/* HUD: the structural label stays Latin mono (SEC 01 · MODE / 01), the
   descriptive half is Arabic, so it drops the tracking and takes Tajawal. */
[dir="rtl"] .hud { letter-spacing: 0; font-family: var(--f-body); text-transform: none; }
[dir="rtl"] .hud b { font-family: var(--f-mono); letter-spacing: .22em; text-transform: uppercase; }
[dir="rtl"] .hud::before { background: linear-gradient(270deg, var(--blue), transparent); }
[dir="rtl"] .work .hud::before { background: linear-gradient(270deg, #B0331E, transparent); }
/* Latin digits and mono in instrument contexts, per the AR-tree convention */
[dir="rtl"] .ro-v, [dir="rtl"] .stat b, [dir="rtl"] .led-n, [dir="rtl"] .city .tm,
[dir="rtl"] .process-count b, [dir="rtl"] .plan-tl .lab, [dir="rtl"] .day .d,
[dir="rtl"] .svc .no, [dir="rtl"] .sheet a.big small { font-variant-numeric: tabular-nums; letter-spacing: 0; }
/* Latin-only instrument labels keep JetBrains mono… */
[dir="rtl"] .led-n, [dir="rtl"] .city .tm, [dir="rtl"] .svc .no,
[dir="rtl"] .sheet a.big small, [dir="rtl"] .process-count span { font-family: var(--f-mono); }
/* …while the descriptive labels are Arabic sentences, so they take Tajawal: in
   mono the Latin word-spaces are wider than the Arabic glyphs and the phrase
   falls apart. */
[dir="rtl"] .process-note, [dir="rtl"] .ro-k, [dir="rtl"] .hero-note,
[dir="rtl"] .plan-tl .lab, [dir="rtl"] .day .d { font-family: var(--f-body); }
/* …but any of those that carry Arabic words lose the tracking, which would
   otherwise break the joining. Latin-only labels (01-04, MODE / 01, clocks,
   / 04) keep theirs. */
[dir="rtl"] .ro-k, [dir="rtl"] .hero-note, [dir="rtl"] .process-note,
[dir="rtl"] .plan-tl .lab, [dir="rtl"] .day .d, [dir="rtl"] .tag,
[dir="rtl"] .city .soon-tag, [dir="rtl"] .opt .lbl,
[dir="rtl"] .foot .foot-h, [dir="rtl"] .rail a span,
[dir="rtl"] .hero-badge, [dir="rtl"] .plan-wa, [dir="rtl"] .plan-tert,
[dir="rtl"] .case-stat div b, [dir="rtl"] .stat b { letter-spacing: 0; text-transform: none; }

/* Arabic at line-height 1.3 needs the extra room somewhere: the display size
   steps down a notch so the hero still fits one screen. */
[dir="rtl"] .hero h1 { font-size: clamp(2.3rem, 5.2vw, 4.9rem); }
[dir="rtl"] .hero-badge { font-family: var(--f-body); font-size: .82rem; }

/* Directional glyphs and origins */
[dir="rtl"] .arr { display: inline-block; transform: scaleX(-1); }
[dir="rtl"] .btn:hover .arr, [dir="rtl"] .btn:focus-visible .arr,
[dir="rtl"] .link-arrow:hover .arr, [dir="rtl"] a.ro:hover .arr { transform: scaleX(-1) translateX(5px); }
[dir="rtl"] .progress { transform-origin: 100% 50%; }
[dir="rtl"] .nav a::after, [dir="rtl"] .foot-col a::after { transform-origin: 100% 50%; }
/* the data pulse travels with the reading direction */
[dir="rtl"] .nav a:hover::after, [dir="rtl"] .foot-col a:hover::after { animation-direction: reverse; }
[dir="rtl"] .step.is-live { transform: translateX(-8px); }
[dir="rtl"] .marquee-track { animation-direction: reverse; }
[dir="rtl"] .t-rail { mask: linear-gradient(270deg, #000 92%, transparent); -webkit-mask: linear-gradient(270deg, #000 92%, transparent); }
[dir="rtl"] .plan-tl .bar i { background: linear-gradient(270deg, var(--blue), var(--violet)); }
[dir="rtl"] .rail-line i { background: linear-gradient(180deg, var(--blue), var(--violet)); }
[dir="rtl"] .tier li::before { content: "←"; }

/* --------------------------------------------------------------------------
   26 · REDUCED MOTION — hard gate
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .001s !important; animation-iteration-count: 1 !important; transition-duration: .15s !important; }
  .grain { animation: none; }
  html.js [data-rv], html.js body:not(.hero-in) .hero-badge, html.js body:not(.hero-in) .hero .lead,
  html.js body:not(.hero-in) .hero-cta, html.js body:not(.hero-in) .hero-tert { opacity: 1 !important; transform: none !important; }
  html.js body:not(.hero-in) .hero h1 .ln { transform: none !important; }
}

/* Print: just the content */
@media print {
  .stage, .aurora, .grain, .dock, .rail, .progress, .hdr { display: none !important; }
  body { background: #fff; color: #000; }
}

/* --------------------------------------------------------------------------
   26 · WORK CARDS CARRY THE DOSSIER SCENE (Wave B)
   The case cards swapped a screenshot for the hand-authored SVG scene, so the
   frame keeps its 16/10.6 box but takes the void field behind the drawing.
   direction: ltr because a scene is a diagram with Latin HUD labels — it must
   not mirror under dir="rtl" the way prose does.
   -------------------------------------------------------------------------- */
/* 16/9 rather than the photo frame's 16/10.6: six files now sit where five
   did, and the shallower frame keeps the section within a tenth of its
   previous height. The scene letterboxes into its own field, so the change
   is invisible. */
.case-media.scene-frame { background: #06080F; aspect-ratio: 16 / 9; }
.case-media.scene-frame img { inline-size: 100%; block-size: 100%; object-fit: contain; }
