/* ==========================================================================
   ZERO FOUR FIVE — FLIGHT DECK 045
   Aesthetic family: glass-cockpit instrumentation (avionics primary flight
   display). Black glass ground, luminous horizon, synthetic-vision terrain,
   annunciator colour law. 045 is a compass bearing — north-east — so the
   brand name is the heading and the site is the instrument reading it.

   Colour law (borrowed from real instruments, matched to the brand board):
     cyan   #00E5FF  live data, selected values, normal/online
     blue   #0066FF  navigation, structure, sky, terrain
     coral  #FF6A4D  caution, attention — the single signal colour
     steel  #A6B2C3  labels and secondary text
     white  #FFFFFF  primary readouts
   No green. The brand has no green, so "normal" is cyan.
   ========================================================================== */

/* --- 1. Tokens ----------------------------------------------------------- */

:root {
  /* Ground and panel — straight off the brand palette card.
     Deep Navy is the page ground (swatch 1), Midnight the raised panel
     (swatch 2). Wells go below navy so depth still reads on a dark page. */
  /* Sampled off the brand board itself, which sits on near-black with a blue
     cast (#00030C at the edges, #010413 behind the wordmark) — not on Deep
     Navy. Deep Navy is a palette swatch and belongs to the raised panels and
     the glow near the horizon, which is exactly where the board puts it.
     Keeping the ground this dark is what lets the blue terrain carry. */
  --ground:     #02040C;   /* page ground — matches the board's own field */
  --panel:      #121B2E;   /* MIDNIGHT — raised instrument bezels */
  --well:       #010207;   /* sunk sections, one step under the ground */
  --black:      #000104;   /* deepest — footer, vignette, bezel shadow */
  --navy:       #0A0F1C;   /* DEEP NAVY — kept for washes and panel tints */
  --midnight:   #121B2E;
  --deck-rgb:   2, 4, 12;  /* glareshield tint, tracks the ground */

  /* Signal — swatches 3 to 6, unchanged */
  --blue:       #0066FF;   /* ELECTRIC BLUE */
  --cyan:       #00E5FF;   /* CYAN */
  --coral:      #FF6A4D;   /* CORAL */
  --steel:      #A6B2C3;   /* STEEL */
  --white:      #FFFFFF;

  /* Ink. --ink-faint carries words, so it is held at 4.5:1 on the navy ground
     (#6E7C90 = 4.52:1). Anything dimmer than that is ornament only and uses
     --ink-ornament or --ink-ghost, which never carry text a reader needs. */
  --ink:          #FFFFFF;   /* 19.4:1 */
  --ink-mid:      #C9D3E0;   /* 12.1:1 */
  --ink-muted:    #8492A6;   /*  6.4:1 */
  --ink-faint:    #717F95;   /*  4.7:1 — floor for text, clear of the AA line */
  --ink-ornament: #46536A;   /* rails, ticks — decorative, aria-hidden */
  --ink-ghost:    #232D3D;   /* unlit segments and dots */

  /* Rules */
  --rule:       rgba(166, 178, 195, 0.16);
  --rule-soft:  rgba(166, 178, 195, 0.08);
  --rule-hard:  rgba(166, 178, 195, 0.32);
  --rule-cyan:  rgba(0, 229, 255, 0.30);

  /* Type */
  --display: "Michroma", "Chakra Petch", ui-sans-serif, system-ui, sans-serif;
  --face:    "Chakra Petch", ui-sans-serif, system-ui, sans-serif;
  --mono:    "JetBrains Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;

  /* 8px spacing scale */
  --s1: 8px;   --s2: 16px;  --s3: 24px;  --s4: 32px;
  --s5: 48px;  --s6: 64px;  --s7: 96px;  --s8: 128px;
  --s9: 176px;

  /* Wide-screen shell. This site is built for width. */
  --gutter: clamp(20px, 3.2vw, 72px);
  /* The rails are fixed overlays, so the shell has to clear them itself. */
  --shell:  min(2100px, 100% - (var(--gutter) * 2) - (var(--rail-w) * 2));
  --measure: 68ch;

  /* Chrome */
  --deck-h: 68px;   /* glareshield height */
  --rail-w: 62px;   /* side instrument rails */
  --sect-pad: clamp(96px, 9vw, 176px);  /* section block padding, shared so the
                                           channel tag can hang off it */

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-snap: cubic-bezier(0.16, 1, 0.3, 1);
}

@media (max-width: 1100px) { :root { --rail-w: 0px; --deck-h: 60px; } }

/* --- 1b. Ground previews -------------------------------------------------
   Two alternative page grounds, switched by ?g= in the URL so they can be
   compared on the live site and reverted by removing the parameter. Neither
   touches the brand signal colours — only how dark the field behind them is.

     (none)   brand palette card, Deep Navy #0A0F1C flat
     ?g=deep  one step deeper everywhere, so the blue terrain carries further
     ?g=fade  near-black under the deck and wordmark, easing into navy
   -------------------------------------------------------------------------- */

/* The previous flat Deep Navy ground, kept as a one-parameter revert. */
:root[data-ground="navy"] {
  --ground:   #0A0F1C;
  --well:     #060A13;
  --black:    #04070D;
  --deck-rgb: 10, 15, 28;
}

/* --- 2. Reset ------------------------------------------------------------ */

*, *::before, *::after { box-sizing: border-box; }

html {
  background: var(--ground);
  color-scheme: dark;
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--face);
  font-weight: 300;
  font-size: clamp(15px, 0.62vw + 12px, 17px);
  line-height: 1.62;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, svg, canvas { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
h1, h2, h3, h4, p, figure, blockquote { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }

::selection { background: var(--coral); color: var(--black); }

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

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--cyan); color: var(--black);
  padding: var(--s2) var(--s3);
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.12em;
}
.skip:focus { left: 0; }

.vh {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* --- 3. Type primitives -------------------------------------------------- */

.readout {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "zero" 1;
  letter-spacing: 0.02em;
}

.label {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.label--cyan  { color: var(--cyan); }
.label--coral { color: var(--coral); }

.display {
  font-family: var(--display);
  font-weight: 400;
  letter-spacing: 0.02em;
  line-height: 0.98;
  text-transform: uppercase;
}

/* Section titles carry the icon's coral dash at the end, centred on the whole
   heading rather than sitting on the last baseline — so it reads the same on a
   one-line and a two-line title. Proportions taken off the artwork: in the
   wordmark the bar measures 175x36 against a 163px cap height, so 1.07 cap
   wide and 0.22 cap tall. Michroma's cap is ~0.72em, hence 0.77em x 0.16em. */
.h-sect {
  font-family: var(--display);
  font-size: clamp(28px, 3.1vw, 62px);
  line-height: 1.0;
  letter-spacing: 0.005em;
  text-transform: uppercase;
  font-weight: 400;
}
/* Set inline at the end of the last line, so it follows the final word rather
   than floating beside the middle of a two-line title. Michroma's cap height
   is ~0.72em, so the cap's optical centre is 0.36em above the baseline; the
   bar is 0.16em tall, hence a 0.28em lift to sit its middle on that centre. */
.h-sect::after {
  content: "";
  display: inline-block;
  width: 0.77em;
  height: 0.16em;
  margin-left: 0.37em;
  vertical-align: 0.28em;
  background: var(--coral);
}
/* Beamed in from the right exactly as the accent bars land on the E's during
   the logo load — same over-stretch, same blowout, same snap, same 0.72s on
   --ease-snap. The distances are the logo's own, restated as multiples of the
   dash's length rather than of the wordmark's width: the bars travel 3.4x
   their own length and overshoot by a quarter of it. It is the same coral
   stroke, so it should arrive the same way. Guarded on .js: with scripting
   off the reveal never fires and the dash must simply be there. */
.js .h-sect::after { opacity: 0; }
.js .rv.is-in .h-sect::after { animation: dash-beam 0.72s var(--ease-snap) 0.4s both; }
@keyframes dash-beam {
  0%   { opacity: 0; transform: translateX(340%) scaleX(1.5); filter: brightness(3) blur(4px); }
  55%  { opacity: 1; transform: translateX(-25%)  scaleX(1);   filter: brightness(2) blur(0); }
  100% { opacity: 1; transform: none; filter: none; }
}
@media (prefers-reduced-motion: reduce) {
  .js .h-sect::after { opacity: 1; }
}

.h-sub {
  font-family: var(--face);
  font-weight: 600;
  font-size: clamp(19px, 1.5vw, 30px);
  line-height: 1.16;
  letter-spacing: -0.005em;
}

.lede {
  font-size: clamp(16px, 0.9vw + 11px, 21px);
  line-height: 1.55;
  color: var(--ink-mid);
  max-width: var(--measure);
  font-weight: 300;
}

.body-c { color: var(--ink-muted); max-width: var(--measure); }

.hl { color: var(--cyan); }
.hl-coral { color: var(--coral); }

/* --- 4. Layout shell ----------------------------------------------------- */

.shell {
  width: var(--shell);
  margin-inline: auto;
}

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

.sect {
  position: relative;
  padding-block: var(--sect-pad);
  border-top: 1px solid var(--rule-soft);
}
.sect--tight { padding-block: clamp(var(--s6), 6vw, var(--s7)); }
.sect--flush { border-top: 0; }

/* Section head: index number, title, note — the instrument page header */
.sect-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr);
  gap: var(--s5) var(--s6);
  align-items: end;
  margin-bottom: clamp(var(--s5), 5vw, var(--s7));
}
@media (max-width: 900px) { .sect-head { grid-template-columns: 1fr; align-items: start; } }

/* The channel tag rides the section's top rule at the outer margin, the way a
   page number sits in the corner of a multi-function display. It is not a
   kicker stacked above the heading. */
/* Anchored to .shell (the nearest positioned ancestor), hung back up into the
   section's top padding so it sits on the rule at the content margin. */
.sect-head__num {
  position: absolute;
  top: calc((var(--sect-pad) * -1) + var(--s4));
  right: 0;
  margin: 0;
  font-family: var(--mono);
  font-size: 10px; letter-spacing: 0.22em;
  color: var(--ink-faint);
  z-index: 2;
}
@media (max-width: 720px) {
  .sect-head__num { position: static; display: block; margin-bottom: var(--s2); }
}

/* --- 5. Glareshield (top chrome + heading tape) -------------------------- */

.deck {
  position: fixed; inset: 0 0 auto 0; z-index: 80;
  height: var(--deck-h);
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s4);
  padding-inline: var(--gutter);
  /* Bright content passing underneath was reading through the old ramp. Blur
     stays modest so it does not trail a visible plume off the mark. */
  background: linear-gradient(180deg,
    rgba(var(--deck-rgb), 0.995) 0%, rgba(var(--deck-rgb), 0.975) 72%,
    rgba(var(--deck-rgb), 0.58) 91%, rgba(var(--deck-rgb), 0) 100%);
  backdrop-filter: blur(13px) saturate(115%);
  -webkit-backdrop-filter: blur(13px) saturate(115%);
  border-bottom: 1px solid var(--rule-soft);
}

.deck__brand { display: flex; align-items: center; gap: var(--s2); flex: none; }
/* The 045 mark reads better than the stacked wordmark at nav scale. Its tile
   ground is stripped to transparency, so the glyphs sit straight on the deck
   instead of carrying an opaque box that fights a semi-transparent bar. */
.deck__logo {
  height: 32px; width: auto;
  transition: filter 0.4s var(--ease), transform 0.4s var(--ease-snap);
}
.deck__brand:hover .deck__logo {
  filter: drop-shadow(0 0 13px rgba(0, 229, 255, 0.6));
  transform: translateY(-1px);
}
@media (max-width: 860px) { .deck__logo { height: 28px; } }

/* The heading tape — a live instrument sitting in the navigation bar */
.tape {
  position: relative;
  height: 40px;
  overflow: hidden;
  border-left: 1px solid var(--rule-soft);
  border-right: 1px solid var(--rule-soft);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
@media (max-width: 1100px) { .tape { display: none; } }

.tape__strip {
  position: absolute; top: 0; left: 50%; height: 100%;
  display: flex; align-items: flex-end;
  will-change: transform;
}
.tape__tick {
  position: relative;
  width: 34px; flex: none;
  height: 100%;
  display: flex; flex-direction: column; justify-content: flex-end; align-items: center;
  gap: 3px;
  padding-bottom: 6px;
}
.tape__tick::after {
  content: ""; width: 1px; height: 7px; background: var(--ink-ghost);
}
.tape__tick--major::after { height: 12px; background: var(--ink-ornament); }
.tape__tick span {
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.1em;
  color: var(--ink-ornament);
  opacity: 0;
}
.tape__tick--major span { opacity: 1; }

.tape__bug {
  position: absolute; left: 50%; top: 0; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center;
  pointer-events: none;
}
.tape__bug b {
  font-family: var(--mono); font-weight: 700;
  font-size: 13px; letter-spacing: 0.14em;
  color: var(--black); background: var(--coral);
  padding: 2px 7px 1px;
  line-height: 1.3;
}
.tape__bug i {
  display: block; width: 0; height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid var(--coral);
}

.deck__nav { display: flex; align-items: center; gap: var(--s1); flex: none; }
@media (max-width: 860px) { .deck__nav .navlink { display: none; } }

.navlink {
  position: relative;
  font-family: var(--mono);
  font-size: 10px; font-weight: 500;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--ink-mid);
  padding: 10px var(--s2);
  transition: color 0.25s var(--ease);
}
.navlink::before {
  content: ""; position: absolute; left: var(--s2); right: var(--s2); bottom: 6px;
  height: 1px; background: var(--cyan);
  transform: scaleX(0); transform-origin: left;
  transition: transform 0.35s var(--ease);
}
.navlink:hover { color: var(--white); }
.navlink:hover::before { transform: scaleX(1); }
.navlink[aria-current="page"] { color: var(--cyan); }
.navlink[aria-current="page"]::before { transform: scaleX(1); }

/* --- 6. Buttons ---------------------------------------------------------- */

.btn {
  position: relative;
  display: inline-flex; align-items: center; gap: var(--s2);
  font-family: var(--mono); font-size: 11px; font-weight: 500;
  letter-spacing: 0.18em; text-transform: uppercase;
  padding: 15px var(--s3);
  border: 1px solid var(--rule-hard);
  color: var(--white);
  background: transparent;
  overflow: hidden;
  transition: color 0.3s var(--ease), border-color 0.3s var(--ease);
  /* clipped corner — the bezel language */
  clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 10px, 100% 100%, 10px 100%, 0 calc(100% - 10px));
}
.btn::before {
  content: ""; position: absolute; inset: 0;
  background: var(--cyan);
  transform: translateY(101%);
  transition: transform 0.42s var(--ease-snap);
  z-index: -1;
}
.btn > * { position: relative; z-index: 1; }
.btn:hover { color: var(--black); border-color: var(--cyan); }
.btn:hover::before { transform: translateY(0); }

.btn--primary {
  background: var(--coral); border-color: var(--coral); color: var(--black);
  font-weight: 700;
}
.btn--primary::before { background: var(--white); }
.btn--primary:hover { color: var(--black); border-color: var(--white); }

.btn--ghost { border-color: var(--rule); color: var(--ink-mid); }

.btn__arrow { transition: transform 0.34s var(--ease-snap); }
.btn:hover .btn__arrow { transform: translateX(4px); }

/* --- 7. Hero: the attitude indicator ------------------------------------- */

/* Vertical budget is tight: the primary action has to clear a 1080 fold with
   browser chrome taken off, so the stack above it is kept lean. */
.adi {
  position: relative;
  min-height: 100svh;
  display: flex; align-items: center;
  padding-top: calc(var(--deck-h) + var(--s3));
  padding-bottom: var(--s5);
  overflow: hidden;
  isolation: isolate;
}

/* Synthetic-vision terrain — real canvas, drawn every frame */
.adi__svt {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  z-index: -3;
}

/* Sky wash above the horizon + earth darkness below */
/* With the ground now near-black, the navy has to be put back deliberately —
   as a glow gathering at the horizon, which is where the brand board puts it.
   Black at the top under the deck and the wordmark, navy and blue below. */
.adi__wash {
  position: absolute; inset: 0; z-index: -2; pointer-events: none;
  background:
    radial-gradient(125% 66% at 50% 63%, rgba(0,102,255,0.30) 0%, rgba(0,102,255,0.09) 44%, transparent 74%),
    radial-gradient(72% 42% at 50% 61%, rgba(0,229,255,0.19) 0%, transparent 70%),
    linear-gradient(180deg, rgba(0,0,0,0.55) 0%, rgba(0,0,0,0.18) 34%, transparent 58%);
}

/* Scanline glass — the screen you are looking through */
.adi__glass {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background-image: repeating-linear-gradient(
    180deg, rgba(255,255,255,0.022) 0px, rgba(255,255,255,0.022) 1px, transparent 1px, transparent 3px);
  mix-blend-mode: overlay;
  opacity: 0.55;
}

/* Vignette so the corners fall into the bezel, plus a dissolve at the foot
   so the terrain does not end on a hard seam where the section stops. */
.adi::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    linear-gradient(180deg, transparent 78%, rgba(10,15,28,0.72) 93%, var(--ground) 100%),
    radial-gradient(115% 88% at 50% 50%, transparent 44%, rgba(4,7,13,0.74) 100%);
}

.adi__grid {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.72fr);
  gap: var(--s6);
  align-items: center;
}
@media (max-width: 1100px) { .adi__grid { grid-template-columns: 1fr; gap: var(--s5); } }

/* Logo block — the aircraft symbol */
/* The wordmark arrives a line at a time — ZERO, then FOUR, then FIVE. Three
   copies of the one file, each clipped to its own row; cut points measured off
   the artwork's own gaps (rows end at 32.0/63.4/95.1%), so the logo itself is
   untouched. Same image three times is one network request. */
.mark {
  position: relative;
  display: block;
  width: clamp(250px, 25vw, 470px);
  margin: 0 0 var(--s3);
  animation: mark-breathe 7s var(--ease) infinite;
}
.mark__row { display: block; width: 100%; height: auto; }
.mark__row:nth-child(1) { clip-path: inset(0 0 63.8% 0); }
.mark__row:nth-child(2) { position: absolute; inset: 0; clip-path: inset(36.2% 0 32.5% 0); }
.mark__row:nth-child(3) { position: absolute; inset: 0; clip-path: inset(67.5% 0 0 0); }

/* The two accent bars are held back and beamed in last. They are the only part
   of the mark that is not white, and they complete the two E's — so the logo
   assembles, then clicks into place. Split out of the artwork by colour; the
   shapes themselves are untouched. */
.mark__bars { position: absolute; inset: 0; width: 100%; height: auto; }

.js .mark__row, .js .mark__bars { opacity: 0; }
.js .mark.is-in .mark__row { animation: mark-drop 0.95s var(--ease-snap) both; }
.js .mark.is-in .mark__row:nth-child(2) { animation-delay: 0.9s; }
.js .mark.is-in .mark__row:nth-child(3) { animation-delay: 1.8s; }
.js .mark.is-in .mark__bars { animation: bars-beam 0.72s var(--ease-snap) 2.55s both; }

@keyframes mark-drop {
  from { opacity: 0; transform: translateY(-26px); filter: blur(7px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes bars-beam {
  0%   { opacity: 0; transform: translateX(34%) scaleX(1.5); filter: brightness(3) blur(4px); }
  55%  { opacity: 1; transform: translateX(-2.5%) scaleX(1); filter: brightness(2) blur(0); }
  100% { opacity: 1; transform: none; filter: none; }
}
@media (prefers-reduced-motion: reduce) {
  .js .mark__row, .js .mark__bars { opacity: 1; animation: none; }
  .mark { animation: none; }
}

.adi__slogan {
  font-family: var(--face);
  font-weight: 300;
  font-size: clamp(13px, 1.05vw, 19px);
  letter-spacing: 0.30em;
  text-transform: uppercase;
  line-height: 1.7;
  color: var(--ink-mid);
  margin-bottom: var(--s3);
}
.adi__slogan b { color: var(--white); font-weight: 400; }

.adi__actions { display: flex; flex-wrap: wrap; gap: var(--s2); }

/* Annunciator stack — right of the hero */
.annun { display: flex; flex-direction: column; gap: var(--s1); position: relative; }

/* A sweep crosses the stack once, as power comes up. */
.annun.is-live::after {
  content: ""; position: absolute; inset: 0; z-index: 4; pointer-events: none;
  background: linear-gradient(100deg,
    transparent 42%, rgba(0,229,255,0.16) 50%, transparent 58%);
  animation: annun-sweep 1.15s var(--ease) 1 both;
}
@keyframes annun-sweep {
  from { transform: translateX(-104%); }
  to   { transform: translateX(104%); }
}

/* Lamps latch one at a time rather than all arriving lit. */
.js .annun .lamp {
  opacity: 0; transform: translateX(-7px);
}
/* Matched to .mark__row's 0.95s so a lamp and its wordmark line resolve
   together rather than the lamp arriving first. */
.js .annun .lamp.is-latched {
  opacity: 1; transform: none;
  transition: opacity 0.95s var(--ease), transform 0.95s var(--ease-snap);
}
.js .annun .lamp.is-latched .lamp__dot { animation: lamp-latch 0.5s var(--ease) 1 both; }
@keyframes lamp-latch {
  0%   { transform: scale(0.2); filter: brightness(2.6); }
  55%  { transform: scale(1.5); filter: brightness(2.2); }
  100% { transform: scale(1);   filter: none; }
}
@media (prefers-reduced-motion: reduce) {
  .js .annun .lamp { opacity: 1; transform: none; }
}

.annun__cap {
  display: flex; justify-content: space-between; align-items: baseline;
  padding-bottom: var(--s1); margin-bottom: var(--s1);
  border-bottom: 1px solid var(--rule);
}

.lamp {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0,1fr) auto;
  align-items: center; gap: var(--s2);
  padding: 13px var(--s2) 13px 13px;
  background: rgba(18, 27, 46, 0.66);
  border: 1px solid var(--rule-soft);
  border-left: 2px solid var(--ink-ghost);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: border-color 0.3s var(--ease), background 0.3s var(--ease), transform 0.3s var(--ease);
}
.lamp:hover { transform: translateX(3px); background: rgba(24, 36, 61, 0.86); }

.lamp__dot {
  width: 7px; height: 7px; flex: none;
  background: var(--ink-ghost);
  box-shadow: 0 0 0 0 transparent;
}
.lamp__name {
  font-family: var(--mono); font-size: 11px; font-weight: 500;
  letter-spacing: 0.13em; text-transform: uppercase; color: var(--ink-mid);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lamp__state {
  font-family: var(--mono); font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-faint);
}

.lamp--live { border-left-color: var(--cyan); }
.lamp--live .lamp__dot { background: var(--cyan); box-shadow: 0 0 10px 1px rgba(0,229,255,0.75); animation: pulse 2.6s var(--ease) infinite; }
.lamp--live .lamp__state { color: var(--cyan); }
.lamp--live .lamp__name { color: var(--white); }

.lamp--armed { border-left-color: var(--coral); }
.lamp--armed .lamp__dot { background: var(--coral); box-shadow: 0 0 10px 1px rgba(255,106,77,0.7); }
.lamp--armed .lamp__state { color: var(--coral); }

.lamp--standby { border-left-color: var(--ink-faint); }

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.42; }
}

/* Corner readouts — the instrument furniture */
.adi__corner {
  position: absolute; z-index: 2;
  display: flex; align-items: center; gap: var(--s2);
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.16em;
  color: var(--ink-faint); text-transform: uppercase;
}
.adi__corner--bl { left: calc(var(--gutter) + var(--rail-w)); bottom: var(--s4); }
.adi__corner--br { right: calc(var(--gutter) + var(--rail-w)); bottom: var(--s4); }
@media (max-width: 900px) { .adi__corner { display: none; } }

.adi__corner b { color: var(--cyan); font-weight: 500; }

/* Scroll cue */
.cue {
  position: absolute; left: 50%; bottom: var(--s4); z-index: 2;
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.26em;
  color: var(--ink-faint); text-transform: uppercase;
}
.cue__bar {
  width: 1px; height: 40px;
  background: linear-gradient(180deg, var(--cyan), transparent);
  animation: cue-fall 2.4s var(--ease) infinite;
}
@keyframes cue-fall {
  0%   { transform: scaleY(0); transform-origin: top; opacity: 0; }
  40%  { transform: scaleY(1); transform-origin: top; opacity: 1; }
  60%  { transform: scaleY(1); transform-origin: bottom; opacity: 1; }
  100% { transform: scaleY(0); transform-origin: bottom; opacity: 0; }
}

/* Pitch ladder + bank arc (SVG overlay on the hero) */
.adi__ladder {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  width: 100%; height: 100%;
  opacity: 0.5;
}
@media (max-width: 900px) { .adi__ladder { opacity: 0.3; } }

/* --- 8. Side rails ------------------------------------------------------- */

.rail {
  position: fixed; top: var(--deck-h); bottom: 0; z-index: 60;
  width: var(--rail-w);
  display: flex; flex-direction: column; align-items: center;
  justify-content: center;
  gap: var(--s3);
  pointer-events: none;
}
.rail--l { left: 0; border-right: 1px solid var(--rule-soft); }
.rail--r { right: 0; border-left: 1px solid var(--rule-soft); }
@media (max-width: 1100px) { .rail { display: none; } }

.rail__cap {
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.2em;
  color: var(--ink-ornament); text-transform: uppercase;
  writing-mode: vertical-rl;
}
.rail--l .rail__cap { transform: rotate(180deg); }

/* Altitude tape = scroll position, read as an instrument */
.alt {
  position: relative;
  flex: 1 1 auto;
  width: 100%;
  max-height: 58vh;
  display: flex; justify-content: center;
  overflow: hidden;
  mask-image: linear-gradient(180deg, transparent, #000 18%, #000 82%, transparent);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 18%, #000 82%, transparent);
}
.alt__strip {
  position: absolute; top: 50%; left: 0; right: 0;
  display: flex; flex-direction: column; align-items: center;
  will-change: transform;
}
.alt__tick {
  height: 30px; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.08em;
  color: var(--ink-ghost);
}
.alt__tick--major { color: var(--ink-ornament); }

.alt__bug {
  position: absolute; top: 50%; left: 0; right: 0;
  transform: translateY(-50%);
  display: flex; justify-content: center;
  pointer-events: none;
}
.alt__bug span {
  font-family: var(--mono); font-size: 10px; font-weight: 700; letter-spacing: 0.06em;
  background: var(--cyan); color: var(--black);
  padding: 2px 5px;
}

.rail__stack { display: flex; flex-direction: column; gap: 5px; align-items: center; }
.rail__pip {
  width: 5px; height: 5px;
  background: var(--ink-ghost);
  transition: background 0.4s var(--ease), box-shadow 0.4s var(--ease);
}
.rail__pip.is-on { background: var(--cyan); box-shadow: 0 0 8px rgba(0,229,255,0.7); }

/* --- 9. Systems index (the app list) ------------------------------------- */

.sys { border-top: 1px solid var(--rule); }

.sys__row {
  position: relative;
  display: grid;
  grid-template-columns: 58px 64px minmax(0, 1fr) minmax(0, 0.95fr) 150px 120px 44px;
  align-items: center;
  gap: var(--s3);
  padding: clamp(var(--s3), 2.2vw, var(--s4)) 0;
  border-bottom: 1px solid var(--rule);
  transition: background 0.4s var(--ease);
}
/* Sweep is a scaleX transform, not an animated width — width animation
   relayouts the whole row grid on every frame of the hover. */
.sys__row::before {
  content: ""; position: absolute; inset: -1px 0;
  background: rgba(0, 102, 255, 0.07);
  transform: scaleX(0); transform-origin: left;
  transition: transform 0.5s var(--ease-snap);
  z-index: 0;
}
.sys__row:hover::before,
.sys__row:focus-within::before { transform: scaleX(1); }
.sys__row > * { position: relative; z-index: 1; }
.sys__row:hover .sys__idx { transform: translateX(6px); }
.sys__idx { transition: color 0.3s var(--ease), transform 0.4s var(--ease); }

/* The narrow-viewport rules for this row live AFTER the component rules below,
   not here. Media queries add no specificity, so a later flat rule beats an
   earlier one inside a query — which is how `.sys__bar { display: flex }` was
   quietly outranking the `display: none` these breakpoints intended. */

.sys__idx {
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.1em;
  color: var(--ink-faint);
}
.sys__row:hover .sys__idx { color: var(--coral); }

.sys__icon {
  width: 56px; height: 56px;
  border-radius: 13px;
  overflow: hidden;
  border: 1px solid var(--rule-soft);
  transition: transform 0.5s var(--ease-snap), box-shadow 0.5s var(--ease);
}
.sys__icon img { width: 100%; height: 100%; object-fit: cover; }
.sys__row:hover .sys__icon {
  transform: scale(1.06) rotate(-2deg);
  box-shadow: 0 8px 34px rgba(0, 0, 0, 0.7);
}

.sys__name {
  font-family: var(--display);
  font-size: clamp(17px, 1.55vw, 30px);
  line-height: 1.05;
  letter-spacing: 0.005em;
  text-transform: uppercase;
  color: var(--ink-mid);
  transition: color 0.3s var(--ease);
}
.sys__row:hover .sys__name { color: var(--white); }

.sys__desc {
  font-size: 14px; line-height: 1.5; color: var(--ink-muted);
  font-weight: 300;
  transition: color 0.3s var(--ease);
}
/* The whole row lifts on hover, description included — not just the name. */
.sys__row:hover .sys__desc { color: var(--ink); }

/* Capability bar — segmented, instrument style */
.sys__bar { display: flex; gap: 3px; align-items: center; }
.sys__bar i {
  display: block; flex: 1; height: 12px;
  background: var(--ink-ghost);
  transition: background 0.26s var(--ease), box-shadow 0.26s var(--ease);
  transition-delay: 0s;
}
.sys__bar i.is-on { background: var(--blue); }

/* The meter fills left to right on hover, a segment at a time, the way a bar
   gauge charges. Delays apply on the way in only; leaving snaps back at once
   so a fast cursor never leaves a half-lit gauge behind. */
.sys__row:hover .sys__bar i.is-on {
  background: var(--cyan);
  box-shadow: 0 0 9px rgba(0, 229, 255, 0.55);
}
.sys__row:hover .sys__bar i:nth-child(1) { transition-delay: 0s; }
.sys__row:hover .sys__bar i:nth-child(2) { transition-delay: 0.055s; }
.sys__row:hover .sys__bar i:nth-child(3) { transition-delay: 0.11s; }
.sys__row:hover .sys__bar i:nth-child(4) { transition-delay: 0.165s; }
.sys__row:hover .sys__bar i:nth-child(5) { transition-delay: 0.22s; }
.sys__row:hover .sys__bar i:nth-child(6) { transition-delay: 0.275s; }
.sys__row:hover .sys__bar i:nth-child(7) { transition-delay: 0.33s; }
.sys__row:hover .sys__bar i:nth-child(8) { transition-delay: 0.385s; }

.sys__stat {
  font-family: var(--mono); font-size: 10px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
  display: inline-flex; align-items: center; gap: 7px;
  justify-self: start;
}
.sys__stat::before { content: ""; width: 6px; height: 6px; flex: none; background: currentColor; }
.sys__stat--live    { color: var(--cyan); }
.sys__stat--armed   { color: var(--coral); }
.sys__stat--standby { color: var(--ink-faint); }

.sys__chev {
  font-family: var(--mono); font-size: 17px; color: var(--ink-faint);
  justify-self: end;
  transition: transform 0.42s var(--ease-snap), color 0.3s var(--ease);
}
.sys__row:hover .sys__chev { transform: translateX(7px); color: var(--cyan); }

.sys__link { position: absolute; inset: 0; z-index: 3; }
.sys__link:focus-visible { outline-offset: -3px; }

/* --- systems row, narrow viewports --------------------------------------- */
/* Placed after the component rules on purpose. A media query carries no extra
   specificity, so these have to come last to win — stated above the row too,
   because getting it wrong is silent: the bars kept their `display: flex` and
   went on occupying a column nobody could see. */

@media (max-width: 1400px) {
  .sys__row { grid-template-columns: 46px 56px minmax(0,1fr) 130px 40px; }
  .sys__desc, .sys__bar { display: none; }
}

@media (max-width: 720px) {
  /* Three tracks — index, icon, name — with the status set beneath the name
     rather than beside it. Holding it on the same line left the name about
     170px, and "Shipping Rules AI" in a display face this wide broke onto two
     lines; dropping the status gives the name the full 284px and every one of
     them sets on one line. The status reads as a sub-label of the name it sits
     under, which is what it is. Every placement is explicit: auto-flow is what
     put the status in column 1 of its own row in the first place.
     The chevron goes — the whole row is already one tap target, so it was
     spending width to repeat what the row says. */
  .sys__row {
    grid-template-columns: 18px 40px minmax(0,1fr);
    column-gap: var(--s2); row-gap: 6px;
  }
  .sys__chev { display: none; }
  .sys__idx  { grid-column: 1; grid-row: 1; }
  /* Spans both rows so it stays centred against the name-plus-status pair. */
  .sys__icon { grid-column: 2; grid-row: 1 / span 2; }
  .sys__name { grid-column: 3; grid-row: 1; }
  .sys__stat { grid-column: 3; grid-row: 2; justify-self: start; }
  /* 40px keeps the icon a thumbnail beside the name rather than competing with
     it, and holds the desktop corner ratio (13/56) at this size. */
  .sys__icon { width: 40px; height: 40px; border-radius: 10px; }
}

/* --- 10. Instrument panel (generic bezel container) ---------------------- */

.panel {
  position: relative;
  background:
    linear-gradient(180deg, rgba(18, 27, 46, 0.78) 0%, rgba(6, 10, 19, 0.92) 100%);
  border: 1px solid var(--rule-soft);
  padding: clamp(var(--s3), 2.4vw, var(--s5));
  clip-path: polygon(0 0, calc(100% - 18px) 0, 100% 18px, 100% 100%, 18px 100%, 0 calc(100% - 18px));
}
.panel--flush { padding: 0; }

.panel__tag {
  position: absolute; top: 0; left: 0;
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.2em;
  text-transform: uppercase;
  background: var(--cyan); color: var(--black);
  padding: 3px 9px 2px;
}

/* Corner brackets — drawn, not decorative chrome */
.brackets { position: relative; }
.brackets::before, .brackets::after {
  content: ""; position: absolute; width: 14px; height: 14px;
  border-color: var(--rule-hard); border-style: solid;
}
.brackets::before { top: 0; left: 0; border-width: 1px 0 0 1px; }
.brackets::after  { bottom: 0; right: 0; border-width: 0 1px 1px 0; }

/* --- 11. Featured system (Store Chat AI block) --------------------------- */

.feat {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.92fr);
  gap: clamp(var(--s5), 5vw, var(--s7));
  align-items: center;
}
@media (max-width: 1100px) { .feat { grid-template-columns: 1fr; } }

.feat__head { display: flex; align-items: center; gap: var(--s3); margin-bottom: var(--s3); }
.feat__icon {
  width: 74px; height: 74px; border-radius: 17px; flex: none;
  box-shadow: 0 12px 46px rgba(255, 106, 77, 0.30);
}

/* Spec list — definition rows with tabular figures */
.spec { border-top: 1px solid var(--rule); margin-top: var(--s4); }
.spec__row {
  display: grid; grid-template-columns: 150px minmax(0,1fr);
  gap: var(--s3);
  padding: var(--s2) 0;
  border-bottom: 1px solid var(--rule-soft);
  align-items: baseline;
}
@media (max-width: 620px) { .spec__row { grid-template-columns: 1fr; gap: 4px; } }
.spec__k {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--ink-faint);
}
.spec__v { font-size: 15px; color: var(--ink-mid); font-weight: 300; }

/* --- 12. Chat demo (authored, labelled synthetic) ------------------------ */

.chat { display: flex; flex-direction: column; gap: var(--s2); }

.chat__head {
  display: flex; align-items: center; justify-content: space-between;
  padding-bottom: var(--s2); border-bottom: 1px solid var(--rule);
  margin-bottom: var(--s1);
}

.msg {
  max-width: 84%;
  padding: 13px var(--s2);
  font-size: 14.5px; line-height: 1.55; font-weight: 300;
  border: 1px solid var(--rule-soft);
  opacity: 0; transform: translateY(10px);
}
.msg.is-in { opacity: 1; transform: none; transition: opacity 0.5s var(--ease), transform 0.5s var(--ease); }

.msg--them {
  align-self: flex-start;
  background: rgba(18, 27, 46, 0.82);
  color: var(--ink-mid);
  border-left: 2px solid var(--ink-faint);
}
.msg--ai {
  align-self: flex-end;
  background: rgba(0, 102, 255, 0.13);
  border-color: rgba(0, 229, 255, 0.22);
  border-right: 2px solid var(--cyan);
  color: var(--white);
}
.msg__who {
  display: block;
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--ink-faint);
  margin-bottom: 6px;
}
.msg--ai .msg__who { color: var(--cyan); }

.msg__act {
  display: inline-flex; align-items: center; gap: 7px;
  margin-top: var(--s1);
  font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--coral);
  border: 1px solid rgba(255,106,77,0.4);
  padding: 4px 8px;
}

/* A demonstration has to disclose itself at a size someone actually reads. */
.synthetic {
  display: block; margin-top: var(--s2);
  padding-top: var(--s2); border-top: 1px solid var(--rule-soft);
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.1em;
  color: var(--ink-muted);
}

/* --- 13. Flight plan (roadmap) ------------------------------------------ */

.plan { position: relative; }

.plan__route {
  position: absolute; left: 0; right: 0; top: 27px; height: 1px;
  background: linear-gradient(90deg, var(--cyan), var(--blue) 40%, var(--ink-ghost));
  z-index: 0;
}

/* A pulse runs the route the way a leg lights on a flight plan. Transform
   only — animating left would relayout the whole row every frame. A real
   element rather than a pseudo so its live position can be measured each
   frame and the waypoints struck as it reaches them. */
.plan__beam {
  position: absolute; top: 50%; left: 0;
  width: 22%; height: 2px;
  background: linear-gradient(90deg,
    transparent 0%, rgba(0,229,255,0.85) 42%, #FFFFFF 52%, rgba(0,102,255,0.7) 62%, transparent 100%);
  box-shadow: 0 0 18px rgba(0, 229, 255, 0.7);
  animation: beam-x 5.4s cubic-bezier(0.5, 0, 0.5, 1) infinite;
  will-change: transform;
}
@keyframes beam-x {
  0%   { transform: translate(-115%, -50%); opacity: 0; }
  9%   { opacity: 1; }
  86%  { opacity: 1; }
  100% { transform: translate(465%, -50%); opacity: 0; }
}

@media (max-width: 900px) {
  .plan__route { left: 27px; right: auto; top: 0; bottom: 0; width: 1px; height: auto;
    background: linear-gradient(180deg, var(--cyan), var(--blue) 40%, var(--ink-ghost)); }
  /* Vertical rail on narrow screens, so the beam runs down it instead. */
  .plan__beam {
    top: 0; left: 50%; width: 2px; height: 18%;
    background: linear-gradient(180deg,
      transparent 0%, rgba(0,229,255,0.85) 42%, #FFFFFF 52%, rgba(0,102,255,0.7) 62%, transparent 100%);
    animation-name: beam-y;
  }
  @keyframes beam-y {
    0%   { transform: translate(-50%, -115%); opacity: 0; }
    9%   { opacity: 1; }
    86%  { opacity: 1; }
    100% { transform: translate(-50%, 570%); opacity: 0; }
  }
}

@media (prefers-reduced-motion: reduce) {
  .plan__beam { display: none; }
}

/* Each waypoint takes a hit as the beam reaches it: a cyan ring blooms over
   the diamond and fades. The flash lives on a pseudo-element so the resting
   border — steel, cyan for done, coral for next — is never touched and there
   is nothing to restore when the animation ends. */
.wpt__mark::before {
  content: ""; position: absolute; inset: -1px;
  border: 1px solid var(--cyan);
  opacity: 0; pointer-events: none;
}
.wpt__mark.is-lit::before { animation: wpt-strike 0.9s var(--ease-snap); }
.wpt__mark.is-lit { animation: wpt-pop 0.9s var(--ease-snap); }
.wpt__mark.is-lit span { animation: wpt-glow 0.9s var(--ease-snap); }

@keyframes wpt-strike {
  0%   { opacity: 0; border-color: var(--cyan); box-shadow: none; }
  12%  { opacity: 1; border-color: #FFFFFF;
         box-shadow: 0 0 32px rgba(0, 229, 255, 0.62), inset 0 0 20px rgba(0, 229, 255, 0.26); }
  100% { opacity: 0; border-color: var(--cyan); box-shadow: none; }
}
@keyframes wpt-pop {
  0%   { transform: rotate(45deg) scale(1); }
  12%  { transform: rotate(45deg) scale(1.09); }
  100% { transform: rotate(45deg) scale(1); }
}
@keyframes wpt-glow {
  0%   { transform: rotate(-45deg); text-shadow: none; }
  12%  { transform: rotate(-45deg); text-shadow: 0 0 14px rgba(0, 229, 255, 0.95); }
  100% { transform: rotate(-45deg); text-shadow: none; }
}

.plan__list {
  position: relative; z-index: 1;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--s4);
}
@media (max-width: 900px) { .plan__list { grid-template-columns: 1fr; gap: var(--s4); } }

.wpt { position: relative; padding-top: 0; }
@media (max-width: 900px) { .wpt { padding-left: 62px; } }

.wpt__mark {
  position: relative;
  width: 54px; height: 54px;
  display: grid; place-items: center;
  border: 1px solid var(--rule-hard);
  background: var(--well);
  margin-bottom: var(--s3);
  font-family: var(--mono); font-size: 11px; font-weight: 700; letter-spacing: 0.06em;
  color: var(--ink-faint);
  transform: rotate(45deg);
  transition: border-color 0.4s var(--ease), color 0.4s var(--ease), box-shadow 0.4s var(--ease);
}
.wpt__mark span { transform: rotate(-45deg); }
@media (max-width: 900px) { .wpt__mark { position: absolute; left: 0; top: 0; margin: 0; } }

.wpt--done .wpt__mark { border-color: var(--cyan); color: var(--cyan); box-shadow: 0 0 22px rgba(0,229,255,0.28); }
.wpt--next .wpt__mark { border-color: var(--coral); color: var(--coral); box-shadow: 0 0 22px rgba(255,106,77,0.24); }

.wpt__name {
  font-family: var(--face); font-weight: 600; font-size: 17px;
  letter-spacing: 0.01em; margin-bottom: 6px;
}
.wpt__note { font-size: 14px; color: var(--ink-muted); font-weight: 300; line-height: 1.5; }
.wpt__eta {
  display: inline-block; margin-top: var(--s2);
  font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--ink-faint);
  border-top: 1px solid var(--rule-soft); padding-top: 6px;
}

/* --- 14. Capability index (custom build work) --------------------------- */

.cap__row {
  position: relative;
  display: grid;
  grid-template-columns: 62px minmax(0, 1fr) minmax(0, 1.05fr);
  gap: var(--s4);
  align-items: baseline;
  padding: clamp(var(--s3), 2vw, var(--s4)) 0;
  border-bottom: 1px solid var(--rule);
}
.cap__row:first-child { border-top: 1px solid var(--rule); }
.cap__row::before {
  content: ""; position: absolute; inset: -1px 0;
  background: rgba(255, 106, 77, 0.06);
  transform: scaleX(0); transform-origin: left;
  transition: transform 0.5s var(--ease-snap);
}
.cap__row:hover::before { transform: scaleX(1); }
.cap__row:hover .cap__idx { transform: translateX(6px); }
.cap__row > * { position: relative; }
@media (max-width: 900px) { .cap__row { grid-template-columns: 44px minmax(0,1fr); gap: var(--s2); }
  .cap__row .cap__note { grid-column: 2; } }

.cap__idx {
  font-family: var(--mono); font-size: 11px; color: var(--ink-faint); letter-spacing: 0.12em;
  transition: color 0.3s var(--ease), transform 0.4s var(--ease);
}
.cap__row:hover .cap__idx { color: var(--coral); }
.cap__name {
  font-family: var(--face); font-weight: 600;
  font-size: clamp(17px, 1.35vw, 25px); line-height: 1.2; color: var(--ink);
}
.cap__note {
  font-size: 14.5px; color: var(--ink-muted); font-weight: 300; line-height: 1.55;
  transition: color 0.3s var(--ease);
}
.cap__row:hover .cap__note { color: var(--ink); }

/* --- 15. Comms panel (contact) ------------------------------------------ */

.comms {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.8fr);
  gap: clamp(var(--s5), 5vw, var(--s7));
  align-items: start;
}
@media (max-width: 1000px) { .comms { grid-template-columns: 1fr; } }

.freq {
  display: block;
  border: 1px solid var(--rule);
  padding: var(--s3);
  margin-bottom: var(--s2);
  transition: border-color 0.35s var(--ease), background 0.35s var(--ease);
}
.freq:hover { border-color: var(--cyan); background: rgba(0, 229, 255, 0.05); }
.freq__k {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--ink-faint); display: block; margin-bottom: 7px;
}
.freq__v {
  font-family: var(--mono); font-size: clamp(15px, 1.3vw, 21px);
  color: var(--white); letter-spacing: 0.02em;
  word-break: break-word;
}
.freq:hover .freq__v { color: var(--cyan); }

/* Typed out on first reveal. The value is monospace, so stepping a clip across
   the element's own width lands exactly on character boundaries — and because
   nothing touches the text itself, it stays selectable, copyable, and readable
   to a screen reader from the first frame. Letter-spacing is zeroed here so the
   caret's ch-based travel matches the clip's steps. The hidden state lives in
   the keyframes under a "both" fill rather than in a base rule: if anything
   about the animation fails to apply, the address is simply there. */
.type {
  display: inline-block; position: relative;
  white-space: nowrap; letter-spacing: 0;
}
.js .rv.is-in .type {
  animation: type-in var(--dur) steps(var(--chars)) var(--delay) both;
}
@keyframes type-in {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

.js .type::after {
  content: ""; position: absolute; left: 0; top: 0.1em;
  width: 2px; height: 1em; background: var(--cyan);
  opacity: 0; pointer-events: none;
}
.js .rv.is-in .type::after {
  animation: caret-run var(--dur) steps(var(--chars)) var(--delay) both,
             caret-out calc(var(--dur) + 0.5s) linear var(--delay) forwards;
}
@keyframes caret-run {
  from { transform: translateX(0); }
  to   { transform: translateX(calc(var(--chars) * 1ch)); }
}
@keyframes caret-out {
  0%, 88% { opacity: 1; }
  100%    { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .js .rv.is-in .type { animation: none; }
  .js .type::after { display: none; }
}

.placeholder {
  display: inline-block;
  font-family: var(--mono); font-size: 10.5px; font-weight: 500;
  letter-spacing: 0.12em; text-transform: uppercase;
  background: rgba(255, 106, 77, 0.16);
  border: 1px dashed rgba(255, 106, 77, 0.6);
  color: var(--coral);
  padding: 3px 8px; margin-left: var(--s1);
  vertical-align: middle;
}

/* --- 16. Footer (the tail) ---------------------------------------------- */

/* The footer drops below the page ground so the scroll lands on a floor
   rather than trailing off. */
.tail {
  border-top: 1px solid var(--rule);
  padding-block: var(--s6) var(--s4);
  position: relative;
  background: var(--black);
  overflow: hidden;
}
.tail > .shell { position: relative; z-index: 1; }

.tail__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) repeat(3, minmax(0, 1fr));
  gap: var(--s5);
  padding-bottom: var(--s6);
}
@media (max-width: 1000px) { .tail__grid { grid-template-columns: 1fr 1fr; gap: var(--s4); } }
@media (max-width: 560px)  { .tail__grid { grid-template-columns: 1fr; } }

/* The footer wordmark is assembled the same way as the hero's: the body
   carries the letters, the bars layer carries the coral and blue strokes that
   complete the E's, and they beam in when the footer comes into view. */
.tail__mark {
  position: relative; display: block;
  width: 190px; margin-bottom: var(--s3);
  opacity: 0.94;
}
.tail__logo { display: block; width: 100%; height: auto; }
.tail__bars { position: absolute; inset: 0; width: 100%; height: auto; }
/* .rv--still borrows the reveal observer's is-in without its fade, so the
   footer keeps arriving as one solid block and only the bars move. */
.js .rv--still { opacity: 1; transform: none; }
.js .tail__bars { opacity: 0; }
.js .rv--still.is-in .tail__bars { animation: bars-beam 0.72s var(--ease-snap) 0.3s both; }
@media (prefers-reduced-motion: reduce) {
  .js .tail__bars { opacity: 1; }
}

.tail__col h3 {
  font-family: var(--mono); font-size: 9.5px; font-weight: 500;
  letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--ink-muted); margin-bottom: var(--s2);
  padding-bottom: var(--s1); border-bottom: 1px solid var(--rule-soft);
}
.tail__col li { margin-bottom: 11px; }
/* Brought up to --ink-mid rather than pure white: the links read crisp, and
   the cyan hover still has somewhere brighter to go. */
.tail__col a {
  font-size: 14px; color: var(--ink-mid); font-weight: 400;
  transition: color 0.25s var(--ease);
  display: inline-flex; align-items: center; gap: 7px;
}
.tail__col a:hover { color: var(--cyan); }
.tail__col a[aria-disabled="true"] { color: var(--ink-faint); cursor: default; }

.tail__bar {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--s2);
  padding-top: var(--s3);
  border-top: 1px solid var(--rule-soft);
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-muted);
}
.tail__bar b { color: var(--ink-mid); font-weight: 400; }

/* --- 17. Boot sequence -------------------------------------------------- */

.boot {
  position: fixed; inset: 0; z-index: 200;
  background: radial-gradient(120% 100% at 50% 50%, #0A0F1C 0%, #04070D 100%);
  display: none;
  place-items: center;
  overflow: hidden;
}
.js .boot { display: grid; }
.boot.is-out {
  animation: boot-out 0.75s var(--ease-snap) forwards;
  pointer-events: none;
}
@keyframes boot-out {
  to { opacity: 0; transform: scale(1.05); visibility: hidden; }
}

.boot__inner {
  position: relative; z-index: 2;
  width: min(560px, 82vw);
  display: flex; flex-direction: column; align-items: center;
  gap: var(--s3);
}

/* Power-on sweep */
.boot__sweep {
  position: absolute; left: 0; right: 0; top: 0; height: 2px; z-index: 3;
  background: linear-gradient(90deg, transparent, var(--cyan), transparent);
  box-shadow: 0 0 26px 4px rgba(0, 229, 255, 0.6);
  animation: sweep 1.05s var(--ease) 1 both;
}
@keyframes sweep {
  0%   { top: 0; opacity: 0; }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { top: 100%; opacity: 0; }
}

.boot__logo {
  width: min(400px, 68vw);
  /* revealed by a wiping mask — the logo file itself is untouched */
  -webkit-mask-image: linear-gradient(100deg, #000 0 33%, rgba(0,0,0,0.25) 42%, transparent 50%);
          mask-image: linear-gradient(100deg, #000 0 33%, rgba(0,0,0,0.25) 42%, transparent 50%);
  -webkit-mask-size: 300% 100%;
          mask-size: 300% 100%;
  -webkit-mask-position: 100% 0;
          mask-position: 100% 0;
  animation: logo-scan 1.35s var(--ease) 0.42s both;
  filter: drop-shadow(0 0 30px rgba(0, 102, 255, 0.5));
}
@keyframes logo-scan {
  0%   { -webkit-mask-position: 100% 0; mask-position: 100% 0; opacity: 0.2; }
  100% { -webkit-mask-position: 0% 0;   mask-position: 0% 0;   opacity: 1; }
}

.boot__hdg {
  font-family: var(--mono); font-weight: 700;
  font-size: clamp(38px, 6vw, 74px);
  letter-spacing: 0.14em;
  color: var(--cyan);
  text-shadow: 0 0 34px rgba(0, 229, 255, 0.55);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.boot__hdg sup {
  font-size: 0.3em; vertical-align: super;
  color: var(--ink-faint); letter-spacing: 0.2em; margin-left: 0.35em;
}

.boot__log {
  width: 100%;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.1em;
  color: var(--ink-faint); text-transform: uppercase;
  min-height: 104px;
}
.boot__log li {
  display: flex; justify-content: space-between; gap: var(--s2);
  padding: 3px 0;
  opacity: 0;
  border-bottom: 1px solid rgba(255,255,255,0.03);
}
.boot__log li.is-in { opacity: 1; transition: opacity 0.2s linear; }
.boot__log li b { color: var(--cyan); font-weight: 500; }
.boot__log li i { color: var(--coral); font-style: normal; }

.boot__bar {
  width: 100%; height: 2px; background: var(--ink-ghost); overflow: hidden;
}
.boot__bar span {
  display: block; height: 100%; width: 100%;
  background: linear-gradient(90deg, var(--blue), var(--cyan));
  box-shadow: 0 0 12px rgba(0,229,255,0.8);
  transform: scaleX(0); transform-origin: left;
  transition: transform 0.14s linear;
}

.boot__skip {
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.22em;
  text-transform: uppercase; color: var(--ink-ghost);
  padding: var(--s1) var(--s2);
  transition: color 0.3s var(--ease);
}
.boot__skip:hover { color: var(--cyan); }

/* --- 18. Reveal on scroll ------------------------------------------------ */

.js .rv { opacity: 0; transform: translateY(22px); }
.js .rv.is-in {
  opacity: 1; transform: none;
  transition: opacity 0.75s var(--ease), transform 0.75s var(--ease);
}
/* A transform makes an element the containing block for its absolutely
   positioned descendants, which would anchor the section's channel tag to this
   wrapper instead of to the section. Those wrappers fade without moving. */
.js .rv:has(> .sect-head__num) { transform: none; }

.js .rv-d1.is-in { transition-delay: 0.07s; }
.js .rv-d2.is-in { transition-delay: 0.14s; }
.js .rv-d3.is-in { transition-delay: 0.21s; }
.js .rv-d4.is-in { transition-delay: 0.28s; }

/* --- 19. Sub-page hero (app pages, legal pages) -------------------------- */

.sub {
  position: relative;
  padding-top: calc(var(--deck-h) + clamp(var(--s6), 8vw, var(--s8)));
  padding-bottom: clamp(var(--s5), 5vw, var(--s7));
  border-bottom: 1px solid var(--rule);
  overflow: hidden;
}
.sub::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(90% 130% at 76% 0%, rgba(0, 102, 255, 0.17) 0%, transparent 62%),
    repeating-linear-gradient(90deg, rgba(166,178,195,0.045) 0 1px, transparent 1px 88px);
}
/* The signature terrain carries onto sub-pages, shorter and further back so it
   never competes with the page it is heading. */
.sub__svt {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%;
  opacity: 0.40;
  /* Fade in from the top so the horizon never cuts across the page title,
     and out at the foot so it hands over to the ground cleanly. */
  mask-image: linear-gradient(180deg, transparent 0%, #000 58%, #000 80%, transparent 99%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 58%, #000 80%, transparent 99%);
}

.sub__grid {
  display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.75fr);
  gap: var(--s6); align-items: end;
}
@media (max-width: 1000px) { .sub__grid { grid-template-columns: 1fr; gap: var(--s4); } }

.sub__title {
  font-family: var(--display);
  font-size: clamp(34px, 5vw, 96px);
  line-height: 0.96; text-transform: uppercase;
  letter-spacing: -0.005em;
  margin: var(--s3) 0 var(--s3);
}

/* System page header: icon in its own column, title sized so a three-word app
   name does not wrap into the icon. */
.sys-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: clamp(var(--s2), 1.7vw, var(--s4));
  align-items: center;
  margin-top: var(--s4);
}
.sys-head__icon {
  width: clamp(60px, 6.2vw, 108px);
  aspect-ratio: 1 / 1;
  border-radius: 23%;
  box-shadow: 0 16px 54px rgba(0, 0, 0, 0.66);
}
/* Sized so the longest app name — SHIPPING RULES AI — holds one line beside
   the icon at desktop widths. Michroma is very wide; 64px overflowed. */
.sys-head .sub__title {
  font-size: clamp(25px, 2.75vw, 52px);
  margin: 0;
}
@media (max-width: 560px) {
  .sys-head { grid-template-columns: 1fr; gap: var(--s2); }
}

.crumb {
  display: flex; align-items: center; gap: var(--s1);
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--ink-faint);
}
.crumb a:hover { color: var(--cyan); }

/* --- 20. Prose (legal pages) -------------------------------------------- */

.prose { max-width: 74ch; }
.prose h2 {
  font-family: var(--display); font-size: clamp(19px, 1.7vw, 27px);
  text-transform: uppercase; letter-spacing: 0.01em; line-height: 1.15;
  margin: var(--s6) 0 var(--s2);
  padding-top: var(--s3); border-top: 1px solid var(--rule);
}
.prose h2:first-child { margin-top: 0; border-top: 0; padding-top: 0; }
.prose h3 {
  font-family: var(--face); font-weight: 600; font-size: 17px;
  margin: var(--s4) 0 var(--s1);
}
.prose p { margin-bottom: var(--s2); color: var(--ink-muted); font-weight: 300; }
.prose ul { margin: 0 0 var(--s3); padding-left: var(--s3); }
.prose li {
  position: relative; margin-bottom: 10px;
  color: var(--ink-muted); font-weight: 300;
  list-style: none;
}
.prose li::before {
  content: ""; position: absolute; left: calc(var(--s3) * -1); top: 0.62em;
  width: 6px; height: 1px; background: var(--coral);
}
.prose a { color: var(--cyan); border-bottom: 1px solid var(--rule-cyan); }
.prose a:hover { border-bottom-color: var(--cyan); }
.prose strong { color: var(--ink); font-weight: 600; }

.draft {
  border: 1px dashed rgba(255, 106, 77, 0.45);
  background: rgba(255, 106, 77, 0.06);
  padding: var(--s3);
  margin-bottom: var(--s5);
}
.draft p { color: var(--ink-mid); margin: 0; font-size: 14.5px; }

/* --- 20b. Section grounds ------------------------------------------------ */

/* Wells sit one step below the navy ground so a section reads as recessed
   panel rather than as a coloured band. */
.sect--well {
  background: var(--well);
  box-shadow: inset 0 1px 0 rgba(166,178,195,0.05);
}
.sect--well::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(80% 100% at 82% 0%, rgba(0,102,255,0.09) 0%, transparent 62%);
}
.sect--well > * { position: relative; }

/* Faint instrument grid on every section, so the page always sits on structure */
.sect::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image: repeating-linear-gradient(90deg,
    rgba(166,178,195,0.035) 0 1px, transparent 1px 132px);
  mask-image: linear-gradient(180deg, #000 0%, transparent 42%);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, transparent 42%);
}
.sect > * { position: relative; z-index: 1; }

/* --- 20c. Readout cluster ------------------------------------------------ */

.rdo {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border: 1px solid var(--rule-soft);
  border-top: 0;
  background: rgba(6, 10, 19, 0.62);
}
.rdo__cell {
  padding: var(--s2) var(--s2) 13px;
  border-right: 1px solid var(--rule-soft);
  display: flex; flex-direction: column; gap: 7px;
}
.rdo__cell:last-child { border-right: 0; }
.rdo__cell b {
  font-family: var(--mono); font-weight: 500;
  font-size: clamp(14px, 1vw, 18px);
  letter-spacing: 0.09em; color: var(--cyan);
}

.panel--chat { padding-top: clamp(var(--s4), 3vw, var(--s5)); }

/* --- 20d. Hero mark, breathing --------------------------------------- */

.adi__mark {
  animation: mark-breathe 7s var(--ease) infinite;
}
@keyframes mark-breathe {
  0%, 100% { filter: drop-shadow(0 0 34px rgba(0, 102, 255, 0.34)); }
  50%      { filter: drop-shadow(0 0 58px rgba(0, 229, 255, 0.44)); }
}

/* --- 20e. Page grain ----------------------------------------------------- */

body::before {
  content: ""; position: fixed; inset: 0; z-index: 100;
  pointer-events: none; opacity: 0.30;
  background-image: 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.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.35'/%3E%3C/svg%3E");
}

/* --- 20f. Mobile navigation ---------------------------------------------- */

/* The deck's links are hidden under 860px, so the same links are rebuilt as a
   disclosure panel by site.js. Nothing here needs per-page markup. */
.deck__menu {
  display: none;
  align-items: center; gap: 9px;
  font-family: var(--mono); font-size: 10px; font-weight: 500;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--ink-mid);
  border: 1px solid var(--rule-hard);
  padding: 11px 14px;
  transition: color 0.25s var(--ease), background 0.25s var(--ease), border-color 0.25s var(--ease);
  clip-path: polygon(0 0, calc(100% - 8px) 0, 100% 8px, 100% 100%, 8px 100%, 0 calc(100% - 8px));
}
@media (max-width: 860px) { .deck__menu { display: inline-flex; } }
.deck__menu i {
  display: block; width: 14px; height: 1px; background: currentColor;
  box-shadow: 0 4px 0 currentColor, 0 -4px 0 currentColor;
}
.deck__menu[aria-expanded="true"] {
  color: var(--black); background: var(--cyan); border-color: var(--cyan);
}

.mnav {
  position: fixed; inset: var(--deck-h) 0 auto 0; z-index: 79;
  background: rgba(6, 10, 19, 0.985);
  backdrop-filter: blur(22px) saturate(120%);
  -webkit-backdrop-filter: blur(22px) saturate(120%);
  border-bottom: 1px solid var(--rule);
  display: none;
  flex-direction: column;
  padding: var(--s1) var(--gutter) var(--s3);
}
.mnav.is-open { display: flex; }
.mnav a {
  display: flex; justify-content: space-between; align-items: center;
  font-family: var(--face); font-weight: 600;
  font-size: 19px; letter-spacing: 0.005em;
  padding: 16px 0;
  border-bottom: 1px solid var(--rule-soft);
  color: var(--ink-mid);
}
.mnav a:last-child { border-bottom: 0; }
.mnav a::after {
  content: "\203A"; font-family: var(--mono); font-size: 17px; color: var(--cyan);
}
.mnav a:hover { color: var(--white); }

/* --- 20g. Truth markers -------------------------------------------------- */

/* A demonstration panel must never wear the livery of a live one. Outlined
   rather than filled: coral is the single caution signal, and a filled chip
   here out-shouted the LAUNCHING lamp it shares the screen with. */
.panel__tag--sim {
  background: rgba(255, 106, 77, 0.10);
  color: var(--coral);
  border: 1px solid rgba(255, 106, 77, 0.55);
  border-top: 0; border-left: 0;
}

/* An address the client has not confirmed does not get a working mailto. */
.freq--pending {
  border-style: dashed;
  border-color: rgba(255, 106, 77, 0.42);
  cursor: default;
}
.freq--pending .freq__v { color: var(--ink-mid); }
.freq--pending:hover { border-color: rgba(255, 106, 77, 0.42); background: none; }
.freq--pending:hover .freq__v { color: var(--ink-mid); }

/* --- 24. Contact form --------------------------------------------------- */
/* The first real inputs in the system, so they are built from the parts that
   already exist rather than from browser defaults: the frequency card's mono
   label, the same 12px chamfer, the well for a recessed ground, and cyan to
   mark the live field. */

.form { display: grid; gap: var(--s3); }
.form__row { display: grid; gap: 8px; }
.form__row--pair {
  grid-template-columns: 1fr 1fr; gap: var(--s3);
}
@media (max-width: 640px) { .form__row--pair { grid-template-columns: 1fr; } }

.form__k {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--ink-faint);
}
.form__k b { color: var(--coral); font-weight: 400; }

.form__in {
  width: 100%;
  font-family: var(--face); font-size: 15px; font-weight: 300;
  color: var(--white);
  background: var(--well);
  border: 1px solid var(--rule);
  padding: 13px var(--s2);
  clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 12px,
                     100% 100%, 12px 100%, 0 calc(100% - 12px));
  transition: border-color 0.3s var(--ease), background 0.3s var(--ease);
  outline: none;
}
.form__in::placeholder { color: var(--ink-ornament); }
.form__in:hover { border-color: var(--rule-hard); }
.form__in:focus {
  border-color: var(--cyan);
  background: rgba(0, 229, 255, 0.04);
}
/* The clip eats an outline, so the focus ring is the border plus a bloom.
   Both are visible with forced colours off; :focus-visible keeps it off mouse
   clicks where the caret already says where you are. */
.form__in:focus-visible { box-shadow: 0 0 22px rgba(0, 229, 255, 0.22); }
textarea.form__in { resize: vertical; min-height: 170px; line-height: 1.6; }
select.form__in { appearance: none; cursor: pointer; }

/* Off-screen rather than display:none — a bot reading the DOM sees a normal
   field, while nobody using the page ever reaches it. */
.form__trap {
  position: absolute; left: -9999px; width: 1px; height: 1px;
  overflow: hidden;
}

.form__foot {
  display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap;
}
.form__fine { font-size: 12.5px; color: var(--ink-faint); font-weight: 300; }

.form__msg {
  display: none;
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.06em;
  padding: 12px var(--s2);
  border: 1px solid var(--rule);
  clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 10px,
                     100% 100%, 10px 100%, 0 calc(100% - 10px));
}
.form__msg.is-on { display: block; }
.form__msg--ok {
  color: var(--cyan);
  border-color: rgba(0, 229, 255, 0.45);
  background: rgba(0, 229, 255, 0.07);
}
.form__msg--bad {
  color: var(--coral);
  border-color: rgba(255, 106, 77, 0.45);
  background: rgba(255, 106, 77, 0.07);
}

.form button[disabled] { opacity: 0.5; pointer-events: none; }

/* Two columns on wide screens: the form carries the weight, the direct routes
   sit beside it for anyone who would rather not type into a box. */
.reach {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: clamp(var(--s4), 5vw, var(--s6));
  align-items: start;
}
@media (max-width: 1000px) { .reach { grid-template-columns: 1fr; } }

.freq {
  clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 12px, 100% 100%, 12px 100%, 0 calc(100% - 12px));
}

/* --- 20h. Capability rows: instrument geometry --------------------------- */

/* Section 04 was plain text on empty ground. It now carries the same lamp and
   column-rule language as the systems index above it. */
/* Rows carrying an icon widen to a four-column grid; rows without one keep
   the plain three-column form used on the app pages. */
.cap__row--ico { grid-template-columns: 52px 46px minmax(0, 1fr) minmax(0, 1.05fr); }
@media (max-width: 900px) {
  .cap__row--ico { grid-template-columns: 40px 40px minmax(0, 1fr); }
  .cap__row--ico .cap__note { grid-column: 3; }
}

.cap__ico { width: 40px; height: 40px; display: block; align-self: center; }
.cap__ico .ln {
  fill: none; stroke: var(--blue); stroke-width: 1.5;
  stroke-linecap: square; stroke-linejoin: miter;
  transition: stroke 0.45s var(--ease);
}
.cap__ico .sig {
  fill: none; stroke: var(--coral); stroke-width: 1.5;
  stroke-linecap: square;
}
.cap__ico .dot { fill: var(--ink-ghost); transition: fill 0.45s var(--ease); }
.cap__row.is-lit .cap__ico .dot { fill: var(--cyan); }
.cap__row:hover .cap__ico .ln { stroke: var(--cyan); }

@media (min-width: 901px) {
  .cap__note { border-left: 1px solid var(--rule-soft); padding-left: var(--s4); }
}

/* --- 20k. Quiet wave field ----------------------------------------------- */

.sect__wave {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  opacity: 0.62;
  mask-image: linear-gradient(180deg, transparent 0%, #000 26%, #000 68%, transparent 100%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 26%, #000 68%, transparent 100%);
}

/* --- 20i. Raked light field ---------------------------------------------- */

/* Converging beams — the real asset from the brand's own CTA band. Beams cross
   in both directions at 45 degrees, hairline at 0.5px, in blue, teal and cyan.
   The baked ground rect was stripped from the file so it composites onto
   whatever page ground is beneath it. This belongs to the comms band only;
   the footer below stays solid so the page still lands on a floor. */
/* Grounded a step below the page so the beams read as light on dark, the way
   they do on the brand's own CTA band. The footer below goes deeper again, so
   the two bands stay distinct. */
/* Shorter than a content section: it holds a heading and one address, so the
   full section rhythm left it standing half empty. */
.sect--rake {
  overflow: hidden;
  background: var(--well);
  padding-block: clamp(var(--s6), 5.5vw, var(--s8));
}
.sect--rake .comms { align-items: center; }
/* No static lattice: the band starts blank and the beams draw it. */
.rake-beams {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  overflow: hidden;
}
.sect > .rake-beams { z-index: 0; }
.rake-beams path {
  fill: none;
  stroke-linecap: round;
  stroke-dashoffset: 4910;              /* nothing drawn, nothing lit */
  animation-timing-function: linear;
  animation-play-state: paused;         /* until the band is on screen */
}
.rake-beams.is-drawing path { animation-play-state: running; }

/* The line itself: laid down once by the pulse, then it stays. */
.beam-trail {
  animation-name: beam-run;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}
/* The travelling light: one pass only. Once it has drawn its line it leaves
   and does not come back — the band settles into a finished lattice rather
   than pulsing at the reader forever. */
.beam-pulse {
  animation-name: beam-pass;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}

/* One full traverse: the beams are 3160 units on each axis, so 4468 along
   their own length, plus the dash and its gap. */
@keyframes beam-run {
  from { stroke-dashoffset: 4910; }
  to   { stroke-dashoffset: 0; }
}
/* Stops at 320, not 0. The dash pattern repeats every 4910, so at offset 0 the
   next dash is already sitting at the head of the path — the pulse would
   freeze visible at the start of its own line. Between 210 and 442 no part of
   the pattern touches the path, so 320 parks it genuinely off-screen. */
@keyframes beam-pass {
  from { stroke-dashoffset: 4910; }
  to   { stroke-dashoffset: 320; }
}

/* Motion off: show the finished lattice, skip the drawing. */
.rake-beams.is-drawn .beam-trail { stroke-dashoffset: 0; }
.rake-beams.is-drawn .beam-pulse { display: none; }
@media (prefers-reduced-motion: reduce) {
  .rake-beams { display: none; }
}

/* --- 20j. Compass -------------------------------------------------------- */

/* The plate is the whole section, so it carries only breathing room. */
.sect--plate { padding-block: clamp(var(--s5), 4vw, var(--s6)); }

.cmp__copy .sect-head__num {
  position: static; display: block; margin-bottom: var(--s2);
}

/* The photograph runs at its own full size, which is how it was composed —
   instrument right, open dark field left. The copy sits in that field rather
   than stacking underneath, so the section is one band and no taller.
   Two stacked frames of identical intrinsic size: the dial with the needle
   removed, and the needle composited so its pivot sits on the dial's. Both are
   width:100%/height:auto, so a percentage transform-origin lands on the pivot. */
.cmp {
  position: relative;
  width: 100%;
  overflow: hidden;
}
/* Nudged right to open up the gap between the instrument and the copy. The
   perspective lives here rather than on .cmp so it still reaches the needle,
   which is now a grandchild. */
.cmp__plate {
  position: relative;
  /* Sized so the whole instrument clears the viewport with dark field around
     it, the way the photograph was composed. At full band width the frame
     stands 1072px tall against an 855px screen, so the compass was always
     cropped top and bottom — which is what read as oversized. */
  width: 85%;
  margin-left: auto;
  transform: translateX(2%);
  perspective: 1500px;
  perspective-origin: 56.70% 45.38%;
}
@media (max-width: 950px) {
  .cmp__plate { width: 100%; margin-left: 0; transform: none; }
}
.cmp__base { display: block; width: 100%; height: auto; }
.cmp__needle {
  position: absolute; inset: 0;
  width: 100%; height: auto;
  /* The dial's own centre, found from the tick ring rather than from the
     needle sprite: the red N/S ticks bracket 185–669 and the blue E/W ticks
     657–1239, putting the pivot at 948,427 of the 1672x941 frame. */
  transform-origin: 56.70% 45.38%;
  transform-style: preserve-3d;
  will-change: transform;
  backface-visibility: hidden;
  /* The needle was keyed off its own shadow, so it sat on the dial with
     nothing under it. Light in the photograph comes from the upper left. Two
     layers: a tight one that reads as contact with the dial face, and a wide
     soft one for the ambient occlusion under a raised object. One layer alone
     reads as a glow rather than as something resting on a surface.

     Offsets are in vw, not px. The plate runs full-bleed, so the needle paints
     at around 2100px on a desktop viewport — offsets sized against the source
     frame's 1672px vanish at that scale, which is exactly what the first
     attempt did. And the shadow has to be this opaque to register at all: the
     dial face it falls on is already near-black. */
  filter: drop-shadow(0.62vw 0.30vw 0.10vw rgba(0, 0, 0, 0.92))
          drop-shadow(1.45vw 0.70vw 0.50vw rgba(0, 0, 0, 0.62));
}

/* Just enough scrim to hold type over the photograph's own darkness. */
.cmp::before {
  content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: linear-gradient(90deg,
    rgba(2,4,12,0.92) 0%, rgba(2,4,12,0.74) 26%, rgba(2,4,12,0.22) 44%, transparent 58%);
}
/* Feather the top and foot so the plate joins the page ground. */
.cmp::after {
  content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: linear-gradient(180deg,
    var(--ground) 0%, rgba(2,4,12,0) 14%, rgba(2,4,12,0) 84%, var(--ground) 100%);
}

.cmp__copy {
  position: absolute; z-index: 3;
  left: calc(var(--gutter) + var(--rail-w));
  top: 50%; transform: translateY(-50%);
  /* Wide enough that "WHY 045" plus its dash holds one line. Michroma runs
     about 0.85em per glyph, so the heading needs ~418px at its largest and the
     old 44ch cap broke the dash onto a line of its own. */
  width: min(52ch, 46%);
}
.cmp__copy .h-sect { white-space: nowrap; }
/* The 4 carries the blue, the way the wordmark's own accents split cool from
   warm — it leaves the heading reading as the bearing rather than a number. */
.h-blue { font-style: normal; color: var(--blue); }

@media (max-width: 950px) {
  .cmp::before { background: linear-gradient(180deg, rgba(2,4,12,0.2) 0%, rgba(2,4,12,0.9) 72%); }
  .cmp__copy {
    /* `static` would drop the z-index below, and the ::before scrim (z-index 2)
       would then paint over this copy instead of under it — the further down the
       column the text sat, the more of that 0.9-opacity gradient covered it, so
       the heading survived while the equation underneath all but vanished.
       `relative` keeps the box in normal flow and restores the stacking order.
       `top` has to be cleared with it: the desktop rule sets top:50% for the
       absolute centring, which a relative box would apply as a real offset. */
    position: relative; z-index: 3; top: auto;
    transform: none; width: auto;
    padding: var(--s4) var(--gutter) 0;
  }
}

.compass__read {
  font-family: var(--mono); font-weight: 700;
  font-size: clamp(27px, 3vw, 38px);
  letter-spacing: 0.12em;
  color: var(--cyan);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 30px rgba(0, 229, 255, 0.45);
  line-height: 1;
}
.compass__read i { font-style: normal; color: var(--ink-faint); font-size: 0.5em; }

.compass__cap {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.24em;
  text-transform: uppercase; color: var(--ink-faint);
}

/* The origin, set as a readable equation rather than a paragraph. */
.origin {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--s2) var(--s3);
  margin: var(--s4) 0 0;
  padding-top: var(--s3);
  border-top: 1px solid var(--rule);
}
/* Each operator travels with the term it introduces. The row wraps at this
   width, and ungrouped it left an "=" dangling at the end of the first line
   with its value orphaned on the next. */
.origin__pair {
  display: flex; align-items: center; gap: var(--s3);
}
.origin__part {
  display: flex; flex-direction: column; gap: 5px;
}
/* The equation is a single statement and reads as one, so it is allowed to run
   past the copy column into the open field the photograph leaves to the left of
   the instrument: 600px of row against the 852px where the bezel starts. Only
   above the breakpoint — below it the copy is a normal stacked column and the
   row wraps like everything else. */
@media (min-width: 951px) {
  .cmp__copy .origin { width: max-content; max-width: 44vw; }
}
.origin__part b {
  font-family: var(--display); font-size: clamp(16px, 1.4vw, 25px);
  font-weight: 400; color: var(--ink); letter-spacing: 0.01em;
  white-space: nowrap;
}
/* The equation's last value is the live bearing: it rolls while the needle
   is turning and locks when the needle does, so the two agree. */
.origin__part--out b {
  font-family: var(--mono); font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 26px rgba(0, 229, 255, 0.4);
}
.origin__part--out b i { font-style: normal; font-size: 0.55em; color: var(--ink-faint); }
.origin__part span {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--ink-faint);
}
.origin__op {
  font-family: var(--mono); font-size: 17px; color: var(--coral);
  align-self: center; padding-top: 12px;
}
.origin__part--out b { color: var(--cyan); }

/* --- 21. Motion off ------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .js .rv { opacity: 1; transform: none; }
  .msg { opacity: 1; transform: none; }
  .cue__bar { animation: none; }
  .lamp--live .lamp__dot { animation: none; }
}

/* --- 22. Print ----------------------------------------------------------- */

@media print {
  .deck, .rail, .boot, .adi__svt, .adi__glass, .cue { display: none !important; }
  body { background: #fff; color: #000; }
}
