/* ==========================================================================
   Ironvane Media — Design System
   Achromatic, warm-white ink on cold black. Chrome reserved for display type.
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Metric-matched fallbacks
   Google Fonts loads with display:swap, so the page paints in a system face
   first. Overriding that face's metrics to match Manrope / JetBrains Mono
   keeps the swap from shifting the layout.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Manrope Fallback";
  src: local("Arial"), local("Helvetica Neue"), local("Liberation Sans");
  size-adjust: 105%;
  ascent-override: 102%;
  descent-override: 27%;
  line-gap-override: 0%;
}

@font-face {
  font-family: "Mono Fallback";
  src: local("Consolas"), local("DejaVu Sans Mono"), local("Menlo");
  size-adjust: 98%;
  ascent-override: 102%;
  descent-override: 30%;
  line-gap-override: 0%;
}

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

:root {
  /* Surfaces — cold near-black */
  --bg:            #060607;
  --bg-raised:     #0b0b0d;
  --bg-sunken:     #030304;
  --surface-1:     rgba(255, 255, 255, 0.028);
  --surface-2:     rgba(255, 255, 255, 0.048);
  --surface-3:     rgba(255, 255, 255, 0.072);

  /* The lit panel surface, as one recipe in one place. Seven components had
     hand-copied it and drifted to four different alpha pairs (0.055/0.014,
     0.045/0.01, 0.04/0.012, 0.04/0.008) -- differences of five thousandths of
     an alpha step, invisible on screen but guaranteed to keep drifting. The
     0.045/0.01 pair is the one four of them already agreed on. */
  --panel-fill: linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.01));
  /* Accent bloom from the top-right corner. .card deliberately keeps its own
     top-LEFT bloom -- that position is a design decision, not drift. */
  --panel-glow: radial-gradient(90% 70% at 100% 0%, rgba(123, 140, 255, 0.10), transparent 60%);

  /* Ink — warm white against cold ground.
     Four steps, each verified above WCAG AA 4.5:1 on --bg:
     17.8 : 9.3 : 6.3 : 4.7. Hierarchy comes from size and weight, not murk. */
  --ink:           #f2f0ec;
  --ink-2:         rgba(242, 240, 236, 0.72);
  --ink-3:         rgba(242, 240, 236, 0.60);
  --ink-4:         rgba(242, 240, 236, 0.50);
  /* Decorative only — never used for text that carries meaning */
  --ink-dim:       rgba(242, 240, 236, 0.28);

  /* Lines */
  --line:          rgba(242, 240, 236, 0.09);
  --line-2:        rgba(242, 240, 236, 0.16);
  --line-3:        rgba(242, 240, 236, 0.30);

  /* Accent system — used as signal, never as decoration.
     --accent  : interaction, active state, key figures        (6.8:1 on --bg)
     --live    : "running / active / covered" status only     (12.5:1 on --bg)
     Everything else stays achromatic. */
  --accent:        #7b8cff;
  --accent-hi:     #a3b0ff;
  --accent-dim:    rgba(123, 140, 255, 0.15);
  --accent-line:   rgba(123, 140, 255, 0.42);
  --accent-glow:   rgba(123, 140, 255, 0.30);
  --live:          #5fe3a1;
  --live-dim:      rgba(95, 227, 161, 0.16);
  --warn:          #ffcf70;
  --cut:           #ff8f9b;

  /* Type */
  --font-sans: "Manrope", "Manrope Fallback", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: "JetBrains Mono", "Mono Fallback", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --fs-display: clamp(2.85rem, 7.4vw, 6.25rem);
  --fs-h1:      clamp(2.3rem, 5.4vw, 4.4rem);
  --fs-h2:      clamp(1.95rem, 4.1vw, 3.15rem);
  --fs-h3:      clamp(1.3rem, 2.1vw, 1.65rem);
  --fs-h4:      clamp(1.08rem, 1.5vw, 1.24rem);
  --fs-lead:    clamp(1.03rem, 1.15vw, 1.22rem);
  --fs-body:    1rem;
  --fs-sm:      0.9rem;
  --fs-xs:      0.875rem;
  --fs-mono:    0.6875rem;

  --lh-display: 0.92;
  --lh-heading: 1.04;
  --lh-body:    1.65;

  --track-display: -0.038em;
  --track-heading: -0.028em;
  --track-mono:     0.16em;

  /* Layout */
  --container:  1440px;
  --gutter:     clamp(20px, 4.4vw, 64px);
  /* Measured, not guessed: 1ch in Manrope is ~0.6em, so 54ch lands at ~64
     characters per line — inside the 45-75 comfortable reading band. */
  --measure:    54ch;
  --measure-prose: 58ch;
  --radius:     14px;
  --radius-lg:  20px;
  --radius-sm:  8px;

  --section-y:   clamp(5rem, 9.5vw, 9.5rem);
  --section-y-s: clamp(3.5rem, 6vw, 6rem);

  --header-h: 74px;

  /* Motion */
  --ease:      cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in:   cubic-bezier(0.55, 0, 0.35, 1);
  --dur:       0.5s;
  --dur-fast:  0.24s;

  --z-header: 200;
  --z-menu:   300;
  --z-grain:  9999;
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */

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

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 24px);
}

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: 400;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  min-height: 100%;
}

body::before {
  /* Ambient light: a cool source top-right, a warmer neutral top-left.
     Two temperatures stop the page reading as one flat sheet of black. */
  content: "";
  position: fixed;
  inset: -25vh 0 auto 0;
  height: 110vh;
  background:
    radial-gradient(46% 52% at 72% 0%, rgba(123, 140, 255, 0.13) 0%, rgba(123, 140, 255, 0) 70%),
    radial-gradient(52% 55% at 22% 4%, rgba(255, 255, 255, 0.055) 0%, rgba(255, 255, 255, 0) 68%);
  pointer-events: none;
  z-index: 0;
}

img, svg, video, canvas { display: block; max-width: 100%; height: auto; }

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

button, input, select, textarea { font: inherit; color: inherit; }

ul, ol { list-style: none; padding: 0; }

h1, h2, h3, h4, h5, h6 {
  font-weight: 700;
  line-height: var(--lh-heading);
  letter-spacing: var(--track-heading);
  /* Long compounds in RU/UK/CS must break rather than push the page sideways */
  overflow-wrap: break-word;
}

p, li, dd, dt, figcaption, label, td, th { overflow-wrap: break-word; }

strong { font-weight: 700; color: var(--ink); }

::selection { background: var(--ink); color: var(--bg); }

/* Browser surfaces. These are the parts nobody draws, and they ship with
   defaults that belong to no design system: a white caret, a light-grey
   scrollbar and a blue focus ring on a near-black page all announce that the
   page was assembled rather than built. Theming them costs six declarations. */

/* The caret is the only element on the page that is always in motion while a
   visitor types. White is the browser's guess; the accent is the answer. */
html { caret-color: var(--accent); accent-color: var(--accent); }

/* Firefox and modern Chromium take the standard property. */
html {
  scrollbar-color: var(--line-3) transparent;
  scrollbar-width: thin;
}

/* WebKit needs its own surface. Track stays transparent so the scrollbar reads
   as part of the page rather than as a channel cut into it. */
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--line-3);
  border-radius: 999px;
  /* Transparent border plus background-clip keeps the thumb visually thinner
     than its hit area -- easier to grab, quieter to look at. */
  border: 3px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--ink-4); background-clip: content-box; }
::-webkit-scrollbar-corner { background: transparent; }

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

:focus:not(:focus-visible) { outline: none; }

/* Film grain — the whole surface, always */
.grain {
  position: fixed;
  inset: 0;
  z-index: var(--z-grain);
  pointer-events: none;
  opacity: 0.24;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
  background-size: 160px 160px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 10000;
  background: var(--ink);
  color: var(--bg);
  padding: 12px 20px;
  border-radius: 0 0 8px 0;
  font-size: var(--fs-sm);
  font-weight: 600;
}
.skip-link:focus { left: 0; }

/* --------------------------------------------------------------------------
   3. Layout primitives
   -------------------------------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
  position: relative;
  z-index: 1;
}

.section { padding-block: var(--section-y); position: relative; }
.section--tight { padding-block: var(--section-y-s); }
.section--flush-top { padding-top: 0; }
.section--line { border-top: 1px solid var(--line); }

.grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(20px, 2.4vw, 34px);
}

/* Faint engineering rules behind selected sections */
.ruled { position: relative; }
.ruled::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: calc(100% / 6) 100%;
  opacity: 0.5;
  mask-image: linear-gradient(180deg, transparent, #000 12%, #000 88%, transparent);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 12%, #000 88%, transparent);
}

/* --------------------------------------------------------------------------
   4. Typography helpers
   -------------------------------------------------------------------------- */

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  font-weight: 500;
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
}
.eyebrow::before {
  content: "";
  width: 5px;
  height: 5px;
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim);
  transform: rotate(45deg);
  flex: none;
}

.display {
  font-size: var(--fs-display);
  line-height: var(--lh-display);
  letter-spacing: var(--track-display);
  font-weight: 800;
}

.h1 { font-size: var(--fs-h1); letter-spacing: var(--track-display); font-weight: 800; line-height: 1.0; }
.h2 { font-size: var(--fs-h2); font-weight: 800; }
.h3 { font-size: var(--fs-h3); font-weight: 700; }
.h4 { font-size: var(--fs-h4); font-weight: 700; letter-spacing: -0.015em; }

.lead {
  font-size: var(--fs-lead);
  line-height: 1.58;
  color: var(--ink-2);
  max-width: var(--measure);
  font-weight: 400;
}

.body-text { color: var(--ink-2); max-width: var(--measure); }
.body-text + .body-text { margin-top: 1.1em; }

.mono {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 500;
}

.num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* Solid ink, not a gradient. A painted headline borrows emphasis it has not
   earned; at 800 weight and 71px this line already outranks everything around
   it, and the chrome ramp dimmed to #8f949d exactly where the type was largest. */
.chrome-text {
  color: var(--ink);
}

.muted { color: var(--ink-3); }
.balance { text-wrap: balance; }
.pretty { text-wrap: pretty; }

/* Section header block */
.section-head { display: flex; flex-direction: column; gap: clamp(16px, 1.8vw, 22px); }
.section-head .h2 { max-width: 20ch; }
.section-head__row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(24px, 5vw, 80px);
  flex-wrap: wrap;
}

/* --------------------------------------------------------------------------
   5. Buttons & links
   -------------------------------------------------------------------------- */

.btn {
  --btn-pad-y: 0.95rem;
  --btn-pad-x: 1.6rem;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.7em;
  padding: var(--btn-pad-y) var(--btn-pad-x);
  border-radius: 999px;
  border: 1px solid transparent;
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: -0.005em;
  line-height: 1;
  cursor: pointer;
  overflow: hidden;
  white-space: nowrap;
  transition: transform var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
  isolation: isolate;
}
.btn:active { transform: translateY(1px); }

.btn__icon { flex: none; transition: transform var(--dur) var(--ease); }
.btn:hover .btn__icon { transform: translateX(3px); }

/* ---------------------------------------------- The primary button, in metal

   A dark face inside a living chrome rim. The metal is not borrowed: those
   four stops are the brand mark own gradient (Logo-Mark in build/lib.ps1), so
   the button is made of the same material as the logo rather than of a look
   imported from somewhere else.

   One thing from the reference is deliberately not copied: its label is
   #666666 on near-black, which is nowhere near AA. Every text role on this
   site is verified against the page ground, and a CTA is the last place to
   start making exceptions. The engraved feel comes from the shadow instead. */

@property --metal-angle {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}

.btn--primary {
  background: linear-gradient(180deg, #212127 0%, #0b0b0d 100%);
  color: var(--ink);
  border-color: transparent;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
  /* Depth, not a halo: every layer is offset downward, so this is a shadow the
     object casts rather than a glow it emits. */
  box-shadow:
    0 18px 14px -12px rgba(0, 0, 0, 0.55),
    0 8px 8px -6px rgba(0, 0, 0, 0.45),
    0 2px 4px -2px rgba(0, 0, 0, 0.4);
  transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease);
}

/* The rim. A conic sweep of chrome, masked down to a hairline ring. */
.btn--primary::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1.5px;
  background: conic-gradient(from 0deg,
    #ffffff, #82868f, #c9ccd2, #3f424a, #ffffff, #82868f, #c9ccd2, #3f424a, #ffffff);
  background: conic-gradient(from var(--metal-angle),
    #ffffff, #82868f, #c9ccd2, #3f424a, #ffffff, #82868f, #c9ccd2, #3f424a, #ffffff);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  animation: metalTurn 9s linear infinite;
  z-index: -1;
}
@keyframes metalTurn { to { --metal-angle: 360deg; } }

/* The sweep survives, at a tenth of its old strength: at 0.85 over a dark
   face it read as a camera flash rather than as light moving across metal. */
.btn--primary::after {
  content: "";
  position: absolute;
  inset: -40% -10%;
  background: linear-gradient(105deg, transparent 38%, rgba(255, 255, 255, 0.10) 50%, transparent 62%);
  transform: translateX(-120%);
  transition: transform 0.7s var(--ease);
  z-index: -1;
}
.btn--primary:hover::after { transform: translateX(120%); }
.btn--primary:hover {
  /* The rim quickens rather than the face brightening: the material reacts,
     which is the whole idea being borrowed. */
  animation: none;
  box-shadow:
    0 10px 10px -8px rgba(0, 0, 0, 0.5),
    0 4px 5px -3px rgba(0, 0, 0, 0.4),
    0 1px 2px 0 rgba(0, 0, 0, 0.35);
}
.btn--primary:hover::before { animation-duration: 3.4s; }
.btn--primary:active {
  box-shadow:
    inset 0 2px 4px rgba(0, 0, 0, 0.45),
    0 1px 2px rgba(0, 0, 0, 0.3);
}

/* The click ripple, driven from assets/js/main.js. */
.btn__ripple {
  position: absolute;
  width: 20px;
  height: 20px;
  margin: -10px 0 0 -10px;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.42) 0%, rgba(255, 255, 255, 0) 70%);
  animation: btnRipple 0.6s ease-out forwards;
  z-index: 2;
}
@keyframes btnRipple {
  from { transform: scale(0);   opacity: 0.6; }
  to   { transform: scale(9);   opacity: 0; }
}

.btn--ghost {
  background: transparent;
  border-color: var(--line-2);
  color: var(--ink);
}
.btn--ghost:hover { border-color: var(--accent-line); background: var(--accent-dim); }

.btn--sm { --btn-pad-y: 0.7rem; --btn-pad-x: 1.1rem; font-size: var(--fs-xs); }

/* Text link with rule */
.link {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink);
  padding-bottom: 3px;
  position: relative;
}
.link::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: var(--line-2);
  transform-origin: left;
  transition: transform var(--dur) var(--ease), background-color var(--dur) var(--ease);
}
.link:hover::after { background: var(--accent); transform: scaleX(1); }
.link svg { transition: transform var(--dur) var(--ease); }
.link:hover svg { transform: translateX(4px); }

/* --------------------------------------------------------------------------
   6. Header
   -------------------------------------------------------------------------- */

.header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: var(--z-header);
  height: var(--header-h);
  display: flex;
  align-items: center;
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease), backdrop-filter var(--dur) var(--ease);
  border-bottom: 1px solid transparent;
}
.header.is-stuck {
  background: rgba(6, 6, 7, 0.72);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border-bottom-color: var(--line);
}
.header.is-hidden { transform: translateY(-100%); }
.header { transition: transform 0.45s var(--ease), background-color var(--dur) var(--ease), border-color var(--dur) var(--ease); }

.header__inner {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(16px, 3vw, 48px);
}

/* Logo */
.logo {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  flex: none;
}
.logo__mark { width: 22px; height: 22px; flex: none; transition: transform 0.8s var(--ease); }
.logo:hover .logo__mark { transform: rotate(90deg); }
.logo__type {
  display: flex;
  flex-direction: column;
  line-height: 1;
}
.logo__name {
  font-size: 0.815rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.logo__sub {
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-top: 3px;
}

/* Desktop nav */
.nav { display: flex; align-items: center; gap: clamp(4px, 1.1vw, 14px); }
.nav__link {
  position: relative;
  padding: 8px 12px;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--ink-2);
  border-radius: 8px;
  transition: color var(--dur-fast) var(--ease);
  white-space: nowrap;
}
.nav__link::after {
  content: "";
  position: absolute;
  left: 12px; right: 12px; bottom: 2px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.4s var(--ease);
}
.nav__link:hover { color: var(--ink); }
.nav__link:hover::after { transform: scaleX(1); transform-origin: left; }
.nav__link.is-active { color: var(--ink); }
.nav__link.is-active::after { transform: scaleX(1); background: var(--ink-3); }

/* The tube light over the active page.

   A hard 2px bar at the top of the item, and light falling from it downward.
   That direction is the whole of the argument with The No Halo Rule: the rule
   forbids a coloured glow smeared at zero offset around a box, because it is
   decoration with no cause. This has a cause — a source you can point at — and
   the light goes one way, away from it, the way light does.

   The old underline is gone with it. Two marks for one state is one mark too
   many, and the bar says it louder. */

.nav { position: relative; }

.nav__lamp {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 0;
  pointer-events: none;
  opacity: 0;
  border-radius: 9px;
  background: linear-gradient(180deg, rgba(123, 140, 255, 0.11), rgba(123, 140, 255, 0) 78%);
  transform: translateX(0);
  transition:
    transform 0.42s cubic-bezier(0.34, 1.3, 0.5, 1),
    width 0.42s cubic-bezier(0.34, 1.3, 0.5, 1),
    opacity var(--dur-fast) var(--ease);
}
.nav__lamp.is-on { opacity: 1; }

/* The tube itself. */
.nav__lamp::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 50%;
  width: 28px;
  height: 2px;
  margin-left: -14px;
  border-radius: 0 0 3px 3px;
  background: var(--accent);
}

/* What the tube throws. Anchored to the bar and falling away from it, never
   wrapped around the item. */
.nav__lamp::after {
  content: "";
  position: absolute;
  top: -3px;
  left: 50%;
  width: 46px;
  height: 20px;
  margin-left: -23px;
  border-radius: 50%;
  background: radial-gradient(50% 60% at 50% 0%, rgba(123, 140, 255, 0.45), rgba(123, 140, 255, 0) 72%);
  filter: blur(4px);
}

.nav__link { z-index: 1; }
.nav__link.is-active { color: var(--ink); }

/* The underline is retired: the bar above already says which page this is. */
.nav__link::after { content: none; }

@media (prefers-reduced-motion: reduce) {
  /* transition-duration alone leaves the visibility delay in place, so the
     hidden button stays clickable for the length of that delay. */
  html:not(.force-motion) .to-top { transition-delay: 0s !important; }
  html:not(.force-motion) .nav__lamp { transition: opacity 0.001ms !important; }
}

.header__actions { display: flex; align-items: center; gap: 10px; flex: none; }

/* Language switcher */
.lang { position: relative; }
.lang__toggle {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 11px;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 999px;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-2);
  transition: border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.lang__toggle:hover { border-color: var(--line-2); color: var(--ink); }
.lang__toggle svg { transition: transform var(--dur-fast) var(--ease); }
.lang__toggle[aria-expanded="true"] svg { transform: rotate(180deg); }

.lang__menu {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  min-width: 186px;
  padding: 6px;
  background: rgba(11, 11, 13, 0.94);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--line-2);
  border-radius: 12px;
  box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.9);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease), visibility var(--dur-fast);
}
.lang.is-open .lang__menu { opacity: 1; visibility: visible; transform: translateY(0); }

.lang__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 12px;
  border-radius: 8px;
  font-size: var(--fs-sm);
  color: var(--ink-2);
  transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.lang__item:hover { background: var(--surface-2); color: var(--ink); }
.lang__item[aria-current="true"] { color: var(--ink); }
.lang__code {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.12em;
  color: var(--ink-4);
}
.lang__item[aria-current="true"] .lang__code { color: var(--ink-2); }

/* Burger */
.burger {
  display: none;
  width: 42px; height: 42px;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 999px;
  cursor: pointer;
}
.burger__lines { position: relative; width: 16px; height: 10px; }
.burger__lines span {
  position: absolute;
  left: 0;
  width: 100%;
  height: 1.5px;
  background: var(--ink);
  transition: transform var(--dur) var(--ease), opacity var(--dur-fast) var(--ease);
}
.burger__lines span:nth-child(1) { top: 0; }
.burger__lines span:nth-child(2) { bottom: 0; }
body.menu-open .burger__lines span:nth-child(1) { transform: translateY(4.25px) rotate(45deg); }
body.menu-open .burger__lines span:nth-child(2) { transform: translateY(-4.25px) rotate(-45deg); }

/* Mobile menu */
.menu {
  position: fixed;
  inset: 0;
  z-index: var(--z-menu);
  background: var(--bg-sunken);
  display: flex;
  flex-direction: column;
  padding-top: var(--header-h);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.4s var(--ease), visibility 0.4s;
  overflow-y: auto;
  overscroll-behavior: contain;
}
body.menu-open .menu { opacity: 1; visibility: visible; }
body.menu-open { overflow: hidden; }
/* The sent dialog has its own lock. It used to borrow menu-open, which also
   matches the rule above that reveals the full-screen menu -- unconditioned by
   width, so a submission raised the menu over the dialog at every size. */
body.dialog-open { overflow: hidden; }

/* The burger is the only way out of this menu on a touch screen, and the menu
   is opaque and covers the whole viewport -- so at --z-menu it paints over the
   X the burger has just turned into. The header has to outrank the sheet it
   opened for the close control to be seen and hit at all. */
body.menu-open .header { z-index: calc(var(--z-menu) + 1); }

.menu__inner {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding: clamp(28px, 6vw, 48px) var(--gutter) clamp(40px, 8vw, 64px);
  display: flex;
  flex-direction: column;
  gap: clamp(28px, 5vw, 44px);
  flex: 1;
}

.menu__nav { display: flex; flex-direction: column; }
.menu__link {
  display: flex;
  align-items: baseline;
  gap: 16px;
  padding: clamp(14px, 2.6vw, 20px) 0;
  border-bottom: 1px solid var(--line);
  font-size: clamp(1.75rem, 8vw, 2.6rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--ink);
  opacity: 0;
  transform: translateY(14px);
}
body.menu-open .menu__link { animation: menuIn 0.55s var(--ease) forwards; animation-delay: calc(var(--i, 0) * 55ms + 90ms); }
.menu__link .num { font-size: var(--fs-mono); color: var(--ink-4); letter-spacing: 0.1em; }
.menu__link.is-active { color: var(--ink); }
.menu__link.is-active .num { color: var(--ink-2); }

@keyframes menuIn { to { opacity: 1; transform: translateY(0); } }

.menu__foot {
  display: flex;
  flex-direction: column;
  gap: 22px;
  margin-top: auto;
}
.menu__langs { display: flex; flex-wrap: wrap; gap: 8px; }
.menu__lang {
  padding: 9px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  transition: border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.menu__lang:hover { border-color: var(--line-2); color: var(--ink); }
.menu__lang[aria-current="true"] { border-color: var(--line-3); color: var(--ink); }
.menu__contact { display: flex; flex-direction: column; gap: 6px; }
.menu__contact a { font-size: var(--fs-lead); font-weight: 600; }

/* --------------------------------------------------------------------------
   7. Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  padding-top: calc(var(--header-h) + clamp(24px, 3.4vw, 48px));
  padding-bottom: clamp(34px, 4.5vw, 64px);
  overflow: hidden;
}

.hero__eyebrow { margin-bottom: clamp(22px, 3vw, 34px); }

.hero__title {
  font-size: var(--fs-display);
  line-height: var(--lh-display);
  letter-spacing: var(--track-display);
  font-weight: 800;
}
.hero__line { display: block; overflow: hidden; }
.hero__line > span {
  display: block;
  transform: translateY(105%);
  animation: heroLine 1.05s var(--ease) forwards;
  animation-delay: calc(var(--i, 0) * 110ms + 120ms);
}
@keyframes heroLine { to { transform: translateY(0); } }

/* Two columns above the funnel: copy left, the handset right. The single
   column that stood here briefly was the right answer to a different brief --
   this one asks for the device back, so the split comes back with it. */
.hero__grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(28px, 3vw, 48px);
  /* Not centred: the handset is far taller than the copy, and centring both
     left a dead band above the headline and pushed the call to action a full
     screen below the fold on every desktop size measured. */
  align-items: start;
}
.hero__copy { grid-column: 1 / span 7; }
.hero__visual { grid-column: 8 / span 5; }

/* ------------------------------------------------------------- The hero light

   DESIGN.md lists "the hero light" among the system's own graphics; it was cut
   along with the handset on an earlier pass and comes back here, in white.

   White because the palette is achromatic by default and colour is a signal:
   a tinted orb behind the headline would be a third meaning for a system that
   has exactly two. White is not a colour here, it is light.

   Two conic sweeps, not one, turning at different speeds and in opposite
   directions. A single rotating gradient reads as a disc being spun -- the
   thing the reference actually does, and the thing that looks cheap. Two of
   them, blurred into each other, never repeat the same shape, so what the eye
   gets is light moving rather than an element animating.

   On The No Halo Rule: that rule forbids a *coloured* glow at zero offset, and
   a bloom *around a small element* that hides it. This is neither. It is an
   ambient light behind a whole section, and the section is what it is lighting. */

.hero__orb {
  position: absolute;
  top: -28%;
  left: 50%;
  width: min(1500px, 130%);
  aspect-ratio: 1;
  translate: -50% 0;
  pointer-events: none;
  z-index: 0;
  /* No hard edge anywhere: the light stops being light before it reaches a
     boundary the eye could trace. */
  -webkit-mask-image: radial-gradient(closest-side, #000 12%, rgba(0, 0, 0, 0.45) 46%, transparent 74%);
  mask-image: radial-gradient(closest-side, #000 12%, rgba(0, 0, 0, 0.45) 46%, transparent 74%);
  opacity: 0.9;
}

.hero__orb i {
  position: absolute;
  inset: 0;
  display: block;
  border-radius: 50%;
  filter: blur(60px);
}

/* The bed: broad, dim, slow. */
.hero__orb i:first-child {
  background: conic-gradient(
    from 0deg,
    rgba(255, 255, 255, 0.10),
    rgba(255, 255, 255, 0.02) 22%,
    rgba(255, 255, 255, 0.13) 46%,
    rgba(255, 255, 255, 0.01) 68%,
    rgba(255, 255, 255, 0.08) 86%,
    rgba(255, 255, 255, 0.10)
  );
  animation: orbTurn 64s linear infinite;
}

/* The highlight: tighter, brighter, turning the other way, so the two never
   line up twice. */
.hero__orb i:last-child {
  inset: 14%;
  background: conic-gradient(
    from 210deg,
    rgba(255, 255, 255, 0.16),
    rgba(255, 255, 255, 0) 30%,
    rgba(255, 255, 255, 0.11) 55%,
    rgba(255, 255, 255, 0) 78%,
    rgba(255, 255, 255, 0.16)
  );
  filter: blur(48px);
  animation: orbTurn 41s linear infinite reverse;
}

@keyframes orbTurn {
  to { rotate: 360deg; }
}

@media (max-width: 760px) {
  /* Narrower screens get a smaller, calmer version: at full size it washed the
     top of the headline instead of sitting behind it. */
  .hero__orb { top: -14%; width: 150%; opacity: 0.7; }
  .hero__orb i { filter: blur(40px); }
  .hero__orb i:last-child { filter: blur(34px); }
}

/* The cursor spotlight. The half of the reference that is portable: a soft
   light that follows the pointer across the hero. Costs one radial gradient
   and two custom properties, no runtime, no third-party scene. */
.hero {
  --spot-x: 50%;
  --spot-y: 0%;
  --spot-on: 0;
}
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* Above the ambient light, below the content. */
  z-index: 1;
  background: radial-gradient(
    420px circle at var(--spot-x) var(--spot-y),
    rgba(123, 140, 255, 0.13),
    rgba(123, 140, 255, 0.05) 40%,
    transparent 68%
  );
  opacity: var(--spot-on);
  transition: opacity 0.5s var(--ease);
}
.hero > .container { position: relative; z-index: 2; }

/* The scroll cue. The string was translated into all five locales and rendered
   by nothing — found while auditing the finished pages. It earns its place now
   rather than as decoration: the first screen is 1285px tall, the funnel that
   pays the headline off starts below the fold on a 900px display, and nothing
   else on screen says so.

   A hairline with a mark travelling down it, and the label the locales already
   carry. Under reduced motion the mark parks at the top and the line stays. */
.hero__scroll {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-top: clamp(26px, 3.2vw, 40px);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-4);
  user-select: none;
}
.hero__scroll i {
  position: relative;
  display: block;
  width: 1px;
  height: 34px;
  background: var(--line-2);
  overflow: hidden;
}
.hero__scroll i::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 11px;
  background: var(--accent);
  animation: scrollCue 2.6s var(--ease) infinite;
}
@keyframes scrollCue {
  0%        { transform: translateY(-11px); opacity: 0; }
  22%       { opacity: 1; }
  78%       { opacity: 1; }
  100%      { transform: translateY(34px); opacity: 0; }
}

/* Stacked layout puts the handset under the copy, so the cue would point at
   the phone rather than at what is below it. It goes there instead. */
@media (max-width: 1024px) {
  .hero__scroll { display: none; }
}

/* ------------------------------------------------- The proof block

   The spine of the first viewport. It replaced a floating handset whose type
   measured 7-10px at absolute sizes and narrowed to 229px on a phone: the
   vessel fought the content, and a phone implied an app that was never ours.

   Everything here is the funnel vocabulary from the case page, plus the two
   lines a case page states elsewhere -- what it cost and where it came from.
   Same classes on purpose: a second dialect of the same idea drifts on the
   second edit. */

.hero__proof {
  margin-top: clamp(30px, 4vw, 46px);
  /* Full container width: the composition refuses the copy-left / visual-right
     split that made this screen interchangeable with any other product. */
  max-width: none;
}

/* Hairline-divided steps, the same reading as the metric panel: a sunken
   ground, a one-pixel ring, and a 1px grid gap so neighbouring rings meet and
   read as a single rule rather than a doubled one. */
.funnel--hero .funnel__list {
  display: grid;
  /* One grid for the list, and every row borrows its columns. Three independent
     row grids sized the label column by each row own text, so the bars started
     on three different pixels and width stopped reading as share of the top. */
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 1px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  isolation: isolate;
}
.funnel--hero .funnel__row {
  align-items: center;
  gap: clamp(14px, 2vw, 28px);
  padding: clamp(14px, 1.8vw, 20px) clamp(14px, 1.8vw, 22px);
  background: var(--bg-sunken);
  box-shadow: 0 0 0 1px var(--line);
  /* Borrow the list columns so all three rows agree on where the bar starts.
     Without subgrid the declaration is dropped and the row falls back to its
     own grid -- ragged, but still readable. */
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
}
.funnel--hero .funnel__label {
  margin: 0;
  white-space: nowrap;
}
.funnel--hero .funnel__track { height: 12px; }
.funnel--hero .funnel__value {
  justify-content: flex-end;
  /* Values run 4 to 7 characters. Tabular figures at a fixed column width mean
     174 350 and 28 311 end on the same pixel, so the bar beside them never
     shifts between rows. */
  font-variant-numeric: tabular-nums;
  min-width: 7ch;
  font-size: clamp(1.15rem, 1.9vw, 1.55rem);
}
.funnel--hero .funnel__rate { white-space: nowrap; }

/* The money line: what the funnel cost and what it returned. Solid ink, never
   --live -- that token means "in delivery" and the step conversion above is
   its one use in this block. */
.hero__money {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(18px, 3vw, 42px);
  margin-top: clamp(18px, 2.2vw, 26px);
  padding: 0 clamp(14px, 1.8vw, 22px);
}
.hero__money-item {
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.hero__money-item b {
  font-weight: 700;
  font-size: clamp(1.05rem, 1.7vw, 1.35rem);
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.hero__money-item span {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-4);
}

/* Provenance, and the one way out of the block. Geo and vertical only: the
   provider and the offer are named on the case page, not here. */
.hero__prov {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: clamp(16px, 2vw, 22px);
  padding: 8px clamp(14px, 1.8vw, 22px);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease);
}
.hero__prov em {
  font-style: normal;
  color: var(--accent);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-fast) var(--ease);
}
.hero__prov svg { flex: none; color: var(--accent); }
.hero__prov:hover,
.hero__prov:focus-visible { color: var(--ink-2); }
.hero__prov:hover em,
.hero__prov:focus-visible em { border-bottom-color: currentColor; }

@media (max-width: 760px) {
  /* Withdraw, do not shrink: the row goes back to stacked rather than
     compressing three columns into a phone. */
  .funnel--hero .funnel__list { grid-template-columns: minmax(0, 1fr); }
  .funnel--hero .funnel__row {
    grid-template-columns: minmax(0, 1fr);
    gap: 9px;
  }
  .funnel--hero .funnel__value { justify-content: flex-start; min-width: 0; }
  .funnel--hero .funnel__label { white-space: normal; }
}

.hero__lead {
  margin-top: clamp(22px, 2.8vw, 32px);
  max-width: 48ch;
  font-size: var(--fs-lead);
  color: var(--ink-2);
  line-height: 1.58;
}

.hero__actions {
  margin-top: clamp(30px, 3.6vw, 44px);
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}

/* Telegram is where these buyers actually are: a third, quieter route out of the hero. */
.hero__tg {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 4px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease);
}

.hero__tg svg { flex: none; opacity: 0.75; transition: opacity var(--dur-fast) var(--ease); }

.hero__tg span {
  border-bottom: 1px solid rgba(242, 240, 236, 0.22);
  transition: border-color var(--dur-fast) var(--ease);
}

.hero__tg:hover,
.hero__tg:focus-visible { color: var(--accent); }
.hero__tg:hover svg,
.hero__tg:focus-visible svg { opacity: 1; }
.hero__tg:hover span,
.hero__tg:focus-visible span { border-bottom-color: currentColor; }

/* Wrapped onto its own row: give it a real touch target. */
@media (max-width: 760px) {
  .hero__tg { min-height: 44px; }
}

.hero__note {
  margin-top: clamp(22px, 2.6vw, 30px);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-4);
}

/* Stat strip under the hero */
.stat-strip {
  margin-top: clamp(34px, 4vw, 58px);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
.stat {
  padding: clamp(17px, 2vw, 26px) clamp(14px, 2vw, 28px);
  border-left: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.stat:first-child { border-left: 0; padding-left: 0; }
.stat {
  position: relative;
  transition: background-color var(--dur) var(--ease);
}
.stat::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.55s var(--ease);
}
.stat:hover::after { transform: scaleX(1); }

.stat__value {
  /* Same figure language as .metric__value: body sans, solid ink. The chrome
     gradient that used to paint these was decoration on a data figure, and its
     darkest stop (#8f949d) cost real contrast against the page.

     tabular-nums stays, and is deliberate: these values count up from zero on
     reveal (see [data-count] in main.js). Proportional figures would re-measure
     the number on every animation frame and make the strip twitch. The rule is
     "tabular where digits must hold a position" -- an animating counter is
     exactly that case, a static tile is not. */
  font-family: var(--font-sans);
  font-variant-numeric: tabular-nums;
  font-size: clamp(1.7rem, 3.2vw, 2.6rem);
  font-weight: 700;
  letter-spacing: -0.04em;
  line-height: 1;
  color: var(--ink);
}
.stat__label {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-3);
  line-height: 1.4;
}

/* --------------------------------------------------------------------------
   8. Hero device — a physical handset running a campaign dashboard
   -------------------------------------------------------------------------- */

.bench {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  perspective: 1600px;
}

.bench__glow {
  position: absolute;
  left: 50%;
  top: 44%;
  width: 128%;
  height: 66%;
  transform: translate(-50%, -50%);
  background:
    radial-gradient(48% 48% at 50% 50%, rgba(123, 140, 255, 0.26), transparent 72%),
    radial-gradient(70% 40% at 50% 88%, rgba(95, 227, 161, 0.10), transparent 70%);
  filter: blur(26px);
  pointer-events: none;
  /* Deliberately still. The screen breathes from inside via .bench__screen::before;
     a second ambient loop out here repeated that gesture at a size too large to
     read, so it registered as nothing and cost a compositor layer. */
  opacity: 0.93;
}

/* ------------------------------------------------------------ Orbiting cards

   Fragments of the product breaking out of the frame -- the move both
   references are built on. Three, not a dozen: each one has to be a thing the
   company actually says (a channel it buys, a verdict it gives, a number it
   watches), or the group turns into decoration.

   Every string here already exists in all five locale files and every value
   comes from content/site.json, so the cards translate with the rest of the
   site and no new copy had to be invented for them. They are aria-hidden
   because each one echoes something the dashboard already announces. */

/* Mirrors the handset box exactly -- same width rule, same aspect ratio, same
   top edge -- rather than filling .bench. Percentages here are therefore
   percentages OF THE DEVICE, which is the only frame the cards can meaningfully
   break out of. Anchored to .bench because the cards must NOT inherit the 3D
   tilt: they are separate objects in the scene, not decals on the glass. */
.bench__orbit {
  position: absolute;
  left: 50%;
  top: 0;
  translate: -50% 0;
  width: min(100%, 272px);
  aspect-ratio: 393 / 852;
  pointer-events: none;
  z-index: 3;
}

.orbit-card {
  position: absolute;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 12px;
  border-radius: 11px;
  border: 1px solid var(--line-2);
  /* Opaque enough to hold over the bright titanium edge, translucent enough to
     belong to the backdrop. The blur is progressive: with no support for it the
     card is simply a solid dark chip, which is a perfectly good fallback. */
  background: rgba(9, 9, 12, 0.74);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 22px 44px -26px rgba(0, 0, 0, 0.95);
  font-family: var(--font-mono);
  font-size: 0.5625rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
  white-space: nowrap;
  /* The parallax rides `transform` and the float rides `translate`, on purpose.
     A CSS animation overrides inline styles, so if both used `transform` the
     JS parallax would set a value the animation overwrites on the next frame
     and the cards would never respond to the pointer at all. */
  transform: translate3d(var(--px, 0px), var(--py, 0px), 0);
  transition: transform 0.5s var(--ease);
  will-change: transform, translate;
}
/* No idle float any more: these follow the pointer (assets/js/main.js).
   Three ambient loops became one thing the visitor is actually driving. */

/* Periods share no common multiple, so the three never swing together. */
.orbit-card--channel { top: 31%; left:  -30%; --float-dur:  9.4s; --float-delay: -1.2s; }
.orbit-card--verdict { top: 14%; right: -26%; --float-dur: 11.6s; --float-delay: -4.5s; }
.orbit-card--metric  { top: 63%; right: -22%; --float-dur:  8.2s; --float-delay: -6.8s; }

.orbit-dot {
  flex: none;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent);
  /* A 1px ring, not a 3px bloom: at this size a halo is the only thing you
     see and the dot itself disappears inside it. */
  outline: 1px solid var(--accent-line);
  outline-offset: 2px;
}

.orbit-card--verdict {
  color: var(--live);
  border-color: rgba(95, 227, 161, 0.28);
}
.orbit-card--verdict svg { flex: none; }

.orbit-card--metric {
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  padding: 9px 13px;
}
.orbit-card--metric b {
  font-family: var(--font-sans);
  font-size: 0.94rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  text-transform: none;
  color: var(--ink);
}
.orbit-card--metric span {
  font-size: 0.5rem;
  letter-spacing: 0.14em;
  color: var(--ink-4);
}

/* Below 1200px the hero puts the handset in a narrow column beside the copy,
   and anything overhanging it lands on the text. The cards are hero art for
   the width that has room for them. */
@media (max-width: 1200px) {
  .hero__copy { grid-column: 1 / span 7; }
  .hero__visual { grid-column: 8 / span 5; }
  .bench__orbit { display: none; }
}

/* ------------------------------------------------------------- The handset */

.bench__device {
  position: relative;
  width: min(100%, 236px);
  aspect-ratio: 393 / 852;
  border-radius: 48px;
  padding: 2.5px;
  /* Brushed titanium edge: bright on the top-left, dark where it turns away */
  background:
    linear-gradient(150deg,
      #f4f5f8 0%, #9ba0aa 7%, #4c505a 16%, #babfc8 26%,
      #6d727c 44%, #2f333b 58%, #8f949e 72%, #d8dce3 84%, #5b606a 100%);
  box-shadow:
    0 70px 130px -46px rgba(0, 0, 0, 0.96),
    0 0 0 1px rgba(255, 255, 255, 0.05),
    0 0 90px -34px var(--accent-glow);
  transform-style: preserve-3d;
  transform: perspective(1600px) rotateX(var(--rx, 2.5deg)) rotateY(var(--ry, -11deg));
  transition: transform 0.75s var(--ease);
  animation: deviceFloat 11s ease-in-out infinite;
  will-change: transform;
}
.bench.is-tilting .bench__device {
  transition: transform 0.14s linear;
  animation-play-state: paused;
}
/* While the pointer is in the frame the cards must track it exactly. The 0.5s
   ease on .orbit-card is there for the return trip only -- left on during the
   move it would lag the pointer by half a second and feel broken. */
.bench.is-tilting .orbit-card { transition: none; }

/* Three phases rather than two, on a period that does not divide evenly into
   the other loops on the page. A two-keyframe float is a metronome -- the eye
   locks onto the beat and the motion stops reading as drift. The sway uses the
   independent `rotate` property, so it composes with the pointer tilt in
   `transform` instead of fighting it for the same declaration. */
@keyframes deviceFloat {
  0%, 100% { translate: 0 0;     rotate: 0deg; }
  34%      { translate: 0 -10px; rotate: 0.55deg; }
  67%      { translate: 0 -4px;  rotate: -0.4deg; }
}

/* Side buttons */
.bench__btn {
  position: absolute;
  width: 2.5px;
  border-radius: 2px;
  background: linear-gradient(180deg, #b9bec7, #4a4e57 40%, #2b2e35 70%, #9ca1aa);
  z-index: 2;
}
.bench__btn--mute      { left: -2px; top: 15%;   height: 4.4%; }
.bench__btn--vol-up    { left: -2px; top: 23%;   height: 8.2%; }
.bench__btn--vol-down  { left: -2px; top: 33.5%; height: 8.2%; }
.bench__btn--power     { right: -2px; top: 26%;  height: 12%; }

/* Black bezel between the metal edge and the display */
.bench__frame {
  height: 100%;
  padding: 7px;
  border-radius: 45.5px;
  background: #050508;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05);
}

.bench__screen {
  position: relative;
  height: 100%;
  border-radius: 39px;
  overflow: hidden;
  background:
    radial-gradient(120% 70% at 50% 0%, rgba(123, 140, 255, 0.16), transparent 62%),
    linear-gradient(178deg, #0d101c 0%, #090b14 46%, #06070d 100%);
  isolation: isolate;
}
.bench__screen::before {
  /* The display's OWN backlight, not a reflection on the glass in front of it.
     That distinction is the whole point: a highlight travelling across the
     outside reads as a prop being lit, while light moving underneath the UI
     reads as a screen that is switched on and working.

     It sits at z-index 0 -- above the screen background, beneath .dash (z 2)
     and beneath the glass highlight in ::after (z 4) -- so the interface is lit
     BY it rather than washed over by it. */
  content: "";
  position: absolute;
  inset: -18%;
  background: radial-gradient(40% 32% at 50% 14%, rgba(123, 140, 255, 0.24), transparent 72%);
  pointer-events: none;
  z-index: 0;
  /* No loop: the wave on the screen is the motion here, and a glow that also
     breathed behind it was a second clock telling the same time. */
}
.bench__screen::after {
  /* Glass: a single raking highlight, not a cartoon shine */
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(128deg,
    rgba(255, 255, 255, 0.10) 0%,
    rgba(255, 255, 255, 0) 34%,
    rgba(255, 255, 255, 0) 66%,
    rgba(255, 255, 255, 0.05) 100%);
  pointer-events: none;
  z-index: 4;
}

/* Dynamic Island */
.bench__island {
  position: absolute;
  top: 9px;
  left: 50%;
  transform: translateX(-50%);
  width: 74px;
  height: 22px;
  border-radius: 12px;
  background: #000;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding-right: 8px;
}
.bench__lens {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 32%, #2b3b6b 0%, #0e1428 55%, #05070f 100%);
  box-shadow: inset 0 0 0 0.6px rgba(120, 150, 220, 0.35);
}

/* ------------------------------------------------------------- Dashboard UI */

.dash {
  position: relative;
  z-index: 2;
  height: 100%;
  display: flex;
  flex-direction: column;
  padding: 44px 16px 16px;
  gap: 9px;
}

.dash__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.dash__label {
  font-family: var(--font-mono);
  font-size: 0.5rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.dash__live {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 9px 4px 7px;
  border-radius: 999px;
  border: 1px solid rgba(95, 227, 161, 0.34);
  background: rgba(95, 227, 161, 0.10);
  font-family: var(--font-mono);
  font-size: 0.5rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--live);
}
.dash__live i {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--live);
  animation: livePulse 2.4s var(--ease) infinite;
}
@keyframes livePulse {
  0%   { box-shadow: 0 0 0 0 rgba(95, 227, 161, 0.55); }
  70%  { box-shadow: 0 0 0 7px rgba(95, 227, 161, 0); }
  100% { box-shadow: 0 0 0 0 rgba(95, 227, 161, 0); }
}

.dash__title {
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin-top: 2px;
}

.dash__hero { display: flex; align-items: baseline; gap: 9px; }
.dash__value {
  font-size: 2.35rem;
  font-weight: 800;
  letter-spacing: -0.045em;
  line-height: 1;
  /* Deliberate: this figure counts up 0 -> 218 over 1.6s (countUp in main.js).
     Tabular figures hold each digit at one width so the number does not
     re-measure on every frame and shove .dash__delta sideways. */
  font-variant-numeric: tabular-nums;
  color: #fff;
}
.dash__delta {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-family: var(--font-mono);
  font-size: 0.625rem;
  font-weight: 500;
  color: var(--live);
}
.dash__sub {
  font-size: 0.5625rem;
  line-height: 1.45;
  color: var(--ink-3);
  max-width: 24ch;
}

/* The wave. It stands where a line chart drawn from Math.random() used to,
   and the swap is the point: a wave is plainly an ornament, so nobody can
   mistake it for a measurement. Drawn on a 2D canvas rather than through a
   third-party 3D runtime -- the site makes no external requests and generates
   every pixel of its own graphics. */
.dash__wave {
  position: relative;
  flex: 1;
  min-height: 78px;
  margin-top: 2px;
  border-radius: 10px;
  overflow: hidden;
  /* Visible before the canvas paints, and the whole of it when JS never runs. */
  background:
    radial-gradient(120% 90% at 50% 118%, rgba(123, 140, 255, 0.30), transparent 70%),
    radial-gradient(80% 70% at 22% 108%, rgba(95, 227, 161, 0.16), transparent 72%);
}
.dash__wave canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* Metric tiles */
.dash__tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
.dash__tile {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 8px 8px 9px;
  border-radius: 10px;
  border: 1px solid var(--line);
  /* Flat token surface. The gradient this replaces spanned 0.055 to 0.012 alpha
     over 34px of tile -- a ramp too short to read as anything but haze. */
  background: var(--surface-2);
}
.dash__tile-key {
  font-family: var(--font-mono);
  font-size: 0.4375rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.dash__tile-val {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ink);
  /* Proportional figures: these drift inside a narrow band rather than
     counting, so no digit has to hold a fixed position. Only .dash__value
     above needs tabular, because it counts up from zero. */
  font-variant-numeric: proportional-nums;
}
/* A refreshed value announces itself for a beat, then settles back to ink --
   the same way a real console marks the cell that just changed. */

/* Managed budget card */
.dash__budget {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 11px;
  border-radius: 13px;
  border: 1px solid rgba(123, 140, 255, 0.26);
  background: var(--accent-dim);
}
.dash__budget-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 26px;
  border-radius: 8px;
  background: rgba(123, 140, 255, 0.22);
  color: #cfd6ff;
  flex: none;
}
.dash__budget-body { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.dash__budget-value {
  font-size: 0.86rem;
  font-weight: 800;
  letter-spacing: -0.025em;
  color: #fff;
}
.dash__budget-label {
  font-size: 0.5rem;
  color: var(--ink-3);
  line-height: 1.3;
}

@media (max-width: 1024px) {
  .bench__device { width: min(100%, 250px); }
}
@media (max-width: 760px) {
  .bench__device {
    width: min(100%, 236px);
    /* Straight on: a tilted phone reads as a mistake on a narrow screen */
    transform: perspective(1600px) rotateX(0deg) rotateY(0deg);
  }
  .dash { padding: 40px 13px 13px; gap: 7px; }
  .dash__value { font-size: 2rem; }
}

/* --------------------------------------------------------------------------
   8b. Touch — a phone is not a small desktop
   --------------------------------------------------------------------------

   Measured across all ten page templates at 375px: every footer link stood at
   24px, the language codes at 29px, "Legal" at 16px and the back-to-top button
   at 20px. All of them are things a thumb has to find, and every one was under
   half of the 44px a thumb actually needs.

   The fix extends the HIT AREA, not the ink. A pseudo-element centred on the
   link grows the target without moving one pixel of the design; padding would
   have opened the footer up by a third and changed a layout nobody asked to
   change. The pseudo-element belongs to the anchor, so it is part of the same
   hit region without any pointer-events work. */

@media (max-width: 760px) {
  .footer__link,
  .footer__lang,
  .footer__legal a,
  .footer__meta a,
  .menu__contact a,
  .breadcrumb a,
  .info-row__val a,
  .logo,
  .link {
    position: relative;
  }

  .footer__link::after,
  .footer__lang::after,
  .footer__legal a::after,
  .footer__meta a::after,
  .menu__contact a::after,
  .breadcrumb a::after,
  .info-row__val a::after,
  .logo::after,
  .link::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 44px;
    transform: translateY(-50%);
    /* Behind the ink, so it never covers something drawn on top of the link. */
    z-index: 0;
  }

  /* Controls that own a box simply get taller. */
  .hub-filter { min-height: 44px; }
  .to-top { --to-top-size: 46px; }
  .form .btn,
  .btn--ghost { min-height: 44px; }

  /* A long label inside a pill used to be cut in half: .btn is nowrap with
     overflow hidden, so "Apply for Creative Strategist" simply ended mid-word
     at 375px. On a narrow screen the label wraps and the button grows. */
  .btn {
    white-space: normal;
    text-align: center;
    line-height: 1.25;
  }
}

/* --------------------------------------------------------------------------
   Geography — the 72 markets as structure, not as a claim
   --------------------------------------------------------------------------

   The number appears in the hero lead, in the positioning block, in the FAQ
   and in the footer. Until now nothing on the site let anyone check it. This
   section names all twelve regions, counts each one, and lists every country
   by name in the reader's own language.

   The globe beside it is drawn from the same data. It cannot be out of step
   with the list, because both come from content/site.json in one pass. */

.geo__layout {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(32px, 4vw, 64px);
  align-items: start;
  margin-top: clamp(40px, 4.6vw, 64px);
}

.geo__globe { position: sticky; top: calc(var(--header-h) + 32px); }

.geo-globe {
  position: relative;
  aspect-ratio: 1;
  max-width: 420px;
  margin-inline: auto;
}
.geo-globe canvas {
  display: block;
  width: 100%;
  height: 100%;
  cursor: grab;
  touch-action: pan-y;
}
.geo-globe.is-grabbing canvas { cursor: grabbing; }

/* The count sits in the middle of the sphere, behind the lattice: the figure
   the section exists to substantiate, in the middle of the thing that
   substantiates it. */
.geo-globe__total {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  pointer-events: none;
  text-align: center;
}
.geo-globe__total strong {
  font-size: clamp(2.4rem, 5vw, 3.4rem);
  font-weight: 700;
  letter-spacing: -0.04em;
  line-height: 1;
  color: var(--ink);
}
.geo-globe__total span {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-4);
}

/* The regions. Hairline-divided cells, the same grammar as the metric panel
   and the funnel: a sunken ground with a one-pixel ring, and a 1px gap so
   neighbouring rings meet as a single rule. */
.geo__regions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: 1px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  isolation: isolate;
}
.geo-region {
  padding: clamp(16px, 1.8vw, 22px);
  background: var(--bg-sunken);
  box-shadow: 0 0 0 1px var(--line);
}
.geo-region__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 9px;
}
.geo-region__name {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.geo-region__n {
  font-size: var(--fs-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink-4);
}
/* The markets, as codes rather than as prose. A comma-run of full country
   names read as filler: nine words where the reader wanted a list, and the one
   form nobody in this job uses. GB, DE, BR is what a buyer types into a
   targeting field every working day -- so that is what the site shows, with
   the translated name still carried in the title. */
.geo-region__list {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin: 0;
}
.geo-code {
  display: inline-block;
  padding: 3px 6px 2px;
  border-radius: 3px;
  background: rgba(242, 240, 236, 0.04);
  box-shadow: inset 0 0 0 1px var(--line);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.09em;
  line-height: 1.3;
  color: var(--ink-3);
  /* The browser default underlines an abbr with a title, which on a dense row
     of two-letter tokens reads as damage rather than as a hint. */
  text-decoration: none;
  cursor: help;
  transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}
.geo-code:hover {
  color: var(--ink);
  background: rgba(242, 240, 236, 0.09);
}
/* Core markets are delivered end to end. One step of ink says so, on the codes
   as well as on the heading -- the same distinction the legend below explains. */
.geo-region--core .geo-code {
  color: var(--ink-2);
  box-shadow: inset 0 0 0 1px var(--accent-line);
}
/* Core markets are delivered end to end; extended ones are launched on demand.
   One step of ink between them, which is the whole difference to state. */
.geo-region--core .geo-region__name { color: var(--ink); }
.geo-region--core .geo-region__n { color: var(--accent); }
.geo-region--extended .geo-region__name { color: var(--ink-2); }

.geo__note {
  grid-column: 1 / -1;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 0;
  padding: 14px clamp(16px, 1.8vw, 22px);
  background: var(--bg-sunken);
  box-shadow: 0 0 0 1px var(--line);
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--ink-3);
}
.geo__key {
  flex: none;
  width: 8px;
  height: 8px;
  margin-top: 6px;
  border-radius: 50%;
}
.geo__key--core { background: var(--accent); }
.geo__key--extended { background: var(--ink-4); }

@media (max-width: 1024px) {
  .geo__layout { grid-template-columns: minmax(0, 1fr); }
  .geo__globe { position: static; }
  .geo-globe { max-width: 340px; }
}

/* --------------------------------------------------------------------------
   9. Ticker
   -------------------------------------------------------------------------- */

.ticker {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding-block: clamp(13px, 1.5vw, 18px);
  overflow: hidden;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: clamp(9px, 1vw, 14px);
  mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}
.ticker__row { overflow: hidden; }
.ticker__track {
  display: flex;
  width: max-content;
  animation: marquee 30s linear infinite;
}
/* Two rows travelling in opposite directions: the band reads as moving
   even in a glance, which a single slow row never did. */
.ticker__row--reverse .ticker__track {
  animation-direction: reverse;
  animation-duration: 38s;
}
.ticker__row--reverse .ticker__item { color: var(--ink-4); }
.ticker__row--reverse .ticker__item::after { background: var(--ink-4); box-shadow: none; }
.ticker:hover .ticker__track { animation-play-state: paused; }
.ticker__group { display: flex; flex: none; }
.ticker__item {
  display: inline-flex;
  align-items: center;
  gap: clamp(20px, 3vw, 40px);
  padding-right: clamp(20px, 3vw, 40px);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
}
.ticker__item::after {
  content: "";
  width: 4px; height: 4px;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent-glow);
  transform: rotate(45deg);
  flex: none;
}
@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* --------------------------------------------------------------------------
   10. Manifesto
   -------------------------------------------------------------------------- */

.manifesto__statement {
  font-size: clamp(1.85rem, 4.6vw, 3.6rem);
  line-height: 1.08;
  letter-spacing: -0.035em;
  font-weight: 800;
  max-width: 19ch;
  margin-top: clamp(24px, 3vw, 36px);
}
.manifesto__body {
  margin-top: clamp(24px, 3vw, 34px);
  max-width: 56ch;
  color: var(--ink-2);
  font-size: var(--fs-lead);
  line-height: 1.6;
}
.manifesto__cols {
  margin-top: clamp(48px, 6vw, 82px);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(24px, 3vw, 44px);
  border-top: 1px solid var(--line);
  padding-top: clamp(28px, 3.4vw, 44px);
}
.manifesto__col { display: flex; flex-direction: column; gap: 12px; }
.manifesto__col .num { font-size: var(--fs-mono); letter-spacing: 0.16em; color: var(--ink-4); }
.manifesto__col h3 { font-size: var(--fs-h4); font-weight: 700; letter-spacing: -0.015em; max-width: 22ch; }
.manifesto__col p { color: var(--ink-3); font-size: var(--fs-sm); line-height: 1.62; }

/* --------------------------------------------------------------------------
   11. Capability index
   -------------------------------------------------------------------------- */

.capabilities__layout {
  margin-top: clamp(44px, 5vw, 72px);
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: clamp(32px, 4vw, 72px);
  align-items: start;
}

.cap-list { border-top: 1px solid var(--line); }
.cap-item {
  width: 100%;
  display: grid;
  grid-template-columns: 44px 1fr auto;
  align-items: center;
  gap: 14px;
  padding: clamp(15px, 1.7vw, 21px) 0;
  border-bottom: 1px solid var(--line);
  background: none;
  border-left: 0; border-right: 0; border-top: 0;
  text-align: left;
  cursor: pointer;
  color: var(--ink-3);
  transition: color var(--dur-fast) var(--ease), padding-left var(--dur) var(--ease);
  position: relative;
}
.cap-item::before {
  content: "";
  position: absolute;
  left: -14px;
  top: 50%;
  width: 6px; height: 6px;
  background: var(--accent);
  box-shadow: 0 0 12px var(--accent-glow);
  transform: translateY(-50%) rotate(45deg) scale(0);
  transition: transform var(--dur) var(--ease);
}
.cap-item::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: linear-gradient(90deg, var(--accent), transparent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.5s var(--ease);
}
.cap-item:hover { color: var(--ink-2); }
.cap-item.is-active { color: var(--ink); padding-left: 14px; }
.cap-item.is-active::before { transform: translateY(-50%) rotate(45deg) scale(1); }
.cap-item.is-active::after { transform: scaleX(1); }
.cap-item__num {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.14em;
  color: var(--ink-4);
  transition: color var(--dur-fast) var(--ease);
}
.cap-item.is-active .cap-item__num { color: var(--accent); }
.cap-item__title {
  font-size: clamp(1.05rem, 1.8vw, 1.45rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
}
.cap-item__short {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 400;
  color: var(--ink-4);
  margin-top: 5px;
  letter-spacing: 0;
  max-width: 40ch;
}
.cap-item__arrow { opacity: 0; transform: translateX(-6px); transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease); }
.cap-item.is-active .cap-item__arrow { opacity: 1; transform: translateX(0); }

.cap-panel {
  position: sticky;
  top: calc(var(--header-h) + 32px);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--panel-fill);
  padding: clamp(24px, 2.8vw, 38px);
  min-height: 340px;
  overflow: hidden;
  isolation: isolate;
}
.cap-panel::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(90% 70% at 100% 0%, rgba(123, 140, 255, 0.16), transparent 62%),
    radial-gradient(80% 60% at 0% 100%, rgba(255,255,255,0.05), transparent 60%);
  pointer-events: none;
  z-index: -1;
}
/* All panels share one grid cell, so the container is always as tall as the
   tallest one and switching disciplines never shifts the page below. */
.cap-panel { display: grid; }
.cap-panel__inner {
  grid-area: 1 / 1;
  display: flex;
  flex-direction: column;
  gap: 18px;
  visibility: hidden;
  opacity: 0;
  transform: translateY(10px);
  pointer-events: none;
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease), visibility 0.4s;
}
.cap-panel__inner.is-active {
  visibility: visible;
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
/* Without JS the server-rendered `hidden` attribute keeps exactly one visible */
.cap-panel__inner[hidden] { display: none; }

.cap-panel__index {
  font-family: var(--font-mono);
  font-size: clamp(2.6rem, 5vw, 3.6rem);
  line-height: 1;
  letter-spacing: -0.04em;
  font-weight: 300;
  color: transparent;
  -webkit-text-stroke: 1px var(--accent-line);
}
.cap-panel__title { font-size: clamp(1.4rem, 2.4vw, 1.95rem); font-weight: 800; letter-spacing: -0.03em; }
.cap-panel__text { color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.66; max-width: 46ch; }
.cap-panel__points { display: flex; flex-direction: column; gap: 9px; margin-top: 4px; }
.cap-panel__points li {
  display: flex;
  gap: 11px;
  align-items: baseline;
  font-size: var(--fs-sm);
  color: var(--ink-3);
  padding-top: 9px;
  border-top: 1px solid var(--line);
}
.cap-panel__points li::before {
  content: "";
  width: 4px; height: 4px;
  background: var(--ink-4);
  transform: rotate(45deg);
  flex: none;
  position: relative;
  top: -1px;
}

/* --------------------------------------------------------------------------
   12. Loop (process)
   -------------------------------------------------------------------------- */

.loop { margin-top: clamp(44px, 5.4vw, 76px); position: relative; }

.loop__rail {
  position: relative;
  height: 1px;
  background: var(--line);
  margin-bottom: clamp(28px, 3vw, 40px);
}
.loop__rail i {
  position: absolute;
  inset: 0 auto 0 0;
  height: 1px;
  width: 0;
  background: linear-gradient(90deg, transparent, var(--accent) 60%, var(--accent-hi));
  box-shadow: 0 0 14px var(--accent-glow);
  transition: width 0.9s var(--ease);
}

.loop__steps {
  display: grid;
  /* Six narrow columns produced 31-character lines. Three gives ~50. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(20px, 2.2vw, 34px) clamp(20px, 2.6vw, 40px);
}
.loop__step {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding-top: clamp(18px, 2vw, 26px);
  border-top: 1px solid var(--line);
  position: relative;
  opacity: 0.42;
  transition: opacity 0.6s var(--ease);
}
.loop__step::before {
  content: "";
  position: absolute;
  top: -3.5px; left: 0;
  width: 6px; height: 6px;
  background: var(--ink-4);
  transform: rotate(45deg);
  transition: background-color 0.5s var(--ease), transform 0.5s var(--ease);
}
.loop__step.is-active { opacity: 1; }
.loop__step.is-active { border-top-color: var(--accent-line); }
.loop__step.is-active::before {
  background: var(--accent);
  box-shadow: 0 0 14px var(--accent-glow);
  transform: rotate(45deg) scale(1.3);
}
.loop__step.is-active .loop__num { color: var(--accent); }
.loop__num {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.16em;
  color: var(--ink-4);
}
.loop__title { font-size: var(--fs-h4); font-weight: 700; letter-spacing: -0.02em; }
.loop__text { font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.6; }
.loop__output {
  margin-top: auto;
  padding-top: 12px;
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-4);
  line-height: 1.55;
  border-top: 1px solid var(--line);
}

.loop__closing {
  margin-top: clamp(34px, 4vw, 54px);
  display: flex;
  align-items: flex-start;
  gap: 18px;
  padding-top: clamp(24px, 2.6vw, 34px);
  border-top: 1px solid var(--line);
}
.loop__closing svg { flex: none; margin-top: 3px; opacity: 0.5; }
.loop__closing p { max-width: 52ch; color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.65; }

/* --------------------------------------------------------------------------
   13. Split blocks (about preview, generic 2-col)
   -------------------------------------------------------------------------- */

.split {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(32px, 5vw, 96px);
  align-items: start;
}
.split__aside { position: sticky; top: calc(var(--header-h) + 40px); }

/* --------------------------------------------------------------------------
   15. Cards (cases, articles, generic)
   -------------------------------------------------------------------------- */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background:
    radial-gradient(120% 80% at 0% 0%, rgba(123, 140, 255, 0.055), rgba(123, 140, 255, 0) 58%),
    var(--panel-fill);
  overflow: hidden;
  isolation: isolate;
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}
.card::before {
  /* Specular hairline that lights up on hover */
  content: "";
  position: absolute;
  top: 0; left: 8%; right: 8%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent-hi), transparent);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.card:hover {
  border-color: var(--accent-line);
  transform: translateY(-3px);
  box-shadow: 0 20px 50px -28px rgba(0, 0, 0, 0.9), 0 0 0 1px var(--accent-dim);
}
.card:hover::before { opacity: 1; }

/* Case card */
.cases { display: grid; gap: clamp(16px, 1.8vw, 22px); }
/* Two featured cases, both real. Same two-up rhythm as .cases--full. */
.cases--home { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: clamp(40px, 4.6vw, 64px); }

.case {
  padding: clamp(22px, 2.4vw, 32px);
  gap: clamp(18px, 2vw, 24px);
}
.case__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--line);
}
.case__code {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.2em;
  font-weight: 500;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.case__code::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--live);
  box-shadow: 0 0 0 3px var(--live-dim);
  flex: none;
}
.case__tag {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-4);
  text-align: right;
}
.case__title { font-size: var(--fs-h4); font-weight: 700; letter-spacing: -0.022em; line-height: 1.25; }
.case__summary { font-size: var(--fs-sm); color: var(--ink-3); line-height: 1.62; }

.case__meta { display: flex; flex-direction: column; gap: 9px; margin-top: auto; padding-top: 4px; }
.case__meta-row { display: grid; grid-template-columns: 78px 1fr; gap: 12px; align-items: baseline; }
.case__meta-key {
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.case__meta-val { font-size: var(--fs-xs); color: var(--ink-2); }

/* ------------------------------------------------------------ Metric widgets

   Built as one hairline-divided readout panel, not as a row of glass cards.

   The previous tile stacked four decorative layers under the number: an accent
   radial glow, a white surface gradient, a specular top edge and a masked
   engineering grid, with the figure itself painted in a chrome gradient. At
   104px none of those details survive the size -- they only add texture, and
   together they read as noise rather than as instrumentation.

   What holds the panel now is what holds one on any well-built dashboard:
   a single hairline, real padding, and the figure set loud in the body sans.
   Colour appears exactly once per cell, on the direction arrow, where it
   carries meaning. The form deliberately echoes .stat-strip, so the site
   states its numbers the same way everywhere.
*/

.metrics {
  display: grid;
  /* auto-fit rather than a fixed three: inside a narrow case card the cells
     drop to two columns on their own, without a breakpoint per container */
  grid-template-columns: repeat(auto-fit, minmax(108px, 1fr));
  gap: 1px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  isolation: isolate;
}

/* No orphan-stretch rule here on purpose: the only column-count-agnostic form
   of it (auto / -1) resolves to a span of one and parks the cell in the LAST
   column, opening a hole on the left. Since the container paints nothing, an
   empty grid area is simply invisible -- a short last row is the better
   failure mode than a misplaced cell. */

.metric {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 11px;
  padding: 15px 14px 13px;
  /* Sunken against the card's lit surface: the panel reads as a readout set
     into the card rather than as another card floating on top of it. */
  background: var(--bg-sunken);
  /* The rule is a ring on each cell, not the container showing through the
     gaps. Neighbouring rings meet inside the 1px gap and read as one hairline,
     and -- unlike a container background -- a grid area with no cell in it
     stays empty instead of lighting up as a block. */
  box-shadow: 0 0 0 1px var(--line);
  transition: background-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}

/* On card hover the rules lift a step and the cells warm. One property each --
   the panel wakes up without anything moving. */
.card:hover .metric {
  background: var(--bg);
  box-shadow: 0 0 0 1px var(--line-2);
}

.metric__figure {
  display: flex;
  align-items: baseline;
  gap: 6px;
}

.metric__value {
  /* Body sans, not mono: at this size a mono figure reads as a code sample.
     Proportional figures, not tabular -- these values sit in a grid, not in a
     column that has to align vertically, and tabular widths make a number
     like 118 look gapped at display sizes. */
  font-family: var(--font-sans);
  font-variant-numeric: proportional-nums;
  font-size: clamp(1.44rem, 2.4vw, 1.78rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.045em;
  color: var(--ink);
}
.metric__unit {
  font-style: normal;
  font-size: 0.58em;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink-3);
  margin-left: 1px;
}

/* The one piece of colour in the cell, and it means direction. */
.metric__dir {
  flex: none;
  align-self: center;
  /* Colour comes from --tone in section 28, so the arrow, the cap and the
     unit cannot drift apart. */
}

.metric__label {
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-3);
  line-height: 1.35;
  margin-top: auto;
}

/* Undisclosed value */
.metric__value.is-placeholder {
  display: flex;
  align-items: center;
  height: 1.78rem;
  color: var(--ink-4);
}
.metric__rule {
  display: block;
  width: 26px;
  height: 2px;
  border-radius: 1px;
  background: repeating-linear-gradient(90deg, var(--ink-4) 0 5px, transparent 5px 9px);
}
/* ------------------------------------------------------------------ Sparkles */

.sparkle {
  position: absolute;
  pointer-events: none;
  opacity: 0.55;
  filter: drop-shadow(0 0 14px rgba(123, 140, 255, 0.35));
  animation: sparkleDrift 14s ease-in-out infinite;
}
.sparkle--sm { opacity: 0.4; animation-duration: 18s; animation-delay: -6s; }

.results__spark { top: 12%; right: 7%; }
.results__spark--b { top: 30%; right: 13%; }
.cta-band__spark { top: 18%; right: 9%; }
.cta-band__spark--b { top: 62%; right: 15%; }
.case-hero__spark { top: 24%; right: 6%; }

@media (max-width: 900px) {
  .cta-band__spark { right: 4%; top: 10%; }
  .cta-band__spark--b,
  .results__spark--b,
  .case-hero__spark { display: none; }
  .results__spark { right: 4%; top: 6%; }
}
@keyframes sparkleDrift {
  0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg) scale(1); }
  50%      { transform: translate3d(-6px, 10px, 0) rotate(38deg) scale(1.08); }
}

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Honeypot. Deliberately NOT .visually-hidden: that class is meant to keep
   content available to screen readers, which is the opposite of what a trap
   needs. And deliberately not display:none either -- the crawlers worth
   catching skip those. Off-screen, aria-hidden in the markup, out of the tab
   order: invisible to people and to assistive tech, still there for a bot
   that walks the DOM and fills every input it finds. */
.hp {
  position: absolute;
  left: -9999px;
  top: 0;
  width: 1px;
  height: 1px;
  overflow: hidden;
  pointer-events: none;
}

/* Reporting index — replaces a grid of identical NDA chips */
.report-list {
  margin-top: clamp(34px, 4vw, 52px);
  border-top: 1px solid var(--line);
  counter-reset: none;
}
.report-row {
  display: grid;
  grid-template-columns: 46px minmax(0, 1.6fr) minmax(0, 1fr);
  gap: clamp(12px, 2vw, 28px);
  align-items: baseline;
  padding-block: clamp(15px, 1.8vw, 21px);
  border-bottom: 1px solid var(--line);
  transition: padding-left var(--dur) var(--ease), background-color var(--dur) var(--ease);
}
.report-row:hover { padding-left: 12px; background: var(--surface-1); }
.report-row__num {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.16em;
  color: var(--accent);
}
.report-row__label {
  font-size: clamp(1rem, 1.5vw, 1.16rem);
  font-weight: 600;
  letter-spacing: -0.018em;
  color: var(--ink);
}
.report-row__note {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  line-height: 1.5;
}
@media (max-width: 620px) {
  .report-row { grid-template-columns: 36px minmax(0, 1fr); row-gap: 5px; }
  .report-row__note { grid-column: 2; }
}

.nda-note {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-4);
}

.case__cta {
  margin-top: 16px;
  padding-top: 15px;
  border-top: 1px solid var(--line);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--accent-hi);
}
.case__cta svg { transition: transform var(--dur) var(--ease); }
.card:hover .case__cta svg { transform: translate(3px, -3px); }

/* ------------------------------------------------------------- Case page */

.case-hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: clamp(30px, 5vw, 80px);
  align-items: start;
}
.case-hero__code {
  font-family: var(--font-mono);
  font-size: clamp(1.5rem, 3vw, 2.1rem);
  letter-spacing: 0.16em;
  font-weight: 300;
  color: var(--accent-hi);
}
.case-hero__facts { padding-top: clamp(8px, 2vw, 26px); }

.case-body {
  display: grid;
  gap: clamp(24px, 3vw, 40px);
  margin-top: clamp(12px, 2vw, 24px);
}
.case-step {
  display: grid;
  grid-template-columns: minmax(0, 0.7fr) minmax(0, 1.6fr);
  gap: clamp(18px, 4vw, 64px);
  padding-top: clamp(20px, 2.4vw, 30px);
  border-top: 1px solid var(--line);
}
.case-step__key { display: flex; flex-direction: column; gap: 10px; }
.case-step__num {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.16em;
  color: var(--accent);
}
.case-step__title {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 500;
}
.case-step__text {
  font-size: var(--fs-lead);
  line-height: 1.62;
  color: var(--ink-2);
  max-width: var(--measure-prose);
}
.case-chart { margin-top: clamp(34px, 4vw, 56px); }

@media (max-width: 900px) {
  .case-hero__grid { grid-template-columns: minmax(0, 1fr); }
  .case-step { grid-template-columns: minmax(0, 1fr); gap: 12px; }
}

/* -------------------------------------------------- Generated vector marks */

/* Shared pattern definitions, referenced by every generated graphic */
.viz-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

.article-card__cover {
  display: block;
  position: relative;
  margin: calc(-1 * clamp(20px, 2.2vw, 28px)) calc(-1 * clamp(20px, 2.2vw, 28px)) 2px;
  height: 118px;
  overflow: hidden;
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(123, 140, 255, 0.07), rgba(0, 0, 0, 0.16));
}
.article-card__cover .mark {
  width: 100%;
  height: 100%;
  display: block;
  transition: transform 0.9s var(--ease), opacity var(--dur) var(--ease);
  opacity: 0.9;
}
.card:hover .article-card__cover .mark { transform: scale(1.045); opacity: 1; }
.article-card__cover::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 46%;
  background: linear-gradient(180deg, transparent, rgba(6, 6, 7, 0.75));
  pointer-events: none;
}

/* ------------------------------------------------------------ Shape charts */

.shape-grid {
  margin-top: clamp(38px, 4.4vw, 62px);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(16px, 1.8vw, 24px);
}
.shape-grid .shape-chart:first-child { grid-column: 1 / -1; }
.shape-chart {
  margin: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background:
    var(--panel-glow),
    var(--panel-fill);
  padding: clamp(18px, 2vw, 26px);
  transition: border-color var(--dur) var(--ease);
}
.shape-chart:hover { border-color: var(--accent-line); }
.shape-chart svg { width: 100%; height: auto; display: block; }
.shape-chart__cap {
  margin-top: clamp(14px, 1.6vw, 20px);
  padding-top: clamp(12px, 1.4vw, 16px);
  border-top: 1px solid var(--line);
  font-size: var(--fs-xs);
  color: var(--ink-2);
  line-height: 1.6;
  max-width: 62ch;
}

@media (max-width: 1024px) {
}
@media (max-width: 760px) {
  .shape-grid { grid-template-columns: minmax(0, 1fr); }
  .article-card__cover { height: 96px; }
}
@media (max-width: 440px) {
}

/* Article card */
.articles { display: grid; gap: clamp(16px, 1.8vw, 22px); }
.articles--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.articles--home { margin-top: clamp(40px, 4.6vw, 64px); }

.article-card { padding: clamp(20px, 2.2vw, 28px); gap: 16px; height: 100%; }
.article-card__top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.article-card__cat {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--accent-hi);
  border: 1px solid var(--accent-line);
  border-radius: 999px;
  padding: 4px 10px;
  background: var(--accent-dim);
}
.article-card__meta {
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-4);
  white-space: nowrap;
}
.article-card__title {
  font-size: var(--fs-h4);
  font-weight: 700;
  letter-spacing: -0.022em;
  line-height: 1.28;
  transition: opacity var(--dur-fast) var(--ease);
}
.article-card__excerpt { font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.62; }
.article-card__foot {
  margin-top: auto;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.article-card__foot svg { transition: transform var(--dur) var(--ease); }
.card:hover .article-card__foot svg { transform: translateX(4px); }

/* --------------------------------------------------------------------------
   16. Accordion (FAQ, services, jobs)
   -------------------------------------------------------------------------- */

.accordion { border-top: 1px solid var(--line); margin-top: clamp(36px, 4vw, 56px); }
.acc {
  border-bottom: 1px solid var(--line);
}
.acc__trigger {
  width: 100%;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: clamp(16px, 3vw, 48px);
  padding: clamp(18px, 2.2vw, 28px) 0;
  background: none;
  border: 0;
  text-align: left;
  cursor: pointer;
  color: var(--ink-2);
  transition: color var(--dur-fast) var(--ease);
}
.acc__trigger:hover { color: var(--ink); }
.acc__trigger[aria-expanded="true"] { color: var(--ink); }
.acc__q {
  font-size: clamp(1.02rem, 1.7vw, 1.32rem);
  font-weight: 700;
  letter-spacing: -0.022em;
  line-height: 1.35;
  max-width: 46ch;
  display: flex;
  gap: 16px;
  align-items: baseline;
}
.acc__q .num { font-size: var(--fs-mono); color: var(--accent); letter-spacing: 0.14em; flex: none; }
.acc__icon { position: relative; width: 14px; height: 14px; flex: none; margin-top: 6px; }
.acc__icon::before, .acc__icon::after {
  content: "";
  position: absolute;
  background: currentColor;
  transition: transform var(--dur) var(--ease), opacity var(--dur-fast) var(--ease);
}
.acc__icon::before { top: 50%; left: 0; width: 100%; height: 1.5px; transform: translateY(-50%); }
.acc__icon::after { left: 50%; top: 0; height: 100%; width: 1.5px; transform: translateX(-50%); }
.acc__trigger[aria-expanded="true"] .acc__icon::after { transform: translateX(-50%) rotate(90deg); opacity: 0; }

.acc__panel {
  overflow: hidden;
  height: 0;
  transition: height 0.42s var(--ease);
}
/* Clipping to height 0 hides a panel from the eye and from nobody else: the
   answer is still read out and its links are still tabbed through. The
   accordion module puts `hidden` on a collapsed panel once the height
   transition has finished, which is the one mechanism that takes a subtree out
   of both the accessibility tree and the tab order without breaking the
   animation. Rule 2 of main.js applies, so it has to survive that file not
   running: with no JS the panels are simply open. */
.no-js .acc__panel { height: auto; }
.acc__body {
  padding-bottom: clamp(20px, 2.4vw, 30px);
  padding-right: clamp(0px, 6vw, 120px);
  padding-left: clamp(0px, 3vw, 44px);
  color: var(--ink-2);
  font-size: var(--fs-sm);
  line-height: 1.7;
  max-width: 74ch;
}

/* --------------------------------------------------------------------------
   17. Service blocks (services page)
   -------------------------------------------------------------------------- */

.service {
  border-top: 1px solid var(--line);
  padding-block: clamp(40px, 5vw, 76px);
  scroll-margin-top: calc(var(--header-h) + 24px);
}
.service__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
  gap: clamp(24px, 4vw, 72px);
  align-items: start;
}
.service__num {
  font-family: var(--font-mono);
  font-size: clamp(2.4rem, 5vw, 3.6rem);
  font-weight: 300;
  line-height: 0.9;
  letter-spacing: -0.04em;
  color: transparent;
  -webkit-text-stroke: 1px var(--accent-line);
}
.service__title { font-size: clamp(1.6rem, 3.4vw, 2.5rem); font-weight: 800; letter-spacing: -0.034em; margin-top: 16px; }
.service__kicker {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-top: 14px;
  line-height: 1.7;
}
.service__summary { font-size: var(--fs-lead); color: var(--ink); line-height: 1.5; font-weight: 500; letter-spacing: -0.015em; max-width: 34ch; }
.service__pa { margin-top: clamp(22px, 2.6vw, 32px); display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(20px, 2.6vw, 36px); }
.service__pa-block { display: flex; flex-direction: column; gap: 10px; padding-top: 15px; border-top: 1px solid var(--line); }
.service__pa-key {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.service__pa-block p { font-size: var(--fs-sm); color: var(--ink-2); line-height: 1.66; }

.service__detail {
  margin-top: clamp(30px, 3.6vw, 48px);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(20px, 2.6vw, 40px);
}
.service__col { display: flex; flex-direction: column; gap: 14px; }
.service__col-key {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding-bottom: 13px;
  border-bottom: 1px solid var(--line);
}
.step-list { counter-reset: step; display: flex; flex-direction: column; }
.step-list li {
  counter-increment: step;
  display: grid;
  grid-template-columns: 30px 1fr;
  gap: 10px;
  padding-block: 11px;
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-xs);
  color: var(--ink-2);
  line-height: 1.55;
}
.step-list li::before {
  content: counter(step, decimal-leading-zero);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.1em;
  color: var(--ink-4);
  padding-top: 2px;
}
.tick-list { display: flex; flex-direction: column; }
.tick-list li {
  display: grid;
  grid-template-columns: 16px 1fr;
  gap: 10px;
  padding-block: 11px;
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-xs);
  color: var(--ink-2);
  line-height: 1.55;
}
.tick-list li::before {
  content: "";
  width: 5px; height: 5px;
  background: var(--ink-3);
  transform: rotate(45deg);
  margin-top: 7px;
}
.service__outcome {
  margin-top: clamp(24px, 3vw, 36px);
  padding: clamp(20px, 2.4vw, 30px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background:
    var(--panel-glow),
    var(--panel-fill);
  display: flex;
  gap: clamp(16px, 2.4vw, 32px);
  align-items: baseline;
  flex-wrap: wrap;
}
.service__outcome p { font-size: var(--fs-lead); line-height: 1.5; letter-spacing: -0.015em; max-width: 58ch; }

/* Services index (top of services page) */
.svc-index {
  margin-top: clamp(34px, 4vw, 54px);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.svc-index__item {
  background: var(--bg);
  padding: clamp(18px, 2.2vw, 26px);
  display: flex;
  flex-direction: column;
  gap: 10px;
  transition: background-color var(--dur) var(--ease);
}
.svc-index__item:hover { background: var(--surface-2); }
.svc-index__num { font-family: var(--font-mono); font-size: var(--fs-mono); letter-spacing: 0.16em; color: var(--accent); }
.svc-index__title { font-size: var(--fs-h4); font-weight: 700; letter-spacing: -0.02em; }
.svc-index__sum { font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.55; }

/* --------------------------------------------------------------------------
   18. Principles / team / why grids
   -------------------------------------------------------------------------- */

.tiles {
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  margin-top: clamp(38px, 4.4vw, 62px);
}
.tiles--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.tiles--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.tile {
  background: var(--bg);
  padding: clamp(24px, 2.8vw, 38px);
  display: flex;
  flex-direction: column;
  gap: 13px;
  min-height: 210px;
  position: relative;
  overflow: hidden;
  transition: background-color var(--dur) var(--ease);
}
.tile::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(90% 70% at 0% 0%, var(--accent-dim), transparent 60%);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
  pointer-events: none;
}
.tile::after {
  content: "";
  position: absolute;
  top: 0; left: 0; bottom: 0;
  width: 2px;
  background: var(--accent);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 0.5s var(--ease);
}
.tile:hover { background: var(--surface-1); }
.tile:hover::before { opacity: 1; }
.tile:hover::after { transform: scaleY(1); }
.tile > * { position: relative; }
.tile__num {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.16em;
  color: var(--accent);
}
.tile__title { font-size: var(--fs-h4); font-weight: 700; letter-spacing: -0.02em; max-width: 20ch; }
.tile__text { font-size: var(--fs-sm); color: var(--ink-3); line-height: 1.64; }
.tile__skills { margin-top: auto; padding-top: 16px; display: flex; flex-wrap: wrap; gap: 6px; }
.tile__skill {
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 5px 10px;
}

/* --------------------------------------------------------------------------
   19. Jobs
   -------------------------------------------------------------------------- */

.jobs { border-top: 1px solid var(--line); margin-top: clamp(36px, 4vw, 56px); }
.job { border-bottom: 1px solid var(--line); }
.job__trigger {
  width: 100%;
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: clamp(14px, 2.4vw, 34px);
  padding: clamp(20px, 2.4vw, 30px) 0;
  background: none; border: 0;
  text-align: left;
  cursor: pointer;
  color: var(--ink);
  transition: padding-left var(--dur) var(--ease);
}
.job__trigger:hover { padding-left: 10px; }
.job__title { font-size: clamp(1.15rem, 2.2vw, 1.7rem); font-weight: 700; letter-spacing: -0.028em; }
.job__sum { font-size: var(--fs-xs); color: var(--ink-3); margin-top: 7px; max-width: 58ch; line-height: 1.6; }
.job__tags { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.job__tag {
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-3);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 5px 10px;
  white-space: nowrap;
}
.job__body {
  padding-bottom: clamp(24px, 3vw, 38px);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(20px, 2.6vw, 40px);
}
.job__actions { margin-top: clamp(20px, 2.4vw, 28px); padding-bottom: clamp(20px, 2.4vw, 30px); }

/* Hiring steps */
.steps {
  margin-top: clamp(38px, 4.4vw, 60px);
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: clamp(14px, 1.8vw, 26px);
}
.step {
  display: flex;
  flex-direction: column;
  gap: 11px;
  padding-top: clamp(18px, 2vw, 24px);
  border-top: 1px solid var(--line-2);
  position: relative;
}
.step__num {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.16em;
  color: var(--accent);
}
.step__title { font-size: var(--fs-h4); font-weight: 700; letter-spacing: -0.02em; }
.step__text { font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.6; }

/* --------------------------------------------------------------------------
   20. Insights hub
   -------------------------------------------------------------------------- */

.hub-controls {
  margin-top: clamp(36px, 4vw, 56px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(16px, 3vw, 40px);
  flex-wrap: wrap;
  padding-bottom: clamp(20px, 2.4vw, 28px);
  border-bottom: 1px solid var(--line);
}
.hub-search {
  position: relative;
  flex: 1 1 260px;
  max-width: 340px;
}
.hub-search input {
  width: 100%;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 11px 16px 11px 40px;
  font-size: var(--fs-sm);
  color: var(--ink);
  transition: border-color var(--dur-fast) var(--ease);
}
.hub-search input::placeholder { color: var(--ink-4); }
.hub-search input:focus { border-color: var(--line-3); outline: none; }
.hub-search svg { position: absolute; left: 15px; top: 50%; transform: translateY(-50%); opacity: 0.4; pointer-events: none; }

.hub-filters { display: flex; flex-wrap: wrap; gap: 7px; }
.hub-filter {
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  transition: border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
  white-space: nowrap;
}
.hub-filter:hover { color: var(--ink); border-color: var(--accent-line); }
.hub-filter.is-active {
  background: var(--accent);
  color: #07070c;
  border-color: var(--accent);
  box-shadow: 0 6px 22px -8px var(--accent-glow);
}

.hub-count {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-top: clamp(20px, 2.4vw, 28px);
}

.hub-grid { margin-top: clamp(20px, 2.4vw, 28px); }
.hub-empty {
  padding: clamp(48px, 8vw, 96px) 0;
  text-align: center;
  display: none;
  flex-direction: column;
  gap: 12px;
  align-items: center;
}
.hub-empty.is-visible { display: flex; }
.hub-empty__title { font-size: var(--fs-h3); font-weight: 700; letter-spacing: -0.025em; }

/* Newsletter */
.news {
  margin-top: clamp(48px, 6vw, 84px);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(28px, 3.6vw, 48px);
  background:
    var(--panel-glow),
    var(--panel-fill);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(24px, 4vw, 56px);
  align-items: center;
}
.news__form { display: flex; gap: 10px; flex-wrap: wrap; }
.news__form input {
  flex: 1 1 200px;
  background: transparent;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  padding: 13px 18px;
  font-size: var(--fs-sm);
  color: var(--ink);
}
.news__form input::placeholder { color: var(--ink-4); }
.news__note { font-size: var(--fs-xs); color: var(--ink-4); margin-top: 12px; }

/* --------------------------------------------------------------------------
   21. Article page
   -------------------------------------------------------------------------- */

.article-hero {
  padding-top: calc(var(--header-h) + clamp(40px, 6vw, 76px));
  padding-bottom: clamp(28px, 3.4vw, 44px);
  border-bottom: 1px solid var(--line);
}
.article-hero__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: clamp(20px, 2.4vw, 28px);
}
.article-hero__cat { color: var(--ink-2); }
.article-hero__title {
  font-size: clamp(2rem, 4.6vw, 3.6rem);
  font-weight: 800;
  letter-spacing: -0.036em;
  line-height: 1.04;
  max-width: 20ch;
}
.article-hero__lead {
  margin-top: clamp(20px, 2.4vw, 30px);
  font-size: var(--fs-lead);
  color: var(--ink-2);
  line-height: 1.58;
  max-width: 58ch;
}

.article-layout {
  display: grid;
  grid-template-columns: minmax(0, 220px) minmax(0, 1fr);
  gap: clamp(32px, 6vw, 96px);
  padding-block: clamp(40px, 5vw, 72px);
  align-items: start;
}
.article-toc { position: sticky; top: calc(var(--header-h) + 32px); display: flex; flex-direction: column; gap: 14px; }
.article-toc__key {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-4);
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}
.article-toc__list { display: flex; flex-direction: column; gap: 2px; }
.article-toc__list a {
  font-size: var(--fs-xs);
  color: var(--ink-3);
  padding: 7px 0 7px 14px;
  border-left: 1px solid var(--line);
  line-height: 1.45;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.article-toc__list a:hover, .article-toc__list a.is-active { color: var(--ink); border-left-color: var(--accent); }

.prose { max-width: var(--measure-prose); }
.prose h2 {
  font-size: clamp(1.3rem, 2.4vw, 1.8rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  margin-top: clamp(38px, 4vw, 56px);
  margin-bottom: 16px;
  scroll-margin-top: calc(var(--header-h) + 24px);
}
.prose h2:first-child { margin-top: 0; }
.prose h3 {
  font-size: var(--fs-h4);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-top: clamp(26px, 3vw, 36px);
  margin-bottom: 12px;
}
.prose p { color: var(--ink-2); line-height: 1.75; margin-bottom: 1.05em; font-size: 1.02rem; }
.prose ul, .prose ol { display: flex; flex-direction: column; gap: 12px; margin-bottom: 1.6em; margin-top: 0.4em; }
.prose ul li {
  display: grid;
  grid-template-columns: 16px 1fr;
  gap: 12px;
  color: var(--ink-2);
  line-height: 1.7;
  font-size: 1.02rem;
}
.prose ul li::before {
  content: "";
  width: 5px; height: 5px;
  background: var(--ink-4);
  transform: rotate(45deg);
  margin-top: 11px;
}
.prose ol { counter-reset: p; }
.prose ol li {
  counter-increment: p;
  display: grid;
  grid-template-columns: 30px 1fr;
  gap: 12px;
  color: var(--ink-2);
  line-height: 1.7;
  font-size: 1.02rem;
}
.prose ol li::before {
  content: counter(p, decimal-leading-zero);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  color: var(--ink-4);
  padding-top: 5px;
}
.prose .callout {
  margin: clamp(28px, 3.4vw, 44px) 0;
  padding: clamp(20px, 2.4vw, 28px) clamp(20px, 2.6vw, 32px);
  border-left: 1px solid var(--line-3);
  background: linear-gradient(90deg, rgba(255,255,255,0.045), rgba(255,255,255,0));
  font-size: clamp(1.05rem, 1.7vw, 1.28rem);
  line-height: 1.5;
  letter-spacing: -0.018em;
  font-weight: 500;
  color: var(--ink);
}

.article-takeaways {
  margin-top: clamp(40px, 4.6vw, 62px);
  padding: clamp(24px, 2.8vw, 36px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background:
    var(--panel-glow),
    var(--panel-fill);
}
.article-takeaways__key {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 18px;
}
/* Related services — turns a read into a next step */
.svc-links {
  margin-top: clamp(30px, 3.4vw, 44px);
  border-top: 1px solid var(--line);
  padding-top: clamp(18px, 2vw, 24px);
}
.svc-links__key {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 14px;
}
.svc-link {
  display: grid;
  grid-template-columns: 34px 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 15px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-1);
  margin-bottom: 8px;
  transition: border-color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease);
}
.svc-link:hover { border-color: var(--accent-line); background: var(--accent-dim); transform: translateX(3px); }
.svc-link__num {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.14em;
  color: var(--accent);
}
.svc-link__body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.svc-link__title { font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }
.svc-link__sum { font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.5; }
.svc-link svg { color: var(--ink-4); flex: none; }
.svc-link:hover svg { color: var(--accent-hi); }

.article-foot {
  margin-top: clamp(32px, 4vw, 50px);
  padding-top: clamp(22px, 2.6vw, 30px);
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
}
.article-foot__author {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-4);
}

/* --------------------------------------------------------------------------
   22. Contact / forms
   -------------------------------------------------------------------------- */

.contact-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(32px, 5vw, 88px);
  align-items: start;
}

.info-list { display: flex; flex-direction: column; border-top: 1px solid var(--line); }
.info-row {
  display: grid;
  grid-template-columns: minmax(96px, 0.5fr) minmax(0, 1fr);
  gap: 16px;
  padding-block: 16px;
  border-bottom: 1px solid var(--line);
  align-items: baseline;
}
.info-row__key {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.info-row__val {
  font-size: var(--fs-sm);
  color: var(--ink);
  line-height: 1.55;
  min-width: 0;
  /* Email addresses are long and unbreakable — never let them push the page */
  overflow-wrap: anywhere;
}
.info-row__val a { border-bottom: 1px solid var(--line-2); padding-bottom: 1px; transition: border-color var(--dur-fast) var(--ease); }
.info-row__val a:hover { border-color: var(--accent); color: var(--accent-hi); }

.form {
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(24px, 3.2vw, 44px);
  background:
    var(--panel-glow),
    var(--panel-fill);
  position: relative;
  overflow: hidden;
}
.form__title {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-4);
  padding-bottom: clamp(20px, 2.4vw, 28px);
  margin-bottom: clamp(22px, 2.6vw, 30px);
  border-bottom: 1px solid var(--line);
}
.form__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(16px, 1.8vw, 22px); }
.field { display: flex; flex-direction: column; gap: 8px; }
.field--full { grid-column: 1 / -1; }
.field__label {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-3);
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.field__opt { color: var(--ink-4); text-transform: none; letter-spacing: 0.06em; }
.field input,
.field select,
.field textarea {
  width: 100%;
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 13px 15px;
  font-size: var(--fs-sm);
  color: var(--ink);
  transition: border-color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
  appearance: none;
  -webkit-appearance: none;
}
.field textarea { min-height: 132px; resize: vertical; line-height: 1.6; }
.field input::placeholder, .field textarea::placeholder { color: var(--ink-4); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--line-3);
  background: rgba(0, 0, 0, 0.4);
}
.field select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%23f2f0ec' stroke-opacity='0.45' stroke-width='1.4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 15px center;
  padding-right: 40px;
  cursor: pointer;
}
.field select option { background: #0b0b0d; color: var(--ink); }
.field.has-error input, .field.has-error select, .field.has-error textarea { border-color: rgba(255, 120, 120, 0.55); }
.field__error {
  font-size: var(--fs-xs);
  color: rgba(255, 150, 150, 0.85);
  display: none;
}
/* The message itself is the part of the signal that survives colour blindness,
   a monochrome display and a printed page -- so it leads with a mark that has
   a shape, not only a hue. */
.checkbox.has-error .field__error::before {
  content: "!\00a0";
  font-weight: 700;
}
.field.has-error .field__error { display: block; }

.checkbox {
  display: grid;
  grid-template-columns: 18px 1fr;
  gap: 12px;
  align-items: start;
  cursor: pointer;
  font-size: var(--fs-xs);
  color: var(--ink-3);
  line-height: 1.55;
}
.checkbox input { position: absolute; opacity: 0; width: 0; height: 0; }
.checkbox__box {
  width: 18px; height: 18px;
  border: 1px solid var(--line-2);
  border-radius: 5px;
  position: relative;
  margin-top: 2px;
  transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.checkbox__box::after {
  content: "";
  position: absolute;
  left: 5px; top: 1.5px;
  width: 5px; height: 10px;
  border: solid #08080a;
  border-width: 0 1.6px 1.6px 0;
  transform: rotate(45deg) scale(0);
  transition: transform var(--dur-fast) var(--ease);
}
.checkbox input:checked ~ .checkbox__box { background: var(--ink); border-color: var(--ink); }
.checkbox input:checked ~ .checkbox__box::after { transform: rotate(45deg) scale(1); }
.checkbox input:focus-visible ~ .checkbox__box { outline: 2px solid var(--ink); outline-offset: 3px; }
.checkbox.has-error .checkbox__box { border-color: rgba(255, 120, 120, 0.6); }
/* The consent error span sits inside <label class="checkbox">, not inside a
   .field, so the reveal rule above never matched it: the visitor pressed Send,
   the box changed hue by a shade and nothing else happened. The label is a
   two-column grid, so the message has to be put in the text column or it
   renders 18px wide under the box. */
.checkbox.has-error .field__error { display: block; grid-column: 2; }
/* Send is usually pressed with a mouse, and a programmatic focus after a mouse
   click does not match :focus-visible -- so the field the validator jumped to
   would otherwise show no ring at all. */
.checkbox.has-error input:focus ~ .checkbox__box { outline: 2px solid rgba(255, 120, 120, 0.8); outline-offset: 3px; }

.form__foot { margin-top: clamp(22px, 2.6vw, 30px); display: flex; flex-direction: column; gap: 18px; }

.form__status {
  display: none;
  flex-direction: column;
  gap: 10px;
  padding: clamp(20px, 2.4vw, 28px);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.03);
}
.form__status.is-visible { display: flex; }
.form__status-title { font-size: var(--fs-h4); font-weight: 700; letter-spacing: -0.02em; }
.form__status p { font-size: var(--fs-sm); color: var(--ink-3); line-height: 1.6; }

.expect { display: flex; flex-direction: column; gap: clamp(20px, 2.4vw, 28px); margin-top: clamp(34px, 4vw, 48px); }
.expect__item { display: grid; grid-template-columns: 40px 1fr; gap: 16px; padding-top: 18px; border-top: 1px solid var(--line); }
.expect__num { font-family: var(--font-mono); font-size: var(--fs-mono); letter-spacing: 0.14em; color: var(--accent); padding-top: 3px; }
.expect__title { font-size: var(--fs-h4); font-weight: 700; letter-spacing: -0.02em; margin-bottom: 8px; }
.expect__text { font-size: var(--fs-sm); color: var(--ink-3); line-height: 1.62; }

/* --------------------------------------------------------------------------
   23. CTA band
   -------------------------------------------------------------------------- */

.cta-band {
  position: relative;
  border-top: 1px solid var(--line);
  padding-block: clamp(56px, 8vw, 120px);
  overflow: hidden;
}
.cta-band::before {
  content: "";
  position: absolute;
  inset: auto 0 -60% 0;
  height: 120%;
  background: radial-gradient(50% 60% at 50% 100%, rgba(123, 140, 255, 0.16), transparent 70%);
  pointer-events: none;
}
.cta-band__inner { display: flex; flex-direction: column; align-items: center; text-align: center; gap: clamp(18px, 2.2vw, 26px); }
.cta-band__title {
  font-size: clamp(2rem, 5.4vw, 4.2rem);
  font-weight: 800;
  letter-spacing: -0.038em;
  line-height: 1.02;
  max-width: 17ch;
}
.cta-band__lead { max-width: 54ch; color: var(--ink-2); font-size: var(--fs-lead); line-height: 1.58; }
.cta-band__actions { margin-top: clamp(10px, 1.4vw, 18px); display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; }

/* --------------------------------------------------------------------------
   24. Footer
   -------------------------------------------------------------------------- */

.footer {
  border-top: 1px solid var(--line);
  padding-top: clamp(48px, 6vw, 80px);
  padding-bottom: clamp(28px, 3vw, 40px);
  background: var(--bg-sunken);
  position: relative;
  z-index: 1;
}
.footer__top {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) repeat(4, minmax(0, 1fr));
  gap: clamp(28px, 3vw, 48px);
  padding-bottom: clamp(40px, 5vw, 64px);
}
.footer__brand { display: flex; flex-direction: column; gap: 20px; max-width: 34ch; }
.footer__tagline { font-size: var(--fs-sm); color: var(--ink-3); line-height: 1.65; }
.footer__col { display: flex; flex-direction: column; gap: 13px; }
.footer__key {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 3px;
}
.footer__link {
  font-size: var(--fs-sm);
  color: var(--ink-3);
  transition: color var(--dur-fast) var(--ease);
  width: fit-content;
  max-width: 100%;
  overflow-wrap: anywhere;
}
.footer__link:hover { color: var(--ink); }

.footer__langs { display: flex; flex-wrap: wrap; gap: 6px; }
.footer__lang {
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-4);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 5px 9px;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.footer__lang:hover { color: var(--ink); border-color: var(--line-2); }
.footer__lang[aria-current="true"] { color: var(--ink); border-color: var(--line-2); }

.footer__bottom {
  border-top: 1px solid var(--line);
  padding-top: clamp(20px, 2.4vw, 28px);
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: clamp(20px, 3vw, 48px);
  flex-wrap: wrap;
}
.footer__legal { font-size: var(--fs-xs); color: var(--ink-4); max-width: 62ch; line-height: 1.6; }
.footer__meta { display: flex; gap: 18px; flex-wrap: wrap; align-items: center; }
.footer__meta a, .footer__meta span {
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-4);
  line-height: 1.6;
  /* Copyright strings run long in CS/UK — let them wrap, keep links intact */
  overflow-wrap: anywhere;
}
.footer__meta a { white-space: nowrap; }
.footer__meta a:hover { color: var(--ink-2); }

/* --------------------------------------------------------------------------
   25. Page hero (interior pages)
   -------------------------------------------------------------------------- */

.page-hero {
  padding-top: calc(var(--header-h) + clamp(48px, 7vw, 96px));
  padding-bottom: clamp(36px, 5vw, 64px);
  position: relative;
}
.page-hero__title {
  font-size: var(--fs-h1);
  font-weight: 800;
  letter-spacing: var(--track-display);
  line-height: 1.0;
  max-width: 17ch;
  margin-top: clamp(20px, 2.4vw, 30px);
}
.page-hero__lead { margin-top: clamp(22px, 2.6vw, 32px); max-width: 60ch; }
.page-hero__actions { margin-top: clamp(26px, 3vw, 36px); display: flex; gap: 12px; flex-wrap: wrap; }

.breadcrumb {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-4);
  flex-wrap: wrap;
}
.breadcrumb a { transition: color var(--dur-fast) var(--ease); }
.breadcrumb a:hover { color: var(--ink-2); }

/* --------------------------------------------------------------------------
   26. Legal page
   -------------------------------------------------------------------------- */

.legal-layout {
  display: grid;
  grid-template-columns: minmax(0, 200px) minmax(0, 1fr);
  gap: clamp(32px, 6vw, 88px);
  padding-block: clamp(30px, 4vw, 56px);
  align-items: start;
}
.legal-section { padding-top: clamp(30px, 3.6vw, 48px); scroll-margin-top: calc(var(--header-h) + 24px); }
.legal-section + .legal-section { border-top: 1px solid var(--line); margin-top: clamp(30px, 3.6vw, 48px); }
.legal-section__title { font-size: clamp(1.4rem, 2.6vw, 1.9rem); font-weight: 800; letter-spacing: -0.03em; margin-bottom: 20px; }

/* --------------------------------------------------------------------------
   27. 404
   -------------------------------------------------------------------------- */

.nf {
  min-height: 76vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-top: calc(var(--header-h) + 40px);
  padding-bottom: 60px;
}
.nf__code {
  font-family: var(--font-mono);
  font-size: clamp(4rem, 16vw, 12rem);
  font-weight: 200;
  line-height: 0.85;
  letter-spacing: -0.05em;
  color: transparent;
  -webkit-text-stroke: 1px var(--accent-line);
}
.nf__title { font-size: var(--fs-h1); font-weight: 800; letter-spacing: -0.035em; margin-top: clamp(20px, 3vw, 34px); max-width: 16ch; }
.nf__links { margin-top: clamp(28px, 3.4vw, 40px); display: flex; gap: 10px; flex-wrap: wrap; }

/* --------------------------------------------------------------------------
   27b. Floating controls — reading progress, back to top
   --------------------------------------------------------------------------

   Both were shipped as markup plus a driver in main.js and no rules at all, so
   the progress bar was a zero-height box painting nothing and the back-to-top
   button was a native grey control sitting in the page flow under the footer
   from first paint. They are given here the treatment the rest of the site
   already implies: a hairline in the accent for the bar, the panel recipe and
   a hairline ring for the button. */

.read-bar {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 2px;
  /* Above the header: the header is opaque once stuck, and a progress bar
     painted underneath it is a progress bar nobody sees. */
  z-index: calc(var(--z-header) + 1);
  background: var(--line);
  pointer-events: none;
}
.read-bar i {
  /* The <i> is what main.js scales. It has to be a block for a width-less
     inline box to have anything to scale. */
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--accent-hi));
  transform: scaleX(0);
  transform-origin: left center;
}

.to-top {
  position: fixed;
  right: clamp(16px, 3vw, 28px);
  bottom: clamp(16px, 3vw, 28px);
  z-index: var(--z-header);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Through a custom property because the 44px touch-target rule for this
     button lives in section 8b, higher up the file: a plain `width` here would
     be the later declaration and would silently undo it. */
  width: var(--to-top-size, 42px);
  height: var(--to-top-size, 42px);
  border: 1px solid var(--line);
  border-radius: 999px;
  background-color: var(--bg-raised);
  background-image: var(--panel-fill);
  color: var(--ink-2);
  cursor: pointer;
  /* Hidden until main.js says the page has scrolled far enough to want it.
     visibility is delayed off by the full duration so the button fades out
     rather than vanishing, and is taken out of the tab order in between. */
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease),
              border-color var(--dur) var(--ease), color var(--dur) var(--ease),
              visibility 0s linear var(--dur);
}
.to-top.is-visible {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}
.to-top:hover { border-color: var(--accent-line); color: var(--ink); }
.to-top:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

/* --------------------------------------------------------------------------
   28. Reveal animation
   -------------------------------------------------------------------------- */

[data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.75s var(--ease), transform 0.75s var(--ease);
  transition-delay: calc(var(--d, 0) * 70ms);
  will-change: opacity, transform;
}
[data-reveal].is-visible { opacity: 1; transform: none; }
.no-js [data-reveal] { opacity: 1; transform: none; }

/* --------------------------------------------------------------------------
   29. Responsive
   -------------------------------------------------------------------------- */

@media (max-width: 1200px) {
  .loop__steps { grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: clamp(24px, 3vw, 34px); }
  .svc-index { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer__top { grid-template-columns: minmax(0, 1.4fr) repeat(3, minmax(0, 1fr)); }
  .footer__col--langs { grid-column: 2 / -1; }
  .footer__col--langs .footer__langs { max-width: 420px; }
}

@media (max-width: 1024px) {
  :root { --header-h: 66px; }
  .hero__grid { grid-template-columns: minmax(0, 1fr); }
  .hero__copy, .hero__visual { grid-column: 1 / -1; }
  .hero__visual { display: flex; justify-content: center; margin-top: clamp(24px, 4vw, 38px); }
  .nav { display: none; }
  .burger { display: inline-flex; }
  .lang { display: none; }
  .header__actions .btn--header { display: none; }

  .capabilities__layout { grid-template-columns: minmax(0, 1fr); }
  .cap-panel { position: static; min-height: 0; }
  .split, .split--even { grid-template-columns: minmax(0, 1fr); }
  .split__aside { position: static; }
  .article-layout { grid-template-columns: minmax(0, 1fr); }
  .article-toc { display: none; }
  .legal-layout { grid-template-columns: minmax(0, 1fr); }
  .contact-layout { grid-template-columns: minmax(0, 1fr); }
  .service__head { grid-template-columns: minmax(0, 1fr); }
  .service__detail { grid-template-columns: minmax(0, 1fr); gap: clamp(24px, 3vw, 32px); }
  .job__body { grid-template-columns: minmax(0, 1fr); }
  .steps { grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: clamp(22px, 3vw, 30px); }
  .news { grid-template-columns: minmax(0, 1fr); }
  .tiles--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .manifesto__cols { grid-template-columns: minmax(0, 1fr); gap: clamp(24px, 4vw, 34px); }
  .articles--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer__top { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer__brand { grid-column: 1 / -1; }
  .footer__col--langs { grid-column: 1 / -1; }
}

@media (max-width: 900px) {
  .stat-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .stat { border-left: 1px solid var(--line); padding-left: clamp(14px, 4vw, 22px); }
  .stat:first-child { padding-left: 0; border-left: 0; }
  .stat:nth-child(3) { border-left: 0; padding-left: 0; }
  .stat:nth-child(3), .stat:nth-child(4) { border-top: 1px solid var(--line); }
}

@media (max-width: 760px) {
  :root { --section-y: clamp(3.5rem, 12vw, 5rem); --section-y-s: clamp(2.75rem, 9vw, 3.5rem); }

  .loop__steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cases--home { grid-template-columns: minmax(0, 1fr); }
  .articles--3 { grid-template-columns: minmax(0, 1fr); }
  .tiles--3, .tiles--2 { grid-template-columns: minmax(0, 1fr); }
  .svc-index { grid-template-columns: minmax(0, 1fr); }
  .service__pa { grid-template-columns: minmax(0, 1fr); }
  .form__grid { grid-template-columns: minmax(0, 1fr); }
  .hub-controls { flex-direction: column; align-items: stretch; }
  .hub-search { max-width: none; }
  /* Six stacked columns made the mobile footer 1.6 screens tall */
  .footer__top { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 26px 20px; padding-bottom: 30px; }
  .footer { padding-top: clamp(34px, 8vw, 48px); }
  .footer__brand { gap: 14px; }
  .job__trigger { grid-template-columns: 1fr; gap: 14px; }
  .job__tags { justify-content: flex-start; }
  .acc__body { padding-left: 0; padding-right: 0; }
  .article-hero__title { max-width: none; }
  .cta-band__title { max-width: none; }
  .ruled::before { background-size: calc(100% / 3) 100%; }
}

@media (max-width: 400px) {
  .info-row { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .menu__contact a { overflow-wrap: anywhere; }
}

@media (max-width: 480px) {
  :root { --gutter: 20px; }
  .loop__steps { grid-template-columns: minmax(0, 1fr); }
  .steps { grid-template-columns: minmax(0, 1fr); }
  .btn { --btn-pad-x: 1.35rem; width: 100%; }
  .hero__actions .btn, .cta-band__actions .btn, .nf__links .btn { width: 100%; }
}

/* --------------------------------------------------------------------------
   30. Preferences & print
   -------------------------------------------------------------------------- */

/* Everything here is gated on html:not(.force-motion).

   .force-motion is set only when the URL carries ?motion=on -- a developer
   affordance, because this project is built on a machine whose OS reports
   reduced motion, which makes the whole site look stone dead locally and is
   impossible to review. Nothing sets the class on its own, so a real visitor
   who asked for less motion still gets exactly that. */
@media (prefers-reduced-motion: reduce) {
  html:not(.force-motion) { scroll-behavior: auto; }
  html:not(.force-motion) *,
  html:not(.force-motion) *::before,
  html:not(.force-motion) *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  html:not(.force-motion) [data-reveal] { opacity: 1 !important; transform: none !important; }
  html:not(.force-motion) .hero__line > span { transform: none !important; }
  html:not(.force-motion) .ticker__track { animation: none !important; }
  /* The ticker is decorative and can simply stop. The partner band is not:
     stopping it alone would hide every card past the fold of the row, so it
     also becomes an ordinary scrollable strip. */
  html:not(.force-motion) .partners__track { animation: none !important; }
  html:not(.force-motion) .partners__viewport { overflow-x: auto; }
  html:not(.force-motion) .btn--primary::before { animation: none !important; }
  html:not(.force-motion) .btn__ripple { display: none !important; }
  html:not(.force-motion) .hero__scroll i::after { animation: none !important; opacity: 1 !important; transform: none !important; }
  html:not(.force-motion) .geo-globe canvas { cursor: default; }
  html:not(.force-motion) .hero__orb i { animation: none !important; }
  html:not(.force-motion) .bench__device { transform: none !important; }
  html:not(.force-motion) .hero::before { opacity: 0 !important; }
}

@media print {
  .header, .menu, .grain, .cta-band, .ticker, .bench,
  .read-bar, .to-top { display: none !important; }
  body { background: #fff; color: #000; }
  .chrome-text { color: #000 !important; -webkit-text-fill-color: #000 !important; }
  a { color: #000; }
}

/* ------------------------------------------------------------------- Funnel

   The real acquisition funnel on a case page. Bar width encodes share of the
   top of the funnel and nothing else -- no gradient fills, no perspective, no
   tapering trapezoid. A funnel drawn as a 3D cone misstates every stage after
   the first, because the eye reads area while the data is a length.

   The step rate sits next to the figure it produced rather than floating
   between rows, so a screen reader meets them in the order they are read. */

.funnel { margin: 0; }
.funnel__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(14px, 1.8vw, 22px);
}
.funnel__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
}
.funnel__label {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.funnel__track {
  display: block;
  height: 10px;
  border-radius: 3px;
  background: var(--surface-1);
  box-shadow: inset 0 0 0 1px var(--line);
  overflow: hidden;
}
.funnel__fill {
  display: block;
  height: 100%;
  width: var(--w, 100%);
  border-radius: 3px;
  background: var(--accent);
  /* Grows from nothing on reveal, but only as a width change -- nothing moves
     position, so the figure beside it never appears to drift. */
  transform-origin: left center;
}
/* The bar is at full width by default and the animation only reveals it.
   With `both` the resting state was scaleX(0), so anywhere the animation does
   not run the funnel showed three empty tracks -- print being the case that
   reaches a real person: @media print executes no animations, and the first
   viewport is not hidden from it. The evidence the whole screen exists for
   would have printed blank. */
@media (prefers-reduced-motion: no-preference) {
  .funnel__fill { animation: var(--funnel-draw); }
}
/* ?motion=on is the project review switch and it has to reach this animation
   too: gating the draw on the media query alone made the one authored motion
   of the first viewport unreachable on a machine with reduced motion on --
   which is every machine a reviewer is likely to be sitting at. */
html.force-motion .funnel__fill { animation: var(--funnel-draw); }

/* The cascade is a formula on the step index, not a chain of nth-child rules:
   a four-step funnel used to start its last bar together with its first,
   because the chain stopped at three. */
.funnel__fill {
  --funnel-draw: funnelGrow 1.1s var(--ease) calc(var(--d, 0) * 0.12s) 1 normal both;
}
@keyframes funnelGrow {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

.funnel__value {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-family: var(--font-sans);
  font-variant-numeric: proportional-nums;
  font-size: clamp(1.3rem, 2.2vw, 1.7rem);
  font-weight: 700;
  letter-spacing: -0.035em;
  line-height: 1;
  color: var(--ink);
}
.funnel__rate {
  font-family: var(--font-mono);
  font-style: normal;
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  font-weight: 500;
  color: var(--live);
}
.funnel__caption {
  margin-top: clamp(16px, 2vw, 24px);
  padding-top: 14px;
  border-top: 1px solid var(--line);
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--ink-3);
  max-width: 52ch;
}

/* Traffic quality under the funnel. Hairline-divided cells, same language as
   the metric panel on the case card, so the page states unit prices and
   outcomes in one visual grammar instead of two. */
.quality {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 1px;
  margin: clamp(20px, 2.6vw, 30px) 0 0;
  border-radius: var(--radius-sm);
  overflow: hidden;
  isolation: isolate;
}
.quality__item {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 14px 14px 13px;
  background: var(--bg-sunken);
  box-shadow: 0 0 0 1px var(--line);
}
.quality__label {
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-3);
  line-height: 1.35;
}
.quality__value {
  margin: 0;
  font-family: var(--font-sans);
  font-variant-numeric: proportional-nums;
  font-size: clamp(1.15rem, 1.9vw, 1.4rem);
  font-weight: 700;
  letter-spacing: -0.035em;
  line-height: 1;
  color: var(--ink);
}
.quality__value em {
  font-style: normal;
  font-size: 0.56em;
  font-weight: 600;
  color: var(--ink-3);
}

/* --------------------------------------------------------- Creative formats

   The formats a case ran, and the job each one did. Hairline-divided cells in
   the same vocabulary as the metric panel and the quality strip, so the case
   states creative the way it states everything else.

   No thumbnails by design: a generated preview of an ad that really ran is a
   fabrication, and this site already cut one grid of invented creative tiles.
   The block carries reasoning, which is the part a competitor cannot lift from
   a screenshot anyway. */

.crea-block { margin-top: clamp(40px, 5vw, 72px); }
.crea-block__title {
  font-size: var(--fs-h3);
  font-weight: 700;
  letter-spacing: var(--track-heading);
  line-height: var(--lh-heading);
  color: var(--ink);
  margin: 0 0 clamp(20px, 2.4vw, 30px);
  max-width: 26ch;
}
.crea-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 1px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  isolation: isolate;
}
.crea {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: clamp(18px, 2vw, 24px);
  background: var(--bg-sunken);
  box-shadow: 0 0 0 1px var(--line);
}
.crea__name {
  font-size: var(--fs-h4);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
  color: var(--ink);
  margin: 0;
}
.crea__what {
  margin: 0;
  font-size: var(--fs-xs);
  line-height: 1.6;
  color: var(--ink-2);
}
/* The outcome is the payload: pushed to the bottom edge so the three of them
   line up across the row and can be read as one comparison. */
.crea__outcome {
  margin: auto 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  line-height: 1.45;
  color: var(--live);
}
/* Per-format cost, where a case measured it. Sans and solid, like every other
   figure on the site; the label above it is already doing the mono work. */
.crea__metric {
  margin: 10px 0 0;
  font-family: var(--font-sans);
  font-variant-numeric: proportional-nums;
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--ink);
}

/* ==========================================================================
   Pass — subscription tiers
   Five tiers, one rate. The page argues that the deposit is not a fee, so the
   rate gets the loudest treatment on the page and the deposit figures are
   deliberately quieter than a normal pricing table would make them.
   ========================================================================== */

/* The rate, stated once under the hero. It is the only number a visitor has
   to carry into the table below, so it is set at display scale and given the
   accent -- the one colour this site spends on signal rather than decoration. */
.pass-rate {
  margin-top: clamp(28px, 3.4vw, 46px);
  padding-top: clamp(20px, 2.4vw, 30px);
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px clamp(18px, 2.4vw, 34px);
}
.pass-rate__figure {
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: 10px;
}
.pass-rate__value {
  font-size: var(--fs-h2);
  font-weight: 800;
  letter-spacing: var(--track-heading);
  line-height: 1;
  color: var(--accent);
  font-variant-numeric: proportional-nums;
}
.pass-rate__label {
  font-size: var(--fs-lead);
  color: var(--ink-2);
}
.pass-rate__note {
  margin: 0;
  max-width: var(--measure);
  font-size: var(--fs-sm);
  color: var(--ink-3);
}

/* How it works */
.pass-steps {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(20px, 2.4vw, 34px);
  margin-top: clamp(30px, 3.6vw, 54px);
}
.pass-step { padding-top: 18px; border-top: 1px solid var(--line-2); }
.pass-step__num {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--track-mono);
  color: var(--accent);
}
.pass-step__title {
  margin: 12px 0 8px;
  font-size: var(--fs-h4);
  font-weight: 700;
  letter-spacing: var(--track-heading);
  color: var(--ink);
}
.pass-step__text { margin: 0; font-size: var(--fs-sm); line-height: var(--lh-body); color: var(--ink-3); }

/* Included in every tier */
.pass-incl {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  margin-top: clamp(30px, 3.6vw, 54px);
  background: var(--line);
  border: 1px solid var(--line);
}
.pass-incl__item { padding: clamp(22px, 2.4vw, 32px); background: var(--bg); }
.pass-incl__num {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--track-mono);
  color: var(--ink-4);
}
.pass-incl__title {
  margin: 12px 0 8px;
  font-size: var(--fs-h4);
  font-weight: 700;
  letter-spacing: var(--track-heading);
  color: var(--ink);
}
.pass-incl__text { margin: 0; font-size: var(--fs-sm); line-height: var(--lh-body); color: var(--ink-3); }

/* The tier table.
   Five columns only above 1200px: below that a fifth column drops each card
   under 210px, at which point the feature lines wrap to three rows each and
   the ladder stops being readable as a ladder. */
.pass-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: clamp(14px, 1.4vw, 20px);
  margin-top: clamp(30px, 3.6vw, 54px);
  align-items: stretch;
}
.pass-card {
  display: flex;
  flex-direction: column;
  padding: clamp(20px, 1.9vw, 28px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background-image: var(--panel-fill);
  position: relative;
  overflow: hidden;
  transition: border-color var(--dur) var(--ease);
}
.pass-card::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--panel-glow);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
  pointer-events: none;
}
.pass-card:hover { border-color: var(--line-2); }
.pass-card:hover::before { opacity: 1; }
.pass-card > * { position: relative; }

.pass-card__head { padding-bottom: 16px; border-bottom: 1px solid var(--line); }
.pass-card__name {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--accent);
}
.pass-card__price { margin: 12px 0 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; }
.pass-card__amount {
  font-size: clamp(1.35rem, 1.7vw, 1.6rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--ink);
  font-variant-numeric: proportional-nums;
}
.pass-card__period { font-size: var(--fs-xs); color: var(--ink-4); }
/* The deposit caveat rides with the figure, never in a footnote. A number
   that comes back and a number that does not are different things, and the
   page cannot afford the reader learning that two sections later. */
.pass-card__note { margin: 10px 0 0; font-size: var(--fs-xs); line-height: 1.45; color: var(--ink-3); }
.pass-card__note-key { color: var(--ink-2); font-weight: 600; }

.pass-card__specs { margin: 16px 0 0; display: flex; flex-direction: column; gap: 8px; }
.pass-card__spec { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.pass-card__spec dt { font-size: var(--fs-xs); color: var(--ink-4); }
.pass-card__spec dd { margin: 0; font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }

.pass-card__key {
  margin: 18px 0 10px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--track-mono);
  color: var(--ink-4);
}
.pass-card__list { gap: 7px; font-size: var(--fs-xs); }
/* Pushes the buttons to a common baseline across cards of unequal height, so
   the row of calls to action reads as one row. */
.pass-card__actions { margin-top: auto; padding-top: 20px; display: flex; flex-direction: column; gap: 8px; }
.pass-card__actions .btn { width: 100%; justify-content: center; }

/* Deposit and invite code: one claim, its conditions beside it. */
.pass-note {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: clamp(24px, 3vw, 56px);
  align-items: start;
}
.pass-note__body > .h2 { margin: 10px 0 14px; }
.pass-note__body > .lead { margin: 0; max-width: var(--measure); }
.pass-note__rules {
  gap: 10px;
  padding: clamp(22px, 2.4vw, 30px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background-image: var(--panel-fill);
  font-size: var(--fs-sm);
}

@media (max-width: 1200px) {
  .pass-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .pass-steps, .pass-incl { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* Header breathing room, needed because of the Pass link and therefore
     living with it. The bar collapses to the burger only below 1024px, so
     between 1025 and 1200 it has to carry six links, the logo, the language
     switcher and the contact button on one row. Six overflowed .header__inner
     by 19px at 1090px; five did not. Trimming the link padding buys back 36px
     across the row, which clears it without hiding the nav on the laptop
     widths where people actually browse. */
  .nav { gap: 2px; }
  .nav__link { padding-left: 9px; padding-right: 9px; }
}
@media (max-width: 900px) {
  .pass-note { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 760px) {
  .pass-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  .pass-grid, .pass-steps, .pass-incl { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   Partners
   The same marquee the hero ticker runs on -- same @keyframes, same edge
   mask -- carrying cards instead of words. Reusing the keyframes is not
   only less CSS: two bands moving at visibly different rhythms on one page
   reads as two unrelated widgets, and this one is deliberately slower and
   calmer than the ticker above it.
   ========================================================================== */

.partners__viewport {
  overflow: hidden;
  position: relative;
  margin-top: clamp(30px, 3.6vw, 54px);
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
.partners__track {
  display: flex;
  width: max-content;
  animation: marquee 52s linear infinite;
}
/* Pausing on hover is not decoration: the cards are links, and a target that
   keeps moving under the cursor cannot be clicked. */
.partners__viewport:hover .partners__track,
.partners__viewport:focus-within .partners__track { animation-play-state: paused; }
.partners__group { display: flex; flex: none; }

.partner {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  min-width: clamp(180px, 17vw, 232px);
  height: clamp(88px, 8.4vw, 108px);
  margin-right: clamp(10px, 1.1vw, 16px);
  padding: 0 clamp(18px, 2vw, 28px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background-image: var(--panel-fill);
  font-size: clamp(0.95rem, 1.1vw, 1.08rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  /* Held one ink step back, lifting to full on hover. The site spends
     contrast on its own claims; other people's brands sit quieter. */
  color: var(--ink-3);
  white-space: nowrap;
  text-align: center;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.partner:hover,
.partner:focus-visible { color: var(--ink); border-color: var(--line-2); }
/* Logos are capped by height first: they arrive at wildly different aspect
   ratios, and a width cap alone lets a wide wordmark tower over a square one.
   Height first makes them read as one row of equals. */
.partner img {
  width: auto;
  max-width: 76%;
  max-height: 52%;
  object-fit: contain;
  /* A step back from full strength, brightening on hover -- the same move the
     text cards make. Deliberately not grayscale(): these are other people's
     brand colours, and desaturating them turns half the row to mud. */
  opacity: 0.82;
  transition: opacity var(--dur) var(--ease);
}
.partner:hover img,
.partner:focus-visible img { opacity: 1; }

/* --------------------------------------------------------------------------
   Partner card: name over vertical tag
   The first pass put a bare word in a large empty card, which read as a gap
   rather than a brand. A name with the vertical under it is an object with
   hierarchy, and it carries the one fact a visitor actually wants: what this
   programme is for.
   -------------------------------------------------------------------------- */

.partner { flex-direction: column; gap: 7px; }
.partner__name {
  font-size: clamp(0.95rem, 1.1vw, 1.06rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
}
.partner__tag {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--ink-4);
  transition: color var(--dur) var(--ease);
}
.partner:hover .partner__tag,
.partner:focus-visible .partner__tag { color: var(--accent); }

/* --------------------------------------------------------------------------
   Verticals
   Six directions, one block each. The band above carries the partner names;
   this carries what the traffic actually is, so neither repeats the other.
   -------------------------------------------------------------------------- */

.verticals {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  margin-top: clamp(30px, 3.6vw, 54px);
  background: var(--line);
  border: 1px solid var(--line);
}
.vertical {
  display: flex;
  flex-direction: column;
  padding: clamp(24px, 2.6vw, 36px);
  background: var(--bg);
  transition: background-color var(--dur) var(--ease);
}
.vertical:hover { background: var(--surface-1); }
.vertical__num {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--track-mono);
  color: var(--accent);
}
.vertical__title {
  margin: 13px 0 6px;
  font-size: var(--fs-h4);
  font-weight: 700;
  letter-spacing: var(--track-heading);
  color: var(--ink);
}
.vertical__kicker {
  margin: 0 0 12px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--ink-4);
}
.vertical__text {
  margin: 0;
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
  color: var(--ink-3);
}
/* Pinned to the bottom so the counts line up across cards of unequal text. */
.vertical__count {
  margin-top: auto;
  padding-top: 20px;
  font-size: var(--fs-xs);
  color: var(--ink-4);
}
.vertical__count b {
  font-size: 1.35rem;
  font-weight: 800;
  letter-spacing: -0.03em;
  color: var(--ink);
  margin-right: 7px;
  font-variant-numeric: proportional-nums;
}

@media (max-width: 1024px) { .verticals { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px)  { .verticals { grid-template-columns: minmax(0, 1fr); } }

/* --------------------------------------------------------------------------
   Partner programme cards, on the vertical pages
   -------------------------------------------------------------------------- */

.progs {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  margin-top: clamp(30px, 3.6vw, 54px);
  background: var(--line);
  border: 1px solid var(--line);
}
.prog {
  display: flex;
  flex-direction: column;
  padding: clamp(22px, 2.4vw, 32px);
  background: var(--bg);
  transition: background-color var(--dur) var(--ease);
}
a.prog:hover { background: var(--surface-1); }
.prog__name {
  margin: 0;
  font-size: var(--fs-h4);
  font-weight: 700;
  letter-spacing: var(--track-heading);
  color: var(--ink);
}
.prog__text {
  margin: 9px 0 0;
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
  color: var(--ink-3);
}
/* The domain, pinned to the bottom so it lines up across cards whose
   descriptions differ in length -- and absent entirely where we could not
   verify a site, which the muted variant states rather than hides. */
.prog__link {
  margin-top: auto;
  padding-top: 18px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.08em;
  color: var(--accent);
  word-break: break-all;
}
.prog__link--none { color: var(--ink-4); font-style: normal; }

/* The vertical card is a link on the hub and on the home page, a plain block
   nowhere. Anchors inherit the site's link reset, so the colour has to be
   restored here or the titles come out accent-blue. */
a.vertical { color: inherit; text-decoration: none; }
a.vertical .vertical__title { transition: color var(--dur) var(--ease); }
a.vertical:hover .vertical__title { color: var(--accent-hi); }
.vertical__more {
  margin-top: 14px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--ink-4);
  transition: color var(--dur) var(--ease);
}
a.vertical:hover .vertical__more { color: var(--accent); }

@media (max-width: 1024px) { .progs { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px)  { .progs { grid-template-columns: minmax(0, 1fr); } }

/* --------------------------------------------------------------------------
   Vertical page: hero, metrics, programme cards
   Three fixes to one root cause -- grids drawn as a table (gap:1px over a
   background) show every unfilled cell as an empty framed box. Nine cards
   divide into three columns; four do not. So these grids stop being tables:
   the cards carry their own borders, and a short last row is simply short.
   -------------------------------------------------------------------------- */

.vhero {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: clamp(28px, 4vw, 72px);
  align-items: center;
}
.vhero__aside {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: clamp(18px, 2.2vw, 28px);
  padding-left: clamp(20px, 3vw, 46px);
  border-left: 1px solid var(--line);
}
.vhero__mark { width: clamp(84px, 10vw, 132px); height: auto; flex: none; }
.vhero__figure { margin: 0; display: flex; flex-direction: column; gap: 4px; }
.vhero__figure b {
  font-size: clamp(2.4rem, 4.6vw, 3.6rem);
  font-weight: 800;
  letter-spacing: var(--track-display);
  line-height: 1;
  color: var(--ink);
  font-variant-numeric: proportional-nums;
}
.vhero__figure span {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--ink-4);
}

/* Metrics: open hairlines, the same idiom as .pass-step, so three items in a
   three-column grid never draw a fourth empty frame.

   NAME COLLISION, and the reason every rule here is scoped. `.metrics` /
   `.metric` were already taken by the case-study readout tile in section 15,
   a completely different component that lives on 45 pages. Written unscoped
   these rules came later and quietly restyled that tile, while its rules leaked
   back here. The two are told apart structurally: on a vertical page the block
   is a direct child of .container, and in a case tile it never is (it sits
   inside a.card.case or .case-hero__facts). That needs no markup change, which
   a rename would -- if the markup is ever revised, .v-metrics / .v-metric on
   the 30 vertical pages is the cleaner end state and these scopes go away.

   The item also has to undo the tile's box (background, ring, padding, flex),
   the same way .progs and .verticals below undo their table-style ancestors. */
.container > .metrics {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(20px, 2.4vw, 34px);
  margin-top: clamp(30px, 3.6vw, 54px);
  border-radius: 0;
  overflow: visible;
}
.metric__num {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--track-mono);
  color: var(--accent);
}
.metric__title {
  margin: 12px 0 8px;
  font-size: var(--fs-h4);
  font-weight: 700;
  letter-spacing: var(--track-heading);
  color: var(--ink);
}
.metric__text { margin: 0; font-size: var(--fs-sm); line-height: var(--lh-body); color: var(--ink-3); }

/* Programme cards own their borders, so an incomplete last row leaves nothing
   behind. Overrides the earlier table-style rules. */
.progs {
  gap: clamp(12px, 1.3vw, 18px);
  background: none;
  border: 0;
}
.prog {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background-image: var(--panel-fill);
  transition: border-color var(--dur) var(--ease), background-color var(--dur) var(--ease);
}
a.prog:hover { border-color: var(--line-2); background-color: var(--surface-1); }

/* The mobile aside and mark are defined by the second-pass block further down;
   the declarations that used to sit here were all overridden by it and by the
   unconditional rules it added, so they only looked like the mobile design. */
@media (max-width: 900px) {
  .vhero { grid-template-columns: minmax(0, 1fr); }
  .container > .metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 620px) { .container > .metrics { grid-template-columns: minmax(0, 1fr); } }

/* ==========================================================================
   Vertical pages, second pass
   The first version was inert next to the rest of the site: no accent on
   hover, no lift, no stagger, and a hero whose right column held a mark and
   a number against a lot of black. The site already has a language for all
   of this -- .card carries an accent tint, a specular hairline and a blue
   border on hover -- and these blocks now speak it.
   ========================================================================== */

/* The aside stops being a caption beside empty space and becomes a panel with
   something in it: the count, and the programmes themselves. */
.vhero__aside {
  padding: clamp(22px, 2.4vw, 32px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background:
    radial-gradient(120% 80% at 100% 0%, rgba(123, 140, 255, 0.07), rgba(123, 140, 255, 0) 58%),
    var(--panel-fill);
  gap: clamp(16px, 1.8vw, 22px);
  position: relative;
  overflow: hidden;
}
.vhero__aside::before {
  content: "";
  position: absolute;
  top: 0; left: 8%; right: 8%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent-hi), transparent);
  opacity: 0.5;
}
.vhero__top { display: flex; align-items: center; gap: clamp(16px, 2vw, 26px); }
.vhero__mark { width: clamp(64px, 7vw, 92px); }
.vhero__list {
  margin: 0;
  padding: 18px 0 0;
  list-style: none;
  border-top: 1px solid var(--line);
  display: grid;
  gap: 9px;
  width: 100%;
}
.vhero__list li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
}
/* The same rotated accent pip the hero ticker uses for its separators. */
.vhero__list li::before {
  content: "";
  width: 4px; height: 4px;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent-glow);
  transform: rotate(45deg);
  flex: none;
}

/* Programme cards adopt the .card treatment wholesale: accent tint in the
   ground, specular hairline lit on hover, blue border and a lift. */
.prog {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  background:
    radial-gradient(120% 80% at 0% 0%, rgba(123, 140, 255, 0.055), rgba(123, 140, 255, 0) 58%),
    var(--panel-fill);
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}
.prog::before {
  content: "";
  position: absolute;
  top: 0; left: 8%; right: 8%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent-hi), transparent);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
a.prog:hover {
  border-color: var(--accent-line);
  transform: translateY(-3px);
  box-shadow: 0 20px 50px -28px rgba(0, 0, 0, 0.9), 0 0 0 1px var(--accent-dim);
  background-color: transparent;
}
a.prog:hover::before { opacity: 1; }
a.prog:hover .prog__name { color: var(--accent-hi); }
.prog__name { transition: color var(--dur) var(--ease); }

/* Metrics are not interactive, so they get presence rather than reaction:
   the rule above each one carries the accent at its left and fades out. */
.container > .metrics > .metric {
  display: block;
  border-top: 0;
  position: relative;
  padding: 19px 0 0;
  background: none;
  box-shadow: none;
}
.container > .metrics > .metric::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  background: linear-gradient(90deg, var(--accent-line), var(--line) 42%, var(--line));
}

/* Vertical cards: accent bloom and the left bar the .tile component uses, so
   a clickable card announces itself the way clickable things do here. */
.vertical { position: relative; overflow: hidden; isolation: isolate; }
.vertical::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(90% 70% at 0% 0%, var(--accent-dim), transparent 60%);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
  pointer-events: none;
}
.vertical::after {
  content: "";
  position: absolute;
  top: 0; left: 0; bottom: 0;
  width: 2px;
  background: var(--accent);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 0.5s var(--ease);
}
a.vertical:hover::before { opacity: 1; }
a.vertical:hover::after { transform: scaleY(1); }
.vertical > * { position: relative; }

/* Partner band cards pick up the same blue edge on hover. */
.partner { transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease); }
a.partner:hover { border-color: var(--accent-line); transform: translateY(-2px); }

@media (max-width: 900px) {
  .vhero__aside { flex-direction: column; align-items: stretch; border-top: 1px solid var(--line); }
  .vhero__top { align-items: center; }
}

/* Tier cards join the same hover language: the glow alone read as a lighting
   change, not as "this is clickable". */
.pass-card {
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}
.pass-card:hover {
  border-color: var(--accent-line);
  transform: translateY(-3px);
  box-shadow: 0 20px 50px -28px rgba(0, 0, 0, 0.9), 0 0 0 1px var(--accent-dim);
}
.pass-card:hover .pass-card__name { color: var(--accent-hi); }
.pass-card__name { transition: color var(--dur) var(--ease); }

/* --------------------------------------------------------------------------
   Vertical cards become cards
   They were drawn as a table -- one hard-edged rectangle with 1px gutters --
   while everything else clickable on this site is a rounded panel. Rounding
   the outer box would have kept the table; these become individual cards
   instead, which also means an incomplete row can never leave a framed hole.
   -------------------------------------------------------------------------- */

.verticals {
  gap: clamp(12px, 1.3vw, 18px);
  background: none;
  border: 0;
}
.vertical {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background-image: var(--panel-fill);
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}
a.vertical:hover {
  background-color: transparent;
  border-color: var(--accent-line);
  transform: translateY(-3px);
  box-shadow: 0 20px 50px -28px rgba(0, 0, 0, 0.9), 0 0 0 1px var(--accent-dim);
}
/* The accent bar rides the rounded edge, so it needs the same radius on the
   side it sits against or it pokes out of the corner. */
.vertical::after { border-radius: var(--radius) 0 0 var(--radius); }

/* --------------------------------------------------------------------------
   "What this traffic is": two columns, because there are two paragraphs
   A single measure-wide column left the right half of the section empty. The
   copy already comes in two parts -- what the vertical is, and what that
   costs you -- so each takes a column and the row fills itself. No invented
   pull-quote, no filler graphic.
   -------------------------------------------------------------------------- */

.vwhat {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(28px, 4vw, 72px);
  margin-top: clamp(22px, 2.6vw, 34px);
}
.vwhat p {
  margin: 0;
  max-width: var(--measure-prose);
  font-size: var(--fs-lead);
  line-height: var(--lh-body);
  color: var(--ink-2);
}

@media (max-width: 900px) { .vwhat { grid-template-columns: minmax(0, 1fr); gap: 20px; } }

/* --------------------------------------------------------------------------
   Enquiry form: who is asking
   The form only ever fitted a company -- an individual had nothing to put in
   "Компания" and no topic that described them. One form with two modes, not
   two forms: two forms drift apart at the first edit.
   -------------------------------------------------------------------------- */

.form__mode {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  margin-bottom: clamp(20px, 2.2vw, 28px);
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-1);
}
.mode {
  appearance: none;
  border: 0;
  cursor: pointer;
  padding: 9px 18px;
  border-radius: 999px;
  background: transparent;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--ink-4);
  transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}
.mode:hover { color: var(--ink-2); }
.mode.is-active {
  color: var(--bg);
  background: var(--ink);
}
.field[hidden] { display: none; }

/* --------------------------------------------------------------------------
   Sent
   A line of status text under the form read as "nothing happened". This is
   the moment the visitor most wants to be told they were heard.
   -------------------------------------------------------------------------- */

.sent {
  position: fixed;
  inset: 0;
  /* Above the menu layer: the two used to collide when the dialog borrowed
     the menu's body class, and stacking them apart makes that class of bug
     impossible rather than merely fixed. */
  z-index: calc(var(--z-menu) + 10);
  display: grid;
  place-items: center;
  padding: clamp(16px, 4vw, 40px);
  background: rgba(3, 3, 4, 0.72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.32s var(--ease), visibility 0s linear 0.32s;
}
.sent.is-open { opacity: 1; visibility: visible; transition-delay: 0s; }

.sent__panel {
  position: relative;
  width: min(520px, 100%);
  padding: clamp(30px, 4vw, 48px);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-lg);
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(123, 140, 255, 0.10), rgba(123, 140, 255, 0) 60%),
    var(--bg-raised);
  box-shadow: 0 40px 90px -40px rgba(0, 0, 0, 0.95);
  text-align: center;
  transform: translateY(14px) scale(0.98);
  transition: transform 0.42s var(--ease);
}
.sent.is-open .sent__panel { transform: none; }
.sent__panel::before {
  content: "";
  position: absolute;
  top: 0; left: 12%; right: 12%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent-hi), transparent);
}

.sent__mark {
  width: 62px; height: 62px;
  margin: 0 auto clamp(18px, 2.2vw, 26px);
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: var(--live);
  background: var(--live-dim);
  box-shadow: 0 0 0 1px rgba(95, 227, 161, 0.28);
}
.sent__mark path {
  stroke-dasharray: 26;
  stroke-dashoffset: 26;
}
.sent.is-open .sent__mark path { animation: sent-tick 0.5s var(--ease) 0.16s forwards; }
@keyframes sent-tick { to { stroke-dashoffset: 0; } }

.sent__title {
  margin: 0 0 12px;
  font-size: var(--fs-h3);
  font-weight: 800;
  letter-spacing: var(--track-heading);
  color: var(--ink);
}
.sent__text { margin: 0 auto; max-width: 40ch; color: var(--ink-3); line-height: var(--lh-body); }
.sent__actions { margin-top: clamp(22px, 2.6vw, 30px); display: flex; justify-content: center; gap: 10px; }

@media (prefers-reduced-motion: reduce) {
  html:not(.force-motion) .sent,
  html:not(.force-motion) .sent__panel { transition: none !important; }
  html:not(.force-motion) .sent__panel { transform: none !important; }
  /* The tick is the confirmation itself, so it is drawn, not animated. */
  html:not(.force-motion) .sent__mark path { animation: none !important; stroke-dashoffset: 0 !important; }
}

/* ==========================================================================
   28. Colour that carries meaning
   Revertible on its own: this block and nothing else is what `git revert` of
   the commit that added it removes.

   The palette has always declared four colours; three of them were nearly
   unused. --warn appeared zero times and --cut once, because the site had no
   place that said "this went down".

   The data-tone attribute already existed on 645 metric tiles and drove the
   colour of one small arrow. That is the whole reason a page full of measured
   results reads as monochrome.

   What this does NOT do: colour the figures themselves. 580 of the 645 tiles
   are marked "pos", so tinting the numbers would turn almost every result on
   the site green -- at which point green stops meaning anything, and a site
   whose argument is that it does not dress up its numbers would be dressing
   up its numbers. The tone gets a hairline instead: present at a glance,
   quiet up close, and it scales to 580 instances without shouting.

   --cut and --warn are wired here rather than used. The day a case study
   reports a decline, the tile turns without another line of CSS.
   ========================================================================== */

/* Only a tile that declares a tone gets one. The vertical pages reuse .metric
   for explanatory figures that are neither up nor down, and a default green
   there would be colour without meaning -- the exact thing this block exists
   to avoid. */
.metric[data-tone="pos"]     { --tone: var(--live); }
.metric[data-tone="neutral"] { --tone: var(--accent-hi); }
.metric[data-tone="neg"]     { --tone: var(--cut); }
.metric[data-tone="warn"]    { --tone: var(--warn); }

/* A cap on the top edge of the readout. Inset from both sides so it reads as
   part of the cell rather than as a border, and drawn as a gradient so it
   fades rather than stopping dead against the hairline ring. */
.metric[data-tone]::after {
  content: "";
  position: absolute;
  top: 0;
  left: 14px;
  right: 14px;
  height: 2px;
  /* Plain first: a browser without color-mix drops that declaration entirely,
     and without a fallback the cap would simply not be drawn. */
  background: var(--tone);
  background: linear-gradient(90deg, var(--tone), color-mix(in srgb, var(--tone) 25%, transparent));
  opacity: 0.55;
  transition: opacity var(--dur) var(--ease);
  pointer-events: none;
}
.card:hover .metric[data-tone]::after { opacity: 1; }

/* The arrow already used the tone; it now reads from the same variable, so
   there is one place to change and no way for the two to disagree. */
.metric__dir { color: var(--tone, var(--live)); }

/* The unit takes the tone at low strength -- enough that a percent sign or a
   "k" belongs to its figure, not enough to compete with it. */
.metric[data-tone] .metric__unit { color: var(--ink-3); }
.metric[data-tone] .metric__unit { color: color-mix(in srgb, var(--tone) 55%, var(--ink-3)); }

/* ==========================================================================
   29. A colour per vertical
   Revertible on its own.

   Six directions that a visitor moves between, all previously drawn in the
   same accent. The colour is a chapter marker: it tells you which vertical
   you are in without a word, and it gives the six-card grid on the home page
   six identities instead of one repeated six times.

   Contrast on --bg was measured for each, lowest 6.79:1 and highest 10.45:1,
   against the 4.5:1 the site holds itself to -- so these are safe on text,
   not only on rules and marks.

   What --v does NOT touch: buttons, links, focus rings, form states. Those
   stay --accent everywhere. One colour means "you can act on this" across the
   whole site; a second meaning for the same signal would make both weaker.
   ========================================================================== */

[data-vertical="igaming"]     { --v: #7b8cff; }  /* periwinkle -- the brand accent, and iGaming is the main line */
[data-vertical="nutra"]       { --v: #55cfa2; }  /* jade */
[data-vertical="ecommerce"]   { --v: #57b4ea; }  /* sky */
[data-vertical="sweepstakes"] { --v: #d4ab5c; }  /* gold */
[data-vertical="dating"]      { --v: #dd7fae; }  /* rose */
[data-vertical="crypto"]      { --v: #a583f2; }  /* violet */

/* The card in the six-up grid, on the home page and the hub. */
.vertical__num { color: var(--v, var(--accent)); }
.vertical::after { background: var(--v, var(--accent)); }
.vertical::before {
  background: radial-gradient(90% 70% at 0% 0%,
    color-mix(in srgb, var(--v, var(--accent)) 18%, transparent), transparent 60%);
}
a.vertical:hover {
  border-color: color-mix(in srgb, var(--v, var(--accent)) 45%, transparent);
  box-shadow: 0 20px 50px -28px rgba(0, 0, 0, 0.9),
              0 0 0 1px color-mix(in srgb, var(--v, var(--accent)) 18%, transparent);
}
a.vertical:hover .vertical__title { color: var(--v, var(--accent-hi)); }
a.vertical:hover .vertical__more { color: var(--v, var(--accent)); }

/* The vertical's own page. data-vertical sits on <main>, so the hero, the
   metrics and the programme cards all inherit it without repeating it. */
[data-vertical] .page-hero .eyebrow { color: var(--v); }
[data-vertical] .vhero__aside::before {
  background: linear-gradient(90deg, transparent, var(--v), transparent);
}
[data-vertical] .vhero__list li::before {
  background: var(--v);
  box-shadow: 0 0 8px color-mix(in srgb, var(--v) 40%, transparent);
}
[data-vertical] .vhero__figure b { color: var(--v); }
[data-vertical] .metric__num { color: var(--v); }
[data-vertical] .metric::before {
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--v) 55%, transparent), var(--line) 42%, var(--line));
}
[data-vertical] .pass-step__num { color: var(--v); }
[data-vertical] a.prog:hover {
  border-color: color-mix(in srgb, var(--v) 45%, transparent);
  box-shadow: 0 20px 50px -28px rgba(0, 0, 0, 0.9),
              0 0 0 1px color-mix(in srgb, var(--v) 18%, transparent);
}
[data-vertical] a.prog:hover .prog__name { color: var(--v); }
[data-vertical] .prog__link { color: var(--v); }
[data-vertical] .prog::before {
  background: linear-gradient(90deg, transparent, var(--v), transparent);
}
[data-vertical] .vhero__aside {
  background:
    radial-gradient(120% 80% at 100% 0%,
      color-mix(in srgb, var(--v) 12%, transparent), transparent 58%),
    var(--panel-fill);
}

/* ==========================================================================
   30. More light
   Revertible on its own. Nothing here introduces a colour; it raises the
   strength of light that was already in the design and gives the inner pages
   the ambient wash only the home page had.

   Measured rather than nudged: the panel bloom was 0.10 alpha, the card tint
   0.055, the hero spotlight 0.13. Each is raised by roughly half again --
   enough to be seen on a normal screen at normal brightness, short of the
   point where a dark page starts to look like a lit one.
   ========================================================================== */

:root {
  --panel-glow: radial-gradient(90% 70% at 100% 0%, rgba(123, 140, 255, 0.17), transparent 62%);
  --accent-dim: rgba(123, 140, 255, 0.22);
  --accent-glow: rgba(123, 140, 255, 0.42);
}

/* The card's own tint, restated because it is baked into a background
   shorthand rather than read from a token. */
.card {
  background:
    radial-gradient(120% 80% at 0% 0%, rgba(123, 140, 255, 0.09), rgba(123, 140, 255, 0) 58%),
    var(--panel-fill);
}

/* The hero spotlight follows the pointer already; it was just too faint to
   notice on anything but an OLED in a dark room. It is ::before, not ::after --
   an ::after rule here would have declared no content and painted nothing,
   which is a change that looks applied and does nothing. Only the paint is
   raised; the placement, z-index and --spot-on opacity stay where they are. */
.hero::before {
  background: radial-gradient(
    520px circle at var(--spot-x) var(--spot-y),
    rgba(123, 140, 255, 0.19),
    rgba(123, 140, 255, 0.07) 42%,
    transparent 70%
  );
}

/* Every page except the home page opened on flat black. This is the single
   biggest reason the inner pages felt more austere than the front one -- not
   the palette, the absence of any light at all. Tinted by the vertical where
   there is one, so a vertical page opens in its own colour. */
.page-hero::before {
  content: "";
  position: absolute;
  inset: calc(var(--header-h) * -1) 0 auto 0;
  height: clamp(320px, 46vw, 620px);
  background: radial-gradient(70% 100% at 22% 0%,
    color-mix(in srgb, var(--v, var(--accent)) 13%, transparent), transparent 68%);
  pointer-events: none;
  z-index: 0;
}
.page-hero > .container { position: relative; z-index: 1; }

/* The closing band already had a bloom at line 3732, deliberately anchored to
   its bottom edge. Only the paint is raised here -- restating the geometry
   would have silently replaced a placement someone chose. Tinted by the
   vertical where there is one. */
.cta-band::before {
  background: radial-gradient(50% 60% at 50% 100%,
    color-mix(in srgb, var(--v, var(--accent)) 24%, transparent), transparent 70%);
}

/* No reduced-motion rule here: line 4109 already hides the spotlight, and a
   second copy would be one more place to forget. The ambient washes stay --
   they do not move. */
