/* ==========================================================================
   Inter — the substitute the design brief names for SF Pro.

   Self-hosted rather than fetched from a CDN so the type is identical on
   every machine and the page has no render-blocking third-party request.
   Apple hardware still gets the real SF Pro via -apple-system, which sits
   ahead of Inter in the stack.
   ========================================================================== */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../../assets/fonts/inter-latin-300-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../../assets/fonts/inter-latin-400-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../../assets/fonts/inter-latin-500-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../../assets/fonts/inter-latin-600-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../../assets/fonts/inter-latin-700-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  src: url('../../assets/fonts/inter-latin-300-italic.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../../assets/fonts/inter-latin-400-italic.woff2') format('woff2');
}

/* ==========================================================================
   NetrAI — Design Tokens (v4: Apple system, light + dark)

   Light: "white room with a single blue switch."
   Dark:  "black room, same switch."

   Hierarchy is built from scale, weight and hairlines — never from
   elevation. There is exactly one chromatic interactive colour, and it has
   exactly one job.

   ── HOW THEMING WORKS ──────────────────────────────────────────────────
   Two layers, and the split is the whole trick:

     1. RAW PALETTE (--color-*). Fixed pigments. Identical in both themes.
        Never reference these from a component.
     2. SEMANTIC TOKENS (--ink, --surface-*, --line, --accent…). These carry
        the theme's meaning and are the ONLY things the dark block overrides.

   Every component in the other 15 stylesheets reads the semantic layer, so
   dark mode is one override block rather than a parallel set of rules.

   ── BLUE DISCIPLINE ────────────────────────────────────────────────────
   The brief's three blues map onto the two themes almost perfectly, because
   they were extracted from a system that already solved this:

     --accent-fill   #0071e3 in BOTH — a filled action button is the same
                     object under either lighting, and white on it clears AA
                     on any background.
     --accent        #0066cc light / #2997ff dark — links and outlined
                     actions. Link Blue is too dark to read on black; Signal
                     Blue is too light to read on Frost. Each theme gets the
                     one that clears AA against its own canvas.
     --accent-soft   decorative strokes only. Never a control, never a word.

   The rule "never mix the three blues in one interactive element" still
   holds — within a theme there are only ever two in play.
   ========================================================================== */

:root {
  /* ---------------------------------------------------------------------
     1. RAW PALETTE — fixed pigments, theme-independent
     --------------------------------------------------------------------- */
  --color-apple-blue:  #0071e3;
  --color-link-blue:   #0066cc;
  --color-signal-blue: #2997ff;
  --color-carbon:      #1d1d1f;
  --color-frost:       #f5f5f7;
  --color-ice:         #f4f8fb;
  --color-smoke:       #333333;
  --color-graphite:    #474747;
  --color-ash:         #707070;
  --color-mist:        #858585;
  --color-onyx:        #000000;
  --color-pebble:      #e2e2e5;
  --color-hairline:    #d2d2d7;

  /* Dark-side pigments. Apple's own dark values, not inversions of the
     light ones — an inverted #f5f5f7 is #0a0a08, which reads brown. */
  --color-ink-dark:      #f5f5f7;  /* primary text on black               */
  --color-mist-dark:     #86868b;  /* secondary text on black — 6.0:1     */
  --color-hairline-dark: #48484a;  /* Apple's dark separator, a shade up  */
  --color-elevated:      #1d1d1f;  /* card / raised plane on black        */
  --color-elevated-2:    #2c2c2e;  /* filled control, disabled surface    */
  --color-wash-dark:     #0e1116;  /* the barely-blue lift, dark side     */

  /* ---------------------------------------------------------------------
     2. SEMANTIC TOKENS — light theme
     --------------------------------------------------------------------- */

  /* Surfaces — three levels, no shadows. Depth is the step between them,
     which is why each step is deliberately tiny. */
  --surface-canvas:        #f5f5f7;  /* level 0 — page, default section     */
  --surface-white:         #ffffff;  /* level 1 — cards, alternating bands  */
  --surface-elevated-wash: #f4f8fb;  /* level 1b — featured section wash    */
  --surface-pebble:        #e2e2e5;  /* level 2 — filled controls, disabled */

  /* Translucent chrome — sticky nav, category bars, sheets. Sits over
     scrolling content, so it must be the canvas colour at high alpha rather
     than a flat fill. */
  --chrome-bg:        rgba(255, 255, 255, 0.82);
  --chrome-bg-solid:  rgba(255, 255, 255, 0.94);
  --chrome-blur:      saturate(180%) blur(20px);

  /* A whisper of surface separation — the low-alpha fill that used to be
     white-on-dark and is black-on-light here. One token so it can flip. */
  --fill-subtle: rgba(0, 0, 0, 0.04);
  --fill-hover:  rgba(0, 0, 0, 0.08);

  /* Modal backdrop. Dark in both themes — it dims what is behind it — but
     black-on-black needs more of it to separate the sheet from the page. */
  --scrim: rgba(0, 0, 0, 0.55);

  /* Accent-tinted hover/selected fill. A 6% blue over Frost is a whisper; the
     same 6% over black is nothing at all, so dark carries more of it. */
  --accent-tint:        rgba(0, 102, 204, 0.07);
  --accent-tint-strong: rgba(0, 102, 204, 0.13);

  /* Text */
  --ink:      #1d1d1f;   /* Carbon — primary                                */
  /* Apple's own secondary ink. The brief's Ash (#707070) and Mist (#858585)
     are listed as border and caption greys; at 11–14px on the canvas Mist
     lands at 3.4:1, so muted TEXT uses one value that clears AA and lets
     hierarchy come from size and weight instead of from a third grey. Ash
     and Mist stay in the system as rules and hairlines. */
  --mist:     #6e6e73;   /* muted body — 5.4:1 on canvas                    */
  --mist-dim: #6e6e73;   /* fine print — same ink, smaller                  */

  --line:        #d2d2d7;
  --line-strong: #858585;

  /* Interactive colour */
  --accent-fill: #0071e3;   /* filled pill background — both themes         */
  --accent:      #0066cc;   /* link text, outlined action border            */
  /* Filled-pill hover goes DARKER, in both themes. White on #0071e3 is
     4.68:1 and only just clears AA, so any lighter hover fill drops the
     button's own label below the threshold — the "brighter on hover"
     instinct is what breaks it (#0077ed is 4.32:1, #47a6ff is 2.6:1).
     Darker reads as a press on every platform anyway. */
  --accent-dim:  #0062c4;   /* white label = 5.9:1                          */
  --accent-soft: #2997ff;   /* decorative only                              */
  --accent-glow: transparent;
  --on-accent:   #ffffff;   /* ink printed on a filled pill — 4.68:1        */

  /* The logo ships as a Carbon silhouette. In dark it is inverted rather
     than swapped for a second file: one asset, no second request, no
     flash while the other loads. */
  --logo-filter: none;

  /* ---------------------------------------------------------------------
     3. LEGACY ALIASES

     --void carried two jobs in the dark "Iris" system: the page floor, and
     the ink printed on a saturated accent. Those separated when the site
     went light — every `color: var(--void)` is now an explicit --on-accent
     — so --void is purely the canvas and flips cleanly.
     --------------------------------------------------------------------- */
  --void:          var(--surface-canvas);
  --void-2:        var(--surface-white);
  --surface:       var(--surface-white);
  --surface-2:     var(--surface-elevated-wash);
  --surface-hover: var(--surface-pebble);

  /* Iris aliases collapse onto the blue family. Nothing chromatic survives
     outside it — that is the whole point of the system. */
  --iris-violet: var(--accent);
  --iris-indigo: var(--accent-fill);
  --iris-blue:   var(--accent-fill);
  --iris-cyan:   var(--accent-soft);

  /* The warm half of the old palette existed only to light glows that this
     system does not have. Neutralised rather than deleted so any stray
     reference resolves to nothing instead of to a colour cast. */
  --ember:      transparent;
  --ember-deep: transparent;
  --ember-glow: transparent;

  /* Gradients degrade to flat colour. Apple's rhythm comes from surface
     changes and scale, never from a ramp. */
  --gradient-iris:      linear-gradient(120deg, var(--accent-fill) 0%, var(--accent-fill) 100%);
  --gradient-cosmic:    linear-gradient(120deg, var(--accent-fill) 0%, var(--accent-fill) 100%);
  --gradient-iris-soft: linear-gradient(120deg, var(--surface-elevated-wash) 0%, var(--surface-elevated-wash) 100%);
  --gradient-icon:      linear-gradient(135deg, var(--surface-elevated-wash) 0%, var(--surface-elevated-wash) 100%);
  --icon-tile-border:   var(--line);

  /* ---------------------------------------------------------------------
     4. MATERIAL

     There is no glass. Every panel is an opaque surface with a 1px hairline.
     The old glass tokens are kept and flattened so the declarations
     downstream resolve to no-ops instead of needing to be hunted one by one.
     --------------------------------------------------------------------- */
  --glass-bg:                var(--surface-white);
  /* Card hover. The system used to answer a hover with a lift, a border
     change and a pointer-tracked glow all at once; all three are gone (see
     the note on .card:hover below) and this single step replaced them. Light
     mode steps DOWN toward the canvas, dark steps UP away from it — in both
     cases "slightly nearer the page" is the wrong direction and reads as the
     card switching off. */
  --glass-bg-hover:          var(--surface-elevated-wash);
  --glass-bg-strong:         var(--surface-white);
  --glass-border:            var(--line);
  --glass-border-hover:      var(--line-strong);
  --glass-border-top:        var(--line);
  --glass-border-left:       var(--line);
  --glass-border-top-hover:  var(--line-strong);
  --glass-border-left-hover: var(--line-strong);
  --glass-sheen:             none;
  --glass-blur:              0px;
  --glass-saturate:          100%;
  --glass-shadow:            none;
  --glass-shadow-hover:      none;

  /* The single permitted shadow, and only under product imagery — never a
     card, button, panel or nav. */
  --shadow-image: rgba(0, 0, 0, 0.22) 3px 5px 30px 0px;

  /* Film grain has no place on either canvas. */
  --grain: none;

  /* ---------------------------------------------------------------------
     5. TYPE, SPACE, SHAPE, MOTION — theme-independent
     --------------------------------------------------------------------- */
  --font-sf-display: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Inter', ui-sans-serif, system-ui, 'Segoe UI', Roboto, sans-serif;
  --font-sf-text:    -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Inter', ui-sans-serif, system-ui, 'Segoe UI', Roboto, sans-serif;

  --font-display: var(--font-sf-display);
  --font-body:    var(--font-sf-text);
  /* The old system used a mono face for labels and an editorial serif for
     quotes. Apple has neither voice — it changes register with size and
     weight instead, so both aliases resolve into the one family. */
  --font-mono:    var(--font-sf-text);
  --font-serif:   var(--font-sf-display);

  /* Type scale — size / line-height / tracking.
     The tracking is the part that makes this typography read as precise;
     dropping it turns SF Pro into any other grotesk.

     ── THE CURVE RUNS ONE WAY ───────────────────────────────────────────
     Two rules, and both of them are monotonic across the whole scale:
     tracking tightens as type grows, and leading tightens with it. Letters
     read as drifting apart the larger they get, so display sizes need to be
     pulled in; a long line at 17px needs more room between lines than a
     two-word heading at 56px does.

     The previous values ran the other way — most negative at 12px, swinging
     positive by 28px — and `heading-lg` then contradicted its own
     neighbours on BOTH axes at once: tracking jumped back to -0.010em while
     40px and 56px were positive, and leading LOOSENED to 1.18 sitting
     between 1.14 and 1.07. A 44px heading came out visibly tighter and
     airier than the 40px one above it, which is the one seam a reader
     notices without being able to name.

     Caption is the single exception, and it is deliberate: below ~13px the
     counters start to close up, so small text takes slightly POSITIVE
     tracking to stay legible. That is the same curve, not a break in it —
     it is why the curve is drawn from the middle outward. */
  --text-caption:     12px;  --leading-caption:     1.33;  --tracking-caption:      0.004em;
  --text-body-sm:     14px;  --leading-body-sm:     1.29;  --tracking-body-sm:      0.000em;
  --text-body:        17px;  --leading-body:        1.47;  --tracking-body:        -0.005em;
  --text-subheading:  21px;  --leading-subheading:  1.24;  --tracking-subheading:  -0.009em;
  --text-heading-sm:  28px;  --leading-heading-sm:  1.20;  --tracking-heading-sm:  -0.013em;
  --text-heading:     40px;  --leading-heading:     1.14;  --tracking-heading:     -0.017em;
  --text-heading-lg:  44px;  --leading-heading-lg:  1.12;  --tracking-heading-lg:  -0.019em;
  --text-display:     56px;  --leading-display:     1.07;  --tracking-display:     -0.022em;

  --font-weight-light:    300;
  --font-weight-regular:  400;
  --font-weight-semibold: 600;
  --font-weight-bold:     700;

  /* Spacing — 4px base, comfortable density */
  --spacing-unit: 4px;
  --spacing-4: 4px;   --spacing-8: 8px;   --spacing-12: 12px;
  --spacing-16: 16px; --spacing-20: 20px; --spacing-24: 24px;
  --spacing-40: 40px; --spacing-48: 48px; --spacing-56: 56px;

  /* Layout — sections run full bleed; only text columns are constrained. */
  --max-width:     1080px;
  --text-width:    980px;
  --section-gap:   64px;
  --card-padding:  24px;
  --element-gap:   12px;

  /* Radius — the system has exactly two values. 8px for anything with a
     surface, 980px for anything you can press. */
  --radius-sm: 8px;
  --radius:    8px;
  --radius-lg: 8px;
  --radius-pill: 980px;
  --radius-full: 980px;

  /* Motion — Apple's standard curve. Short, precise, no overshoot. */
  --ease-apple: cubic-bezier(0.28, 0.11, 0.32, 1);
  --transition: 300ms cubic-bezier(0.28, 0.11, 0.32, 1);

  /* How long a theme swap takes. Long enough to read as a dimmer rather
     than a light switch, short enough not to be a transition you sit
     through. Applied only to colour, never to layout. */
  --theme-transition: 260ms cubic-bezier(0.28, 0.11, 0.32, 1);

  color-scheme: light;
}

/* ==========================================================================
   DARK THEME

   Overrides the semantic layer only. Note what is NOT here: no type, no
   spacing, no radii, no motion, and no per-component rules. If a component
   needs its own dark rule, that component is reading a raw pigment
   somewhere it should be reading a semantic token — fix it there, not here.

   The canvas is true black rather than a dark grey. It is what makes the
   card plane at #1d1d1f read as a plane at all; on a #121212 canvas the
   1-level step disappears and everything flattens.
   ========================================================================== */
[data-theme="dark"] {
  --surface-canvas:        #000000;
  --surface-white:         var(--color-elevated);      /* #1d1d1f */
  --surface-elevated-wash: var(--color-wash-dark);     /* #0e1116 */
  --surface-pebble:        var(--color-elevated-2);    /* #2c2c2e */

  /* ---------------------------------------------------------------------
     Card surface — deliberately NOT --surface-white.

     The note further up this file explains why the canvas is true black:
     so a #1d1d1f card reads as a raised plane against it. That elevation
     step is real, but at card size it lands as a grey panel rather than as
     depth, which is what it was reported as. Cards drop to just above black
     and are defined by their hairline instead.

     Overridden here rather than on --surface-white on purpose: that token
     also feeds the nav capsule, the search palette, dropdowns and the
     footer, none of which were part of the complaint and all of which lose
     their shape if flattened to the canvas.
     --------------------------------------------------------------------- */
  --glass-bg:              #0a0a0b;
  --glass-bg-hover:        #141416;

  --chrome-bg:       rgba(0, 0, 0, 0.72);
  --chrome-bg-solid: rgba(0, 0, 0, 0.92);

  --fill-subtle: rgba(255, 255, 255, 0.06);
  --fill-hover:  rgba(255, 255, 255, 0.11);

  --scrim: rgba(0, 0, 0, 0.72);

  --accent-tint:        rgba(41, 151, 255, 0.15);
  --accent-tint-strong: rgba(41, 151, 255, 0.24);

  --ink:      var(--color-ink-dark);      /* #f5f5f7 — 19.6:1 on black */
  --mist:     var(--color-mist-dark);     /* #86868b —  6.0:1 on black */
  --mist-dim: var(--color-mist-dark);

  --line:        var(--color-hairline-dark);  /* #48484a */
  --line-strong: #6e6e73;

  /* Link Blue is 2.8:1 on black and unreadable. Signal Blue is 7.0:1 —
     which is exactly the job the brief reserved it for on dark surfaces. */
  --accent:      var(--color-signal-blue);  /* #2997ff — 7.0:1 on black */
  /* --accent-dim is shared: see the note in :root. */
  --accent-soft: var(--color-apple-blue);
  /* --accent-fill and --on-accent deliberately unchanged: a filled action
     button is the same object under either lighting. */

  /* The Carbon logo becomes its own negative. One asset, no second request,
     no flash while a swapped file loads. */
  --logo-filter: invert(1) brightness(1.08);

  --shadow-image: none;

  /* ---------------------------------------------------------------------
     DARK-ONLY: the old "Iris" theme, brought back for the background layer.

     :root neutralises the whole cosmic palette so light mode stays the
     flat Apple system. This block un-neutralises it, dark side only —
     the four accent stops, the warm ember half, and the gradients built
     from them. Nothing that reads as a control changes: --accent-fill,
     --accent and --accent-soft above are untouched, so every button, link
     and focus state is exactly what it was. This only feeds decorative
     consumers — .ambient-bg (css/pages/finale.css, homepage only), gradient
     text, icon-tile washes, and a few hover borders — which is what "the
     background and the theme" scopes down to. The hero is explicitly
     re-guarded below so the headline stays on the plain system. */
  --iris-violet: #8B7CFF;
  --iris-indigo: #6D6BEF;
  --iris-blue:   #5B8DFF;
  --iris-cyan:   #4FD8E8;

  --ember:      #FF8A3D;
  --ember-deep: #C2410C;
  --ember-glow: rgba(255,138,61,0.5);

  --gradient-iris:      linear-gradient(120deg, var(--iris-violet) 0%, var(--iris-blue) 55%, var(--iris-cyan) 100%);
  --gradient-cosmic:    linear-gradient(100deg, var(--ember) 0%, var(--iris-violet) 46%, var(--iris-blue) 100%);
  --gradient-iris-soft: linear-gradient(120deg, rgba(139,124,255,0.28) 0%, rgba(91,141,255,0.28) 55%, rgba(79,216,232,0.28) 100%);
  --gradient-icon:      linear-gradient(135deg, rgba(255,138,61,0.16) 0%, rgba(139,124,255,0.13) 50%, rgba(91,141,255,0.11) 100%);
  --icon-tile-border:   rgba(255,255,255,0.07);

  color-scheme: dark;
}

/* The one consumer of the restored gradient that sits inside the headline
   section — pin it back to the flat system so the hero is pixel-identical
   to before this change, in both themes. */
[data-theme="dark"] .hero .video-play-btn { background: var(--accent-fill); }

/* A theme swap should read as the lights changing, not as the page
   reloading. Colour properties only — transitioning layout would make the
   whole document reflow visibly. Scoped to a class the toggle adds for the
   duration of the swap, so first paint and normal hovers are unaffected. */
.theme-transition,
.theme-transition *,
.theme-transition *::before,
.theme-transition *::after {
  transition: background-color var(--theme-transition),
              border-color var(--theme-transition),
              color var(--theme-transition),
              fill var(--theme-transition),
              stroke var(--theme-transition) !important;
  transition-delay: 0s !important;
}

@media (prefers-reduced-motion: reduce) {
  .theme-transition, .theme-transition * { transition: none !important; }
}

/* ==========================================================================
   Surface material — the replacement for the old glass recipe.
   An opaque plane and a hairline. That is the entire vocabulary.
   ========================================================================== */
.glass,
.glass-strong {
  background: var(--surface-white);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: 1px solid var(--line);
  box-shadow: none;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

body {
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--surface-canvas);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  letter-spacing: var(--tracking-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  position: relative;
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }
a { text-decoration: none; color: inherit; }
ul { list-style: none; }
button { font: inherit; cursor: pointer; border: none; background: none; color: inherit; }
input, select, textarea { font: inherit; }
svg { display: block; }

::selection { background: var(--accent-fill); color: #fff; }

.container {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 32px;
}

/* Text-heavy blocks read at Apple's measure, not the grid's full width. */
.container-text {
  max-width: var(--text-width);
  margin-left: auto;
  margin-right: auto;
}

/* ==========================================================================
   Texture — removed.

   The old system laid film grain over every colour field and a second pass
   over the whole document. On a var(--surface-canvas) canvas grain reads as dirt, not
   finish, so both layers are switched off at the source rather than tuned
   down. The rules stay so the markup that references them is not orphaned.
   ========================================================================== */
.hero-aurora::after,
.page-hero::after,
.finale::after { content: none; }

.noise-overlay,
.blob,
.hero-aurora,
.watermark,
.problem-blob { display: none !important; }

/* .ambient-bg (and its glow-orb/light-bloom/light-streak children) used to
   be killed here with everything else above. It has its own on/off switch
   now — off by default, on for dark theme only — in css/pages/finale.css, right
   next to the rest of the component. Kept off the !important list so that
   switch can actually take effect. */

/* ==========================================================================
   Typography

   The whole voice of this system lives in three decisions: the display cut
   above 40px, weight 600 as the ceiling, and tracking that is applied at
   every size rather than left at zero. Skip the tracking and SF Pro becomes
   an ordinary grotesk.
   ========================================================================== */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  color: var(--ink);
  font-weight: var(--font-weight-semibold);
  line-height: var(--leading-heading-sm);
  letter-spacing: var(--tracking-heading-sm);
}

/* Hero. The brief's own principle — tracking tightens as size grows — wins
   over the extracted +0.011em at these outsized settings; positive tracking
   past ~64px opens the word into separate letters. */
h1 {
  font-family: var(--font-display);
  font-size: clamp(40px, 6vw, 72px);
  font-weight: var(--font-weight-semibold);
  line-height: var(--leading-display);
  letter-spacing: -0.012em;
}

h2 {
  font-size: clamp(32px, 4vw, var(--text-heading));
  line-height: var(--leading-heading);
  letter-spacing: var(--tracking-heading);
}

h3 {
  font-size: var(--text-subheading);
  line-height: var(--leading-subheading);
  letter-spacing: var(--tracking-subheading);
}

h4 {
  font-family: var(--font-body);
  font-size: var(--text-body);
  font-weight: var(--font-weight-semibold);
  line-height: 1.24;
  letter-spacing: var(--tracking-body);
}

p { max-width: 68ch; }

/* The signature whisper-voice: one size up from body, one weight down. */
p.lead {
  font-family: var(--font-body);
  font-size: clamp(19px, 2vw, 26px);
  font-weight: var(--font-weight-light);
  line-height: 1.38;
  letter-spacing: -0.011em;
  color: var(--ink);
  max-width: 46ch;
}

/* Gradient text is banned outright. The class survives so existing markup
   keeps working — it just resolves to ink, which is what a headline is. */
.gradient-text {
  background-image: none;
  background-clip: border-box;
  -webkit-background-clip: border-box;
  color: var(--ink);
  animation: none;
}

/* An eyebrow is a label, not a terminal prompt. Uppercase micro-type in Ash,
   no blinking cursor, no rule bleeding off the column. */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-8);
  font-family: var(--font-body);
  font-size: var(--text-caption);
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.06em;
  line-height: var(--leading-caption);
  text-transform: uppercase;
  color: var(--mist);
  margin-bottom: var(--spacing-12);
}
.eyebrow::after { content: none; }
.section-head:not(.center) > .eyebrow { display: inline-flex; width: auto; }
.section-head:not(.center) > .eyebrow::after { content: none; }
@keyframes cursorBlink {
  0%, 49% { opacity: 1; }
  50%, 100% { opacity: 0; }
}
.eyebrow svg { width: 14px; height: 14px; }

/* ==========================================================================
   Buttons

   Two shapes only, both fully rounded. A filled blue pill for the one action
   that matters, an outlined blue pill for the one beside it. Never two
   filled pills, never a shadow, never a sweep of light across the surface.
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-8);
  padding: 11px 21px;
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-weight: var(--font-weight-regular);
  font-size: var(--text-body);
  line-height: 1.24;
  letter-spacing: var(--tracking-body);
  white-space: nowrap;
  position: relative;
  isolation: isolate;
  border: 1px solid transparent;
  transition: background-color var(--transition), border-color var(--transition),
              color var(--transition), opacity var(--transition);
}
.btn::before { content: none; }

.btn-primary {
  background: var(--accent-fill);
  color: #fff;
  border-color: var(--accent-fill);
  box-shadow: none;
}
.btn-primary:hover {
  background: var(--accent-dim);
  border-color: var(--accent-dim);
  box-shadow: none;
  transform: none;
}
.btn-primary:active { opacity: 0.86; }
.btn-primary::after { content: none; }

.btn-ghost,
.btn-outline-navy {
  background: transparent;
  color: var(--accent);
  border: 1px solid var(--accent);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.btn-ghost:hover,
.btn-outline-navy:hover {
  background: var(--accent-tint);
  border-color: var(--accent);
  color: var(--accent);
}

/* A tertiary action is a link, not a third pill. */
.btn-text {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--accent);
  font-size: var(--text-body);
  letter-spacing: var(--tracking-body);
}
.btn-text:hover { text-decoration: underline; }

/* ---------- Header CTA ---------- */
.nav-cta-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 7px 15px;
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-weight: var(--font-weight-regular);
  font-size: var(--text-body-sm);
  letter-spacing: var(--tracking-body-sm);
  color: #fff;
  background: var(--accent-fill);
  border: 1px solid var(--accent-fill);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: none;
  transition: background-color var(--transition), border-color var(--transition);
}
.nav-cta-btn:hover {
  transform: none;
  background: var(--accent-dim);
  border-color: var(--accent-dim);
  box-shadow: none;
}
/* ==========================================================================
   Navigation

   Apple's global bar is chrome that refuses to be seen: a translucent white
   strip, 12px links in Carbon, one hairline underneath, and nothing else.
   The old floating glass capsule is gone — a pill of frosted glass hovering
   over the content is exactly the kind of container this system forbids.
   ========================================================================== */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--chrome-bg);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  /* No border here. §12: a translucent layer that content scrolls beneath
     separates itself with a scroll edge effect — a short fade where the two
     actually meet — not with a drawn line. The hairline that used to sit
     here was unconditional, so it was also there at the top of the page,
     dividing the bar from nothing. The fade below replaces it and appears
     only once there is something underneath to separate from. */
  transition: background var(--transition);
}
/* The scroll edge itself: a 14px gradient hanging below the bar, painted
   only while the page is scrolled. Content passing under the chrome
   dissolves into it instead of crossing a drawn line.

   Scoped to the mobile layout deliberately. §12 puts a scroll edge only
   where floating chrome actually overlaps content, and that is exactly the
   phone shell — a full-width translucent strip with the page running under
   it. Above 861px the header is transparent and the nav is a floating
   capsule (see nav-capsule.css and glass.css section 8): nothing there
   meets the content edge-to-edge, so a fade would be separating the page
   from empty space.

   pointer-events:none because it overhangs the first section and must not
   intercept a click meant for the content. */
@media (max-width: 860px) {
  .site-header::after {
    content: "";
    position: absolute;
    left: 0; right: 0; top: 100%;
    height: 14px;
    pointer-events: none;
    background: linear-gradient(to bottom, var(--surface-canvas), transparent);
    opacity: 0;
    transition: opacity var(--transition);
  }
  .site-header.scrolled::after { opacity: 1; }
}

/* prefers-contrast asks for a defined edge, not a soft one — a fade is
   precisely the separation that fails when contrast is what is lacking. §14. */
@media (prefers-contrast: more) {
  .site-header { border-bottom: 1px solid var(--line-strong); }
  .site-header::after { display: none; }
}

.site-header.scrolled {
  background: var(--chrome-bg-solid);
  box-shadow: none;
}
.site-header.scrolled .nav { padding-top: 10px; padding-bottom: 10px; }

.nav {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  column-gap: var(--spacing-40);
  padding: 12px clamp(20px, 4vw, 48px);
  width: 100%;
  position: relative;
  z-index: 101;
  transition: padding var(--transition);
}

.logo-mark { display: flex; align-items: center; gap: 10px; position: relative; flex-shrink: 0; justify-self: start; grid-column: 1; }
.logo-mark img {
  height: 34px;
  width: auto;
  display: block;
  filter: var(--logo-filter);
  mix-blend-mode: normal;
  transition: opacity var(--transition), filter var(--theme-transition);
}
.logo-mark:hover img { opacity: 0.7; }
@media (max-width: 860px) {
  .logo-mark img { height: 28px; }
}

.site-footer .logo {
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: var(--font-weight-semibold);
  font-size: var(--text-subheading);
  letter-spacing: var(--tracking-subheading);
  display: flex;
  align-items: center;
  gap: 8px;
}
.site-footer .logo span { color: var(--accent); }

.footer-logo-mark { display: inline-flex; align-items: center; }
.footer-logo-mark img {
  height: 30px;
  width: auto;
  display: block;
  filter: var(--logo-filter);
  mix-blend-mode: normal;
  transition: opacity var(--transition), filter var(--theme-transition);
}
.footer-logo-mark:hover img { opacity: 0.7; }

/* ---------- Link row: a continuous-tabs capsule ---------------------------
   The row is a raised pill containing the links, with a single solid
   indicator that slides between them — one element that travels, rather
   than seven that each light up. js/layout/nav-tabs.js measures the links and
   moves the indicator; every rule that paints it lives here.

   THE INDICATOR FOLLOWS HOVER, NOT CLICK. In the component this pattern
   comes from, the tabs swap panels in place, so the travel happens on
   click. These links are page navigations — click and the document is
   gone before a single frame of that animation could run. So the
   indicator rests on the current page's link, slides to whatever you
   point at, and slides back when you leave. Same motion, at the only
   moment on a multi-page site where it can actually be seen.
   -------------------------------------------------------------------- */
.nav-links-wrapper {
  justify-self: center;
  grid-column: 2;
  z-index: 5;
}

/* The capsule's own lighting. Two values rather than a shadow stack: a
   hairline of light along the top edge, which is what makes the surface
   read as raised, and nothing else — the system has no drop shadows on
   chrome and this does not introduce one. */
:root { --nav-capsule-sheen: rgba(255, 255, 255, 0.9); }
[data-theme="dark"] { --nav-capsule-sheen: rgba(255, 255, 255, 0.06); }

.nav-links {
  position: relative;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 2px;
  margin: 0;
  padding: 5px;
  isolation: isolate;
  overflow: visible;
  border-radius: var(--radius-pill);
  /* Light: #ffffff -> #f5f5f7. Dark: #1d1d1f -> #000000. One declaration,
     because both tokens already flip with the theme. */
  background: linear-gradient(180deg, var(--surface-white), var(--surface-canvas));
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: 1px solid var(--line);
  box-shadow: inset 0 1px 0 var(--nav-capsule-sheen);
}
.nav-links:hover { border-color: var(--line); }
.site-header.scrolled .nav-links {
  background: linear-gradient(180deg, var(--surface-white), var(--surface-canvas));
  border-color: var(--line);
}

.nav-links li { position: relative; z-index: 1; }

/* The travelling indicator. Injected by js/layout/nav-tabs.js, which writes its
   transform/width/height from the target link's own box — so it inherits
   whatever padding and type size the links happen to have and cannot
   drift out of step with them. Held invisible until that first
   measurement lands, so it never flashes at 0,0. */
.nav-pill {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  border-radius: var(--radius-pill);
  background: var(--ink);
  opacity: 0;
  pointer-events: none;
  transition: transform 340ms cubic-bezier(0.22, 1, 0.36, 1),
              width 340ms cubic-bezier(0.22, 1, 0.36, 1),
              opacity var(--transition);
}
.nav-links.is-pill-ready .nav-pill { opacity: 1; }
/* First paint and viewport resizes place the indicator rather than
   animating it there — a jump from the last position would read as a
   glitch, not as motion. */
.nav-pill.is-placing { transition: none; }

/* Body-sm (14px), not caption (12px).

   The nav sat one rung below the "Get Started" pill immediately to its right,
   which is already at --text-body-sm. Two sizes 2px apart in the same row is
   what made the links read as undersized rather than as quiet — the eye had a
   reference. They are the same rung now, and the pill's weight and fill still
   do the separating. */
.nav-links a:not(.btn) {
  display: block;
  font-family: var(--font-body);
  font-weight: var(--font-weight-semibold);
  font-size: var(--text-body-sm);
  letter-spacing: var(--tracking-body-sm);
  color: var(--mist);
  opacity: 1;
  position: relative;
  z-index: 1;
  white-space: nowrap;
  /* 11px → 14px horizontal: inside a capsule the label needs room on
     either side or the indicator crops to the glyphs and reads as a
     highlighter rather than a tab. */
  padding: 7px 14px;
  border-radius: var(--radius-pill);
  transition: color var(--transition);
}
.nav-links a:not(.btn)::after { content: none; }
.nav-links a:not(.btn):hover { color: var(--ink); background: none; transform: none; }

/* Whichever link the indicator is currently under — the active page's by
   default, the hovered one while a pointer is in the row. The class is
   written by js/layout/nav-tabs.js so the label flips in the same frame the
   indicator starts moving, instead of after it arrives. */
.nav-links a.is-on-pill,
.nav-links a.is-on-pill:hover { color: var(--surface-canvas); }

/* Fallback when JS never runs: no indicator exists, so the current page
   is marked the plain way instead of being left indistinguishable. */
.nav-links:not(.is-pill-ready) a.active { color: var(--ink); }
.nav-links a.active::after { content: none; }

.nav-cta { justify-self: end; grid-column: 3; }

.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  padding: 6px;
  width: 40px;
  height: 40px;
  position: relative;
  z-index: 102;
}
.nav-toggle span {
  width: 18px;
  height: 1.5px;
  background: var(--ink);
  border-radius: 2px;
  transition: transform 0.3s var(--ease-apple), opacity 0.2s ease;
}
.nav-toggle.active span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.nav-toggle.active span:nth-child(2) { opacity: 0; }
.nav-toggle.active span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

@media (max-width: 860px) {
  .nav { padding: 12px 20px; column-gap: 16px; }

  /* The capsule is a desktop object. Below the breakpoint .nav-links is a
     full-screen drawer, so every part of the treatment above is undone
     here — the indicator is removed from the layout entirely rather than
     just hidden, and the labels go back to the drawer's own type. */
  .nav-pill { display: none; }
  .nav-links a:not(.btn) { border-radius: 0; }
  .nav-links a.is-on-pill,
  .nav-links a.is-on-pill:hover { color: inherit; }

  .nav-links {
    position: fixed;
    inset: 0;
    background: var(--surface-canvas);
    background-image: none;
    border: none;
    border-radius: 0;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    flex-direction: column;
    justify-content: center;
    padding: 32px;
    display: flex;
    gap: 0;
    align-items: stretch;
    text-align: left;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-6px);
    transition: opacity 0.3s var(--ease-apple), transform 0.3s var(--ease-apple), visibility 0.3s;
  }
  .nav-links::before, .nav-links::after { content: none; }
  .nav-links.open { opacity: 1; visibility: visible; transform: translateY(0); }
  .nav-links li + li { border-top: 1px solid var(--line); }
  .nav-links a:not(.btn) {
    color: var(--ink);
    opacity: 1;
    font-family: var(--font-display);
    font-size: var(--text-heading-sm);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--tracking-heading-sm);
    padding: 18px 4px;
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 0.35s var(--ease-apple), transform 0.35s var(--ease-apple);
  }
  .nav-links.open a:not(.btn) { opacity: 1; transform: translateY(0); }
  .nav-links.open li:nth-child(1) a { transition-delay: 0.03s; }
  .nav-links.open li:nth-child(2) a { transition-delay: 0.06s; }
  .nav-links.open li:nth-child(3) a { transition-delay: 0.09s; }
  .nav-links.open li:nth-child(4) a { transition-delay: 0.12s; }
  .nav-links.open li:nth-child(5) a { transition-delay: 0.15s; }
  .nav-links.open li:nth-child(6) a { transition-delay: 0.18s; }
  .nav-links.open li:nth-child(7) a { transition-delay: 0.21s; }
  .nav-links a.active::after { display: none; }

  .nav-cta {
    position: fixed;
    left: 50%;
    bottom: 48px;
    margin-left: 0;
    transform: translate(-50%, 10px);
    opacity: 0;
    visibility: hidden;
    z-index: 103;
    transition: opacity 0.35s var(--ease-apple) 0.2s, transform 0.35s var(--ease-apple) 0.2s, visibility 0.35s;
  }
  .nav-links-wrapper:has(.nav-links.open) ~ .nav-cta {
    opacity: 1;
    visibility: visible;
    transform: translate(-50%, 0);
  }
  .nav-toggle { display: flex; }
}

/* ==========================================================================
   Scroll progress bar
   ========================================================================== */
.scroll-progress {
  position: fixed;
  top: 0; left: 0;
  height: 3px;
  width: 0%;
  background: var(--gradient-cosmic);
  z-index: 200;
  transition: width 0.1s linear;
}

/* ==========================================================================
   Hero
   ========================================================================== */
.hero {
  position: relative;
  overflow: hidden;
  background: var(--void);
  color: var(--ink);
  padding: clamp(120px, 15vh, 190px) 32px clamp(100px, 12vh, 150px);
  border-bottom: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.hero-inner { position: relative; z-index: 2; max-width: 940px; }

/* The hero headline sits at the display step, not above it. At 56px the
   sentence lands in three lines instead of six, which is the difference
   between a statement and a wall. */
.hero h1 {
  font-size: clamp(34px, 4.6vw, var(--text-display));
  line-height: var(--leading-display);
  letter-spacing: -0.008em;
  font-weight: var(--font-weight-semibold);
}
.hero p.lead { margin: 20px auto 28px; }

/* Decorative line-art behind the hero: atmosphere, and the system does not
   use atmosphere. */
.hero-traces { display: none; }

.hero-aurora {
  position: absolute;
  inset: -20% -10%;
  z-index: 0;
  pointer-events: none;
}
.hero-aurora span {
  position: absolute;
  border-radius: 50%;
  filter: blur(90px);
  opacity: 0.22;
  animation: floatBlob 16s ease-in-out infinite;
}
/* One horizon, not three floating blobs. An ember mass low-left crossfading
   into cool blue right reads as a single light source below the fold —
   several small competing glows just read as decoration. */
.hero-aurora .a1 {
  width: min(1100px, 90vw); height: min(760px, 70vh);
  background: radial-gradient(circle, var(--ember) 0%, var(--ember-deep) 42%, transparent 70%);
  bottom: -34%; left: -12%;
  opacity: 0.5; filter: blur(120px); animation-delay: 0s;
}
.hero-aurora .a2 {
  width: min(1000px, 85vw); height: min(720px, 66vh);
  background: radial-gradient(circle, var(--iris-blue) 0%, var(--iris-violet) 48%, transparent 72%);
  bottom: -30%; right: -14%;
  opacity: 0.42; filter: blur(120px); animation-delay: -6s;
}
.hero-aurora .a3 {
  width: min(760px, 62vw); height: 320px;
  background: radial-gradient(ellipse, var(--fill-hover) 0%, var(--iris-cyan) 30%, transparent 68%);
  bottom: -6%; left: 50%; margin-left: -31vw;
  opacity: 0.22; filter: blur(90px); animation-delay: -12s;
}
@keyframes floatBlob {
  0%, 100% { transform: translate(0,0) scale(1); }
  33% { transform: translate(30px,-24px) scale(1.08); }
  66% { transform: translate(-20px,20px) scale(0.95); }
}
@media (prefers-reduced-motion: reduce) {
  .hero-aurora span { animation: none; }
}

/* ---------- Traces: lines edge to edge, with light running along them ----
   The canvas is injected by js/hero-traces.js. It sits above the aurora and
   below the headline, so the light passes behind the type rather than over
   it. `.hero-visual` is lifted to the same layer as `.hero-inner` because
   without an explicit z-index it would paint underneath the canvas and the
   dashboard would end up behind the traces. */
.hero-traces {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.hero-visual { z-index: 2; }

/* The single biggest lever on how large a page feels. Tight leading and
   negative tracking do as much work here as the size itself. */
.hero h1 {
  max-width: 14ch;
  margin: 0 auto;
  font-size: clamp(2.6rem, 7.5vw, 6.4rem);
  line-height: 0.95;
  letter-spacing: -0.035em;
}

/* ---------- Client marquee (below header video) ---------- */
.client-marquee {
  padding: 24px 0 40px;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.client-marquee-track {
  display: flex;
  flex-wrap: nowrap;
  width: max-content;
  gap: clamp(28px, 5vw, 64px);
  animation: clientMarqueeDrift 24s linear infinite;
}
.client-marquee:hover .client-marquee-track { animation-play-state: paused; }
.client-marquee-track span {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  color: var(--mist-dim);
  white-space: nowrap;
}
@keyframes clientMarqueeDrift {
  0%   { transform: translateX(0); }
  100% { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .client-marquee-track { animation: none; }
}
.hero p.lead { color: var(--mist); margin: 22px auto 32px; max-width: 56ch; }
.hero-actions { display: flex; gap: 16px; flex-wrap: wrap; justify-content: center; margin-bottom: 0; }

.hero-trust {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.hero-trust span {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--mist);
  border: 1px solid var(--line);
  padding: 7px 13px;
  border-radius: 999px;
  background: var(--surface-canvas);
}
.hero-trust span b { color: var(--ink); font-weight: 600; }

/* "intent" is still wrapped in .marker-word so the typewriter can keep it on
   one line. The hand-drawn underline that used to sit under it has been
   removed — on the new hero background a coloured squiggle competed with the
   horizon light instead of accenting the word. */
.marker-word { position: relative; display: inline-block; white-space: nowrap; }

/* Hero visual: the frame that holds the live product demo */
.hero-visual {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  max-width: 980px;
  margin-top: 56px;
}

/* Hero visual: video placeholder, ready for future embedding */
.video-frame {
  width: 100%;
  max-width: 980px;
  aspect-ratio: 16 / 9;
  position: relative;
  z-index: 1;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: none;
}
.video-frame video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.video-frame-placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  text-align: center;
  padding: 24px;
}
.video-frame-placeholder::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 30% 20%, rgba(0, 113, 227, 0.22), transparent 60%),
              radial-gradient(circle at 80% 85%, var(--accent-tint-strong), transparent 55%);
  z-index: 0;
}
.video-frame-placeholder > * { position: relative; z-index: 1; }
.video-play-btn {
  width: 62px; height: 62px;
  border-radius: 50%;
  background: var(--gradient-iris);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  box-shadow: none;
  cursor: default;
  transition: transform var(--transition);
  position: relative;
}
.video-play-btn::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1.5px solid var(--iris-cyan);
  opacity: 0.55;
  animation: playPulse 2.4s ease-out infinite;
}
@keyframes playPulse {
  0%   { transform: scale(1);   opacity: 0.5; }
  100% { transform: scale(1.9); opacity: 0; }
}
.video-play-btn svg { width: 22px; height: 22px; margin-left: 3px; position: relative; z-index: 1; }
.video-frame:hover .video-play-btn { transform: scale(1.06); }
.video-frame-label {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  color: var(--mist);
}
@media (prefers-reduced-motion: reduce) {
  .video-frame:hover .video-play-btn { transform: none; }
  .video-play-btn::before { animation: none; }
}

@media (max-width: 900px) {
  .hero { padding-top: 90px; }
  .hero-visual { max-width: 100%; margin-top: 40px; }
  .hero h1 { max-width: none; }
}

/* ==========================================================================
   Sections
   ========================================================================== */
section { padding: clamp(96px, 12vw, 172px) 0; }   /* sections that breathe read as confident */
.section-head { max-width: 640px; margin-bottom: 56px; }
.section-head.center { margin-left: auto; margin-right: auto; text-align: center; }

.bg-tint { background: var(--void-2); }

/* Bento / feature grid */
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; }

.bento { display: grid; grid-template-columns: 1.3fr 1fr; grid-template-rows: repeat(2, auto); gap: 22px; }
.bento-feature { grid-row: 1 / 3; display: flex; flex-direction: column; justify-content: center; padding: 48px 40px; }
.bento-feature .card-icon { width: 58px; height: 58px; margin-bottom: 28px; }
.bento-feature .card-icon svg { width: 30px; height: 30px; }
.bento-feature h3 { font-size: 1.5rem; margin-bottom: 14px; }
.bento-feature p { font-size: 1.02rem; max-width: 46ch; }

@media (max-width: 900px) {
  .bento { grid-template-columns: 1fr; }
  .bento-feature { grid-row: auto; padding: 36px 30px; }
  .grid-3, .grid-2 { grid-template-columns: 1fr; }
}

.card {
  background: var(--glass-bg);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  padding: 34px 30px;
  box-shadow: none;
  transition: background var(--transition);
  position: relative;
}
/* A hover moves nothing and outlines nothing — the surface just steps.
   Previously this did three things at once: lifted the card 5px, swapped the
   border to --glass-border-hover, and (via the .spotlight class that
   js/core/script.js attached to every card) bloomed a pointer-tracked blue glow
   across it. All three were reported as noise. The border in particular was
   the "outline on hover" — it is the only thing drawing the card now, so it
   stays put in every state. */
.card:hover {
  background: var(--glass-bg-hover);
}
.card-icon {
  width: 48px; height: 48px;
  border-radius: var(--radius);
  background: var(--gradient-icon), var(--surface-2);
  border: 1px solid var(--icon-tile-border);
  color: var(--mist);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 20px;
  transition: border-color var(--transition), color var(--transition), background var(--transition);
}
.card-icon svg { width: 24px; height: 24px; }
.card:hover .card-icon {
  border-color: var(--line);
  color: var(--ink);
}
.card h3 { margin-bottom: 10px; }
.card p { color: var(--mist); font-size: var(--text-body-sm); line-height: var(--leading-body-sm); letter-spacing: var(--tracking-body-sm); }
.card-link {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 18px;
  font-family: var(--font-mono);
  font-size: 0.82rem;
  color: var(--accent);
  transition: gap var(--transition), color var(--transition);
}
.card:hover .card-link { gap: 10px; color: var(--accent); }

/* .tilt used to add its own smaller lift on top of the base one. It now
   inherits the plain background step like every other card; the class is left
   in place so the markup carrying it is not orphaned. */
.card.tilt { transition: background var(--transition); }
.card.tilt:hover { transform: none; box-shadow: none; border-color: var(--glass-border); }

/* Whole-card links (e.g. "View All Services", "Build Something Unique") */
a.card {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  border-style: dashed;
  border-color: var(--line-strong);
}
/* Was: border went solid and turned --iris-violet on hover. That is both an
   outline change and, in dark, a second chromatic colour the one-blue rule
   does not allow. The dashed edge is the resting signal for these
   "add something" cards; the hover is the same background step as everywhere
   else. */
a.card:hover { border-color: var(--line-strong); border-style: dashed; }
a.card .card-link { margin-top: auto; padding-top: 18px; }

/* ==========================================================================
   Services — refined bento layout (featured cards, compact cards, CTA)
   ========================================================================== */

/* Icon accent variants — subtle tinted tile per service category */
.card-icon.icon-cyan    { color: var(--accent);    background: linear-gradient(135deg, var(--accent-tint-strong), var(--accent-tint)), var(--surface-2); border-color: rgba(41, 151, 255, 0.22); }
.card-icon.icon-violet  { color: var(--accent);  background: linear-gradient(135deg, var(--accent-tint-strong), var(--accent-tint)), var(--surface-2); border-color: rgba(0, 113, 227, 0.22); }
.card-icon.icon-magenta { color: var(--accent); background: linear-gradient(135deg, var(--accent-tint-strong), var(--accent-tint)), var(--surface-2); border-color: rgba(0, 113, 227, 0.22); }
.card-icon.icon-amber   { color: var(--accent);   background: linear-gradient(135deg, var(--accent-tint-strong), var(--accent-tint)), var(--surface-2); border-color: rgba(0, 113, 227, 0.22); }
.card:hover .card-icon.icon-cyan    { box-shadow: none;  border-color: rgba(41, 151, 255, 0.5); }
.card:hover .card-icon.icon-violet  { box-shadow: none; border-color: rgba(0, 113, 227, 0.5); }
.card:hover .card-icon.icon-magenta { box-shadow: none;  border-color: rgba(0, 113, 227, 0.5); }
.card:hover .card-icon.icon-amber   { box-shadow: none;  border-color: rgba(0, 113, 227, 0.5); }
.card-icon.icon-lg { width: 56px; height: 56px; border-radius: var(--radius); margin-bottom: 0; }
.card-icon.icon-lg svg { width: 28px; height: 28px; }

/* Purposeful idle motion — each echoes what its card is actually saying,
   not decoration for its own sake. Subtle enough to read as "alive", not "busy". */

/* Timeline problem: the hand genuinely ticks forward, one notch every few seconds —
   estimates quietly slipping even while you're reading. */
.icon-anim-clock .clock-hand {
  transform-origin: 12px 12px;
  animation: clockTick 4s steps(4, end) infinite;
}
@keyframes clockTick {
  0%   { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

/* Telephone problem: the message lines drift very slightly out of alignment and
   back, as if the wording is shifting on its way through. */
.card:hover .icon-anim-message .msg-line-1 { animation: msgDrift1 5s ease-in-out infinite; }
.card:hover .icon-anim-message .msg-line-2 { animation: msgDrift2 5s ease-in-out infinite; animation-delay: 0.4s; }
.card:hover .icon-anim-message .msg-line-3 { animation: msgDrift3 5s ease-in-out infinite; animation-delay: 0.8s; }
@keyframes msgDrift1 { 0%,100% { transform: translateX(0); opacity: 1; } 50% { transform: translateX(1.5px); opacity: 0.55; } }
@keyframes msgDrift2 { 0%,100% { transform: translateX(0); opacity: 1; } 50% { transform: translateX(-1.5px); opacity: 0.55; } }
@keyframes msgDrift3 { 0%,100% { transform: translateX(0); opacity: 1; } 50% { transform: translateX(1px); opacity: 0.55; } }

/* Handoff problem: the bag settles down and resettles, like it's still being held —
   never quite fully set down. */
.card:hover .icon-anim-bag svg { animation: bagSettle 3.2s ease-in-out infinite; }
@keyframes bagSettle {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(2px); }
}

@media (prefers-reduced-motion: reduce) {
  .icon-anim-clock .clock-hand,
  .card:hover .icon-anim-message .msg-line-1,
  .card:hover .icon-anim-message .msg-line-2,
  .card:hover .icon-anim-message .msg-line-3,
  .card:hover .icon-anim-bag svg { animation: none; }
}

/* ---------------------------------------------------------------------
   Services page — one idle animation per service, each echoing what the
   service actually does (signal flow, code, loading, sketching, color,
   growth, connection, sync, search, verification).
   --------------------------------------------------------------------- */

/* AI & Automation: signal pulses outward through the three connected nodes */
.icon-anim-ai .ai-node { transform-box: fill-box; transform-origin: center; }
.card:hover .icon-anim-ai .ai-node { animation: aiPulse 2.6s ease-in-out infinite; }
.icon-anim-ai .ai-node-2 { animation-delay: 0.3s; }
.icon-anim-ai .ai-node-3 { animation-delay: 0.6s; }
@keyframes aiPulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.3); opacity: 0.55; }
}

/* Custom Software: a cursor blinks between the brackets, mid-edit */
.card:hover .icon-anim-code .code-cursor { animation: cursorBlink 1.1s step-end infinite; }

/* Apps & Websites: content lines flicker as if still loading in */
.icon-anim-device .device-line { transform-box: fill-box; transform-origin: left center; }
.card:hover .icon-anim-device .device-line { animation: deviceLoad 2.8s ease-in-out infinite; }
.icon-anim-device .device-line-2 { animation-delay: 0.35s; }
@keyframes deviceLoad {
  0%, 100% { transform: scaleX(1); opacity: 1; }
  50% { transform: scaleX(0.5); opacity: 0.5; }
}

/* UI/UX Design: a small mark draws itself in under the pencil tip, on a loop */
.icon-anim-pencil .pencil-mark { stroke-dasharray: 6; }
.card:hover .icon-anim-pencil .pencil-mark { animation: pencilWrite 2.8s ease-in-out infinite; }
@keyframes pencilWrite {
  0%, 15% { stroke-dashoffset: 6; opacity: 0; }
  45%, 75% { stroke-dashoffset: 0; opacity: 1; }
  100% { stroke-dashoffset: -6; opacity: 0; }
}

/* Branding: the accent dot cycles through the brand palette */
.card:hover .icon-anim-brand .brand-dot { animation: brandHue 4.5s linear infinite; }
@keyframes brandHue {
  0% { filter: hue-rotate(0deg); }
  100% { filter: hue-rotate(360deg); }
}

/* Data & Analytics: bars breathe up and down like a live report */
.icon-anim-chart .chart-bar { transform-box: fill-box; transform-origin: bottom; }
.card:hover .icon-anim-chart .chart-bar { animation: barGrow 2.6s ease-in-out infinite; }
.icon-anim-chart .chart-bar-2 { animation-delay: 0.2s; }
.icon-anim-chart .chart-bar-3 { animation-delay: 0.4s; }
@keyframes barGrow {
  0%, 100% { transform: scaleY(0.68); }
  50% { transform: scaleY(1); }
}

/* Integrations: the two pieces nudge toward each other, staying linked */
.icon-anim-link .link-piece { transform-box: fill-box; transform-origin: center; }
.card:hover .icon-anim-link .link-piece { animation: linkNudge 3s ease-in-out infinite; }
.icon-anim-link .link-piece-b { animation-delay: 0.5s; }
@keyframes linkNudge {
  0%, 100% { transform: translate(0, 0); }
  50% { transform: translate(0.7px, -0.7px); }
}

/* ERP & Enterprise: the top layer resettles, like data syncing between tiers */
.icon-anim-stack .stack-top { transform-box: fill-box; transform-origin: center; animation: stackSync 3.2s ease-in-out infinite; }
@keyframes stackSync {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-1.6px); }
}

/* SEO & Growth: the trend line draws itself, over and over */
.icon-anim-trend .trend-line { stroke-dasharray: 34; }
.card:hover .icon-anim-trend .trend-line { animation: trendDraw 3.2s ease-in-out infinite; }
@keyframes trendDraw {
  0% { stroke-dashoffset: 34; }
  40%, 65% { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: -34; }
}

/* Cybersecurity: the checkmark verifies itself on a loop, like active monitoring */
.icon-anim-shield .shield-check { stroke-dasharray: 11; }
.card:hover .icon-anim-shield .shield-check { animation: shieldCheck 3.4s ease-in-out infinite; }
@keyframes shieldCheck {
  0%, 15% { stroke-dashoffset: 11; opacity: 0.45; }
  45%, 80% { stroke-dashoffset: 0; opacity: 1; }
  100% { stroke-dashoffset: 11; opacity: 0.45; }
}

@media (prefers-reduced-motion: reduce) {
  .card:hover .icon-anim-ai .ai-node,
  .card:hover .icon-anim-code .code-cursor,
  .card:hover .icon-anim-device .device-line,
  .card:hover .icon-anim-pencil .pencil-mark,
  .card:hover .icon-anim-brand .brand-dot,
  .card:hover .icon-anim-chart .chart-bar,
  .card:hover .icon-anim-link .link-piece,
  .icon-anim-stack .stack-top,
  .card:hover .icon-anim-trend .trend-line,
  .card:hover .icon-anim-shield .shield-check { animation: none; }
}

/* Small labelled tag, used on featured cards and the CTA card */
.service-tag {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--mist-dim);
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-canvas);
}

/* Featured row: AI & Automation / Custom Software */
.services-featured-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  margin-bottom: 24px;
}
.service-featured {
  padding: 40px 40px 36px;
  display: flex;
  flex-direction: column;
}
.service-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 24px;
}
.service-featured h3 { font-size: 1.4rem; margin-bottom: 12px; }
.service-featured > p { color: var(--mist); font-size: 1rem; max-width: 46ch; }
.service-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 28px;
  margin-top: 26px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
}
.service-meta-label {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mist-dim);
  margin-bottom: 10px;
}
.service-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.service-list li {
  position: relative;
  padding-left: 15px;
  font-size: 0.87rem;
  line-height: 1.5;
  color: var(--mist);
}
.service-list li::before {
  content: "";
  position: absolute;
  left: 0; top: 8px;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--iris-violet);
}

/* Standard 8-card grid below the featured row */
.services-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  margin-bottom: 24px;
}
.service-card p { margin-bottom: 16px; }
.service-list-compact {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin-bottom: 18px;
}
.service-list-compact li {
  position: relative;
  padding-left: 14px;
  font-size: 0.84rem;
  line-height: 1.5;
  color: var(--mist-dim);
}
.service-list-compact li::before {
  content: "";
  position: absolute;
  left: 0; top: 7px;
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--line-strong);
}
.service-outcome-line {
  display: flex;
  align-items: center;
  gap: 9px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  font-size: 0.85rem;
  color: var(--ink);
  font-weight: 500;
}
.service-outcome-line svg {
  width: 15px; height: 15px;
  color: var(--accent);
  flex-shrink: 0;
}
.service-pricing-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 14px;
  padding: 10px 18px;
  border-radius: 999px;
  border: 1px solid var(--glass-border);
  background: var(--surface-canvas);
  font-size: 0.83rem;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  transition: gap 0.2s ease, border-color var(--transition), background var(--transition), color var(--transition), transform var(--transition);
}
.service-pricing-link:hover {
  gap: 10px;
  border-color: var(--accent);
  background: var(--accent-tint);
  color: var(--accent);
  transform: translateY(-1px);
}

/* Featured cards: pricing pill + a lighter secondary path, side by side */
.service-cta-row {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 14px;
}
.service-cta-row .service-pricing-link { margin-top: 0; }
.service-secondary-link {
  font-size: 0.83rem;
  font-weight: 500;
  color: var(--mist);
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 3px;
  transition: color var(--transition), text-decoration-color var(--transition);
}
.service-secondary-link:hover { color: var(--ink); text-decoration-color: var(--accent); }

/* Compact cards: click-to-expand "what's included" detail */
.service-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  margin-top: 4px;
  padding: 13px 0 0;
  background: none;
  border: none;
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 0.76rem;
  font-weight: 500;
  letter-spacing: 0.03em;
  color: var(--mist);
  cursor: pointer;
  transition: color var(--transition);
}
.service-toggle:hover, .service-toggle:focus-visible { color: var(--ink); }
.service-toggle .toggle-chevron {
  width: 15px; height: 15px; flex-shrink: 0;
  transition: transform var(--transition);
}
.service-toggle[aria-expanded="true"] .toggle-chevron { transform: rotate(180deg); }

.service-more {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.35s cubic-bezier(0.28, 0.11, 0.32, 1);
}
.service-card.is-expanded .service-more { grid-template-rows: 1fr; }
.service-more-inner { overflow: hidden; }
.service-more .service-list-compact {
  padding-top: 13px;
  margin-bottom: 0;
}

/* Premium CTA card — replaces "Build Something Unique" placeholder */
.service-cta {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 40px;
  padding: 48px 56px;
  border-radius: var(--radius);
  border: 1px solid var(--glass-border);
  background: var(--glass-bg);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: none;
  overflow: hidden;
  text-decoration: none;
  transition: border-color var(--transition), transform var(--transition), box-shadow var(--transition);
}
.service-cta-glow {
  position: absolute;
  inset: -40%;
  background: var(--gradient-iris-soft);
  opacity: 0.16;
  filter: blur(60px);
  transition: opacity var(--transition);
  pointer-events: none;
}
.service-cta:hover {
  border-color: rgba(0, 113, 227, 0.4);
  transform: translateY(-4px);
  box-shadow: none;
}
.service-cta:hover .service-cta-glow { opacity: 0.28; }
.service-cta-content { position: relative; z-index: 1; max-width: 52ch; }
.service-cta-content h3 { font-size: 1.6rem; margin: 14px 0 10px; }
.service-cta-content p { color: var(--mist); }
.service-tag-cta { color: var(--accent); border-color: rgba(41, 151, 255, 0.25); }
.service-cta-btn { position: relative; z-index: 1; flex-shrink: 0; }

@media (max-width: 900px) {
  .services-featured-row, .services-grid { grid-template-columns: 1fr; }
  .service-columns { grid-template-columns: 1fr; gap: 20px; }
  .service-cta { flex-direction: column; align-items: flex-start; padding: 36px 30px; }
}

/* ==========================================================================
   Process timeline
   ========================================================================== */
.process-strip {
  display: flex;
  gap: 0;
  border-top: 1px solid var(--line);
  position: relative;
}
.process-step { flex: 1; padding: 32px 24px; border-right: 1px solid var(--line); position: relative; overflow: hidden; }
.process-step:last-child { border-right: none; }
.process-step .eyebrow { margin-bottom: 18px; }
.process-step h4, .process-step h3 { font-family: var(--font-display); font-size: 1.05rem; color: var(--ink); margin-bottom: 8px; }
.process-step p { font-size: 0.9rem; color: var(--mist); }
.process-step > * { position: relative; z-index: 1; }
.process-step .step-num {
  position: absolute;
  top: -14px; right: 8px;
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 4.6rem;
  line-height: 1;
  z-index: 0;
  background: none;
  -webkit-background-clip: border-box; background-clip: border-box; color: var(--ink);
  opacity: 0.22;
  pointer-events: none;
}

@media (max-width: 900px) {
  .process-strip {
    flex-wrap: nowrap;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    border-top: none;
    margin: 0 -32px;
    padding: 0 32px;
    gap: 16px;
    scrollbar-width: none;
  }
  .process-strip::-webkit-scrollbar { display: none; }
  .process-step {
    flex: 0 0 78%;
    scroll-snap-align: start;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
  }
}

/* ==========================================================================
   Work / case study cards
   ========================================================================== */
.filter-row { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 40px; }
.filter-chip {
  font-family: var(--font-mono);
  font-size: 0.82rem;
  color: var(--mist);
  background: var(--surface);
  border: 1px solid var(--line);
  padding: 9px 18px;
  border-radius: 999px;
  transition: all var(--transition);
}
.filter-chip:hover { color: var(--ink); border-color: var(--line-strong); }
.filter-chip.active { color: #fff; background: var(--accent-fill); border-color: var(--accent); }

.work-card {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--glass-border);
  transition: transform var(--transition), box-shadow var(--transition), opacity 0.3s ease, border-color var(--transition);
  background: var(--glass-bg);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: none;
}
.work-card.is-hidden { display: none; }
.work-card.is-fading { opacity: 0; transform: scale(0.93) translateY(8px); }
.filter-chip { transform: scale(1); }
.filter-chip.chip-pop { animation: chipPop 0.35s cubic-bezier(0.28, 0.11, 0.32, 1); }
@keyframes chipPop { 40% { transform: scale(0.93); } 100% { transform: scale(1); } }
/* No lift, no outline swap — same rule as every other card surface. */
.work-card:hover { transform: none; box-shadow: none; border-color: var(--glass-border); background: var(--glass-bg-hover); }
.work-thumb {
  height: 180px;
  position: relative;
  display: flex; align-items: center; justify-content: center;
  color: var(--fill-hover);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  overflow: hidden;
}
.work-thumb::before {
  content: none;
}
.work-thumb { background: var(--surface-pebble); color: var(--mist); }
.work-thumb span {
  position: relative; z-index: 1;
  background: var(--surface-white);
  border: 1px solid var(--line);
  color: var(--mist);
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  font-size: var(--text-caption);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  backdrop-filter: none;
}
.work-body { padding: 26px; }
.work-tag {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--accent);
  background: var(--accent-tint-strong);
  border: 1px solid rgba(41, 151, 255, 0.25);
  padding: 4px 10px;
  border-radius: 6px;
  margin-bottom: 12px;
}
.work-tag::before { content: "<"; opacity: 0.6; }
.work-tag::after { content: "/>"; opacity: 0.6; }
.work-body h3 { margin-bottom: 8px; }
.work-body p { color: var(--mist); font-size: 0.92rem; margin-bottom: 14px; }
.placeholder-note { font-size: 0.78rem; color: var(--mist-dim); font-style: italic; }

/* ==========================================================================
   Editorial quote / testimonial
   ========================================================================== */
.editorial-quote-section { padding: 60px 0 120px; }
.editorial-quote {
  position: relative;
  max-width: 780px;
  margin: 0 auto;
  text-align: center;
  padding: 56px 48px;
  background: var(--glass-bg);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-lg);
  box-shadow: none;
  transition: border-color var(--transition), box-shadow var(--transition), transform var(--transition);
}
.editorial-quote:hover { border-color: var(--glass-border); box-shadow: none; transform: none; background: var(--glass-bg-hover); }
.editorial-quote .quote-mark {
  position: absolute;
  top: -8px; left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-display);
  font-size: 7rem;
  font-weight: 600;
  background: none;
  -webkit-background-clip: border-box; background-clip: border-box; color: var(--ink);
  opacity: 0.5;
  line-height: 1;
  z-index: 0;
}
.editorial-quote-text {
  position: relative; z-index: 1;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.4rem, 2.6vw, 1.9rem);
  line-height: 1.4;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.editorial-quote-person { position: relative; z-index: 1; margin-top: 24px; font-family: var(--font-mono); font-size: 0.85rem; color: var(--mist); }
.editorial-quote-person .dash { color: var(--accent); margin: 0 4px; }

/* ==========================================================================
   Stat row
   ========================================================================== */
.stat-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-top: 20px; }
.stat-card {
  position: relative;
  background: var(--glass-bg);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  padding: 26px;
  text-align: center;
  box-shadow: none;
  transition: transform var(--transition), box-shadow var(--transition), border-color var(--transition);
}
.stat-card:hover { transform: none; box-shadow: none; border-color: var(--glass-border); background: var(--glass-bg-hover); }
.stat-card .stat-num {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 2.2rem;
  background: none;
  -webkit-background-clip: border-box; background-clip: border-box; color: var(--ink);
}
.stat-card .stat-label { font-family: var(--font-mono); font-size: 0.78rem; color: var(--mist); margin-top: 6px; letter-spacing: 0.02em; }
@media (max-width: 700px) { .stat-grid { grid-template-columns: 1fr; } }

/* ==========================================================================
   CTA banner
   ========================================================================== */
/* The brief's Feature Banner: a full-bleed surface change, not a card. A
   bordered, rounded panel floating inside a section is precisely the
   container this system forbids — the wash itself is the surface. */
.cta-banner {
  position: relative;
  overflow: hidden;
  background: var(--surface-elevated-wash);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  color: var(--ink);
  border: none;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  padding: clamp(72px, 9vw, 112px) 32px;
  text-align: center;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  box-shadow: none;
}
.cta-banner::before { content: none; }
.cta-banner > * { position: relative; z-index: 1; }
.cta-banner h2 { color: var(--ink); margin-bottom: 14px; }
.cta-banner p { color: var(--mist); margin-bottom: 30px; }
.cta-actions { display: inline-flex; gap: 14px; flex-wrap: wrap; justify-content: center; }

/* ==========================================================================
   Footer
   ========================================================================== */
.site-footer { background: var(--void-2); color: var(--mist); padding: 64px 0 32px; margin-top: 96px; border-top: 1px solid var(--line); }
.footer-grid { display: grid; grid-template-columns: 1.4fr repeat(3, 1fr); gap: 40px; margin-bottom: 40px; }
.footer-grid h4, .footer-grid h2 {
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--text-caption);
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.02em;
  line-height: var(--leading-caption);
  text-transform: none;
  margin-bottom: 14px;
}
.footer-grid ul li { margin-bottom: 8px; font-size: var(--text-caption); line-height: var(--leading-caption); letter-spacing: var(--tracking-caption); }
.footer-grid ul li a:hover { color: var(--accent); }
.footer-grid ul li .copy-btn { cursor: pointer; transition: color var(--transition); }
.footer-grid ul li .copy-btn:hover { color: var(--accent); }

.social-row { display: flex; gap: 10px; margin-top: 20px; }
.social-row a {
  width: 38px; height: 38px;
  border-radius: 50%;
  border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center;
  transition: all var(--transition);
}
.social-row a:hover { border-color: var(--accent); color: var(--accent); transform: none; }
.social-row svg { width: 17px; height: 17px; }

.footer-bottom {
  border-top: 1px solid var(--line);
  padding-top: 24px;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--mist-dim);
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
}
@media (max-width: 800px) { .footer-grid { grid-template-columns: repeat(2, 1fr); } }

/* ---- Footer: huge CTA banner ---- */
.footer-cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
  flex-wrap: wrap;
  padding-bottom: 52px;
  margin-bottom: 52px;
  border-bottom: 1px solid var(--line);
}
.footer-cta-eyebrow {
  font-family: var(--font-body);
  font-size: var(--text-caption);
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mist);
  margin-bottom: 14px;
}
.footer-cta-giant {
  font-family: var(--font-display);
  font-size: clamp(2rem, 4.2vw, 3.25rem);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.footer-cta-btn {
  flex-shrink: 0;
  padding: 22px 42px;
  font-size: 1rem;
}
@media (max-width: 700px) {
  .footer-cta { flex-direction: column; align-items: flex-start; }
  .footer-cta-btn { width: 100%; justify-content: center; }
}

/* ---- Footer nav columns: clearer hierarchy + directional hover ---- */
.footer-grid h4, .footer-grid h2 {
  position: relative;
  display: inline-block;
  padding-bottom: 12px;
}
.footer-grid h4, .footer-grid h2 { padding-bottom: 0; }
.footer-grid h4::after, .footer-grid h2::after { content: none; }
.footer-grid ul li a {
  display: inline-flex;
  align-items: center;
}
.footer-grid ul li a::before {
  content: "\2192";
  display: inline-block;
  width: 0;
  opacity: 0;
  color: var(--accent);
  overflow: hidden;
  transition: width 0.25s ease, opacity 0.25s ease, margin-right 0.25s ease;
}
.footer-grid ul li a:hover::before { width: 14px; opacity: 1; margin-right: 4px; }

/* ---- Footer: animated social icons ---- */
.social-row a {
  position: relative;
  overflow: hidden;
  transition: transform 0.35s cubic-bezier(0.28, 0.11, 0.32, 1), border-color 0.3s ease, box-shadow 0.35s ease;
}
.social-row a::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--gradient-iris);
  opacity: 0;
  transition: opacity 0.3s ease;
}
.social-row a svg {
  position: relative;
  z-index: 1;
  transition: transform 0.4s cubic-bezier(0.28, 0.11, 0.32, 1), color 0.3s ease;
}
.social-row a:hover {
  border-color: transparent;
  transform: translateY(-5px) scale(1.08) rotate(-4deg);
  box-shadow: none;
}
.social-row a:hover::before { opacity: 1; }
.social-row a:hover svg { color: #fff; transform: none; }

/* ---- Footer bottom: legal nav ---- */
.footer-legal { display: flex; gap: 20px; }
.footer-legal a { transition: color var(--transition); }
.footer-legal a:hover { color: var(--accent); }

@media (prefers-reduced-motion: reduce) {
  .social-row a, .social-row a svg, .footer-grid ul li a::before { transition: none; }
}

/* ==========================================================================
   Page hero (sub-pages)
   ========================================================================== */
.page-hero {
  position: relative;
  overflow: hidden;
  background: var(--surface-canvas);
  color: var(--ink);
  padding: clamp(96px, 11vh, 148px) 32px clamp(72px, 8vh, 104px);
  text-align: center;
  border-bottom: 1px solid var(--line);
}
.page-hero .hero-inner { max-width: 900px; margin: 0 auto; }
.page-hero h1 {
  max-width: none;
  font-size: clamp(34px, 4.6vw, var(--text-display));
  line-height: var(--leading-display);
  letter-spacing: -0.008em;
}
.page-hero p.lead { margin-left: auto; margin-right: auto; }

/* Inner pages get the same single light source as the homepage, at lower
   intensity — on true black an unlit section reads as an empty page rather
   than a restrained one. Warm on the left, cool on the right, as everywhere. */
.page-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  /* Section rhythm here comes from the surface change and the hairline under
     it, not from a coloured wash bleeding up off the floor. */
  background: none;
  filter: none;
}
.page-hero h1 { color: var(--ink); max-width: 16ch; }
.page-hero p.lead { color: var(--mist); }
.page-hero .hero-inner { position: relative; z-index: 1; }

.blob { position: absolute; border-radius: 50%; filter: blur(60px); pointer-events: none; z-index: 0; animation: floatBlob 18s ease-in-out infinite; }
.blob-sky { background: var(--iris-cyan); opacity: 0.28; }
.blob-navy { background: var(--iris-violet); opacity: 0.24; }
@media (prefers-reduced-motion: reduce) { .blob { animation: none; } }

.service-row { position: relative; }
.service-num {
  position: absolute; top: -34px; left: -6px;
  font-family: var(--font-mono); font-weight: 600; font-size: 5.5rem; line-height: 1;
  z-index: -1; pointer-events: none;
  background: none;
  -webkit-background-clip: border-box; background-clip: border-box; color: var(--ink);
  opacity: 0.22;
}
@media (max-width: 900px) { .service-num { font-size: 3.6rem; top: -18px; } }

.checklist { margin-top: 16px; display: flex; flex-direction: column; gap: 12px; color: var(--mist); font-size: 0.95rem; }
.checklist li { display: flex; align-items: flex-start; gap: 10px; }
.checklist li::before {
  content: "";
  flex-shrink: 0;
  width: 18px; height: 18px;
  margin-top: 2px;
  border-radius: 5px;
  background: var(--accent-tint-strong);
  border: 1px solid rgba(41, 151, 255, 0.4);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"%234FD8E8\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M20 6L9 17l-5-5\"/></svg>");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 11px;
}

/* Forms */
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.form-field { display: flex; flex-direction: column; gap: 8px; margin-bottom: 20px; }
.form-field.full { grid-column: 1 / -1; }
.form-field { text-align: left; }
.form-field label {
  font-family: var(--font-body);
  font-size: var(--text-body-sm);
  font-weight: var(--font-weight-regular);
  letter-spacing: var(--tracking-body-sm);
  color: var(--mist);
}
.form-field input, .form-field select, .form-field textarea {
  font-family: var(--font-body);
  font-size: var(--text-body);
  letter-spacing: var(--tracking-body);
  padding: 12px 15px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: border-color var(--transition), box-shadow var(--transition);
  background: var(--surface-white);
  color: var(--ink);
}
.form-field input::placeholder, .form-field textarea::placeholder { color: var(--mist-dim); }
.form-field select { appearance: none; background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"%236e6e73\" stroke-width=\"2\"><path d=\"M6 9l6 6 6-6\"/></svg>"); background-repeat: no-repeat; background-position: right 14px center; background-size: 16px; padding-right: 40px; }
.form-field input:focus, .form-field select:focus, .form-field textarea:focus {
  outline: none;
  border-color: var(--accent-fill);
  box-shadow: 0 0 0 2px var(--accent-fill);
}
.form-field textarea { resize: vertical; min-height: 130px; }
@media (max-width: 700px) { .form-grid { grid-template-columns: 1fr; } }

/* ==========================================================================
   Team avatars (about page)
   ========================================================================== */
.avatar-ring {
  width: 74px; height: 74px;
  border-radius: 50%;
  margin: 0 auto 20px;
  padding: 3px;
  background: var(--gradient-iris);
  display: flex; align-items: center; justify-content: center;
}
.avatar-ring-inner {
  width: 100%; height: 100%;
  border-radius: 50%;
  background: var(--void-2);
  display: flex; align-items: center; justify-content: center;
  color: var(--ink);
}
.avatar-ring-inner svg { width: 30px; height: 30px; }

a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* ==========================================================================
   Custom scrollbar
   ========================================================================== */
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: var(--void); }
::-webkit-scrollbar-thumb { background: var(--surface-2); border-radius: 999px; border: 2px solid var(--void); }
::-webkit-scrollbar-thumb:hover { background: var(--iris-violet); }
html { scrollbar-color: var(--surface-2) var(--void); scrollbar-width: thin; }

/* ==========================================================================
   Cursor spotlight glow
   ========================================================================== */
/* WITHDRAWN — this was the "cards light up under the cursor" effect.

   js/core/script.js used to attach .spotlight to every .card and .work-card on
   every page at runtime (it appears in no HTML file, which is why it is easy
   to miss) and feed the pointer position into --mx/--my. This rule then
   painted a 260px accent-tinted radial glow that tracked the cursor across
   the card face.

   The rule is neutralised rather than deleted, and the stacking context on
   children is kept, so any markup or script still referencing the class
   degrades to nothing instead of breaking its layer order. The class is no
   longer applied — see js/core/script.js. */
.spotlight { position: relative; }
.spotlight::before { content: none; }
.spotlight > * { position: relative; z-index: 1; }

/* ==========================================================================
   Staggered reveal
   ========================================================================== */
.reveal { opacity: 0; transform: translateY(28px); transition: opacity 0.8s cubic-bezier(0.28, 0.11, 0.32, 1), transform 0.8s cubic-bezier(0.28, 0.11, 0.32, 1); }
.reveal.in-view { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) { .reveal { opacity: 1; transform: none; transition: none; } }
.grid-3 .reveal:nth-child(1) { transition-delay: 0s; }
.grid-3 .reveal:nth-child(2) { transition-delay: 0.1s; }
.grid-3 .reveal:nth-child(3) { transition-delay: 0.2s; }
.grid-3 .reveal:nth-child(4) { transition-delay: 0.3s; }
.grid-3 .reveal:nth-child(5) { transition-delay: 0.4s; }
.grid-3 .reveal:nth-child(6) { transition-delay: 0.5s; }
.services-featured-row .reveal:nth-child(1) { transition-delay: 0s; }
.services-featured-row .reveal:nth-child(2) { transition-delay: 0.1s; }
.services-grid .reveal:nth-child(1) { transition-delay: 0s; }
.services-grid .reveal:nth-child(2) { transition-delay: 0.06s; }
.services-grid .reveal:nth-child(3) { transition-delay: 0.12s; }
.services-grid .reveal:nth-child(4) { transition-delay: 0.18s; }
.services-grid .reveal:nth-child(5) { transition-delay: 0.24s; }
.services-grid .reveal:nth-child(6) { transition-delay: 0.3s; }
.services-grid .reveal:nth-child(7) { transition-delay: 0.36s; }
.services-grid .reveal:nth-child(8) { transition-delay: 0.42s; }
.process-strip .reveal:nth-child(1) { transition-delay: 0s; }
.process-strip .reveal:nth-child(2) { transition-delay: 0.1s; }
.process-strip .reveal:nth-child(3) { transition-delay: 0.2s; }
.process-strip .reveal:nth-child(4) { transition-delay: 0.3s; }

/* ==========================================================================
   Back-to-top
   ========================================================================== */
/* Bottom-right is shared with the site-tour launcher (js/tour/ai-tour-guide.js
   pins itself at right:26 bottom:26, 60px across). At 24/24 this button sat
   directly on top of it and you could not use both.

   The two now stack: the launcher keeps the corner, this sits one slot above
   it, and `right` is set so the 48px button shares the launcher's centre line
   rather than being a few pixels off it. */
.back-to-top {
  position: fixed; right: 32px; bottom: 98px;
  width: 48px; height: 48px;
  border-radius: 50%;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  color: var(--ink);
  display: flex; align-items: center; justify-content: center;
  box-shadow: none;
  opacity: 0; transform: translateY(12px);
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.3s ease, background 0.2s ease, border-color 0.2s ease;
  z-index: 90;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.back-to-top.visible { opacity: 1; transform: translateY(0); pointer-events: auto; }
.back-to-top:hover { border-color: var(--accent); color: var(--accent); }
.back-to-top svg { width: 20px; height: 20px; }

/* ==========================================================================
   Custom trailing cursor dot
   ========================================================================== */
.cursor-dot {
  position: fixed; top: 0; left: 0;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--accent-fill);
  pointer-events: none;
  z-index: 999;
  opacity: 0;
  transition: opacity 0.3s ease, transform 0.1s ease, width 0.2s ease, height 0.2s ease, background 0.2s ease;
}
.cursor-dot.active { opacity: 0.7; }
.cursor-dot.hovering { width: 36px; height: 36px; background: transparent; border: 1.5px solid var(--iris-cyan); opacity: 0.9; }
@media (hover: none), (pointer: coarse) { .cursor-dot { display: none; } }

/* ==========================================================================
   Confetti burst
   ========================================================================== */
.confetti-particle {
  position: fixed;
  width: 7px; height: 7px;
  border-radius: 2px;
  pointer-events: none;
  z-index: 500;
  top: 0; left: 0;
  opacity: 1;
}

/* ==========================================================================
   Toast
   ========================================================================== */
.toast {
  position: fixed;
  bottom: 30px; left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 0.85rem;
  padding: 12px 22px;
  border-radius: 999px;
  box-shadow: none;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.3s ease;
  z-index: 500;
  display: flex; align-items: center; gap: 8px;
}
.toast.visible { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast .toast-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent-fill); }

.pull-quote {
  border-left: 3px solid var(--iris-violet);
  padding-left: 24px;
  margin: 32px 0;
  font-family: var(--font-serif);
  /* Instrument Serif has a much larger optical size than Space Grotesk at the
     same px value, so the scale steps up and the tracking tightens to keep it
     from shouting next to the body copy. */
  font-size: 1.65rem;
  font-style: italic;
  letter-spacing: -0.01em;
  color: var(--ink);
  line-height: 1.4;
}
/* Emphasis inside a headline changes register by weight and slant, not by
   colour. #0071e3 is a button fill and #2997ff fails contrast at text size —
   so the emphasised phrase stays in Carbon and simply lightens. */
.accent-italic {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: var(--font-weight-light);
  letter-spacing: -0.005em;
  background: none;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  color: var(--ink);
}

.watermark-wrap { position: relative; overflow: hidden; }
.watermark {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(6rem, 18vw, 15rem);
  color: var(--ink);
  opacity: 0.035;
  white-space: nowrap; letter-spacing: -0.02em;
  z-index: 0; pointer-events: none;
}
.watermark-wrap > .container { position: relative; z-index: 1; }

/* ==========================================================================
   Mission / Vision / Values — three glass cards with an animated hexagon
   icon (soft breathing glow + slow rotating ring), one hue per card,
   staying inside the site's purple/blue/cyan system.
   ========================================================================== */
/* Two statements over three principles, rather than three equal boxes.

   Mission and Vision are long-form claims and get width; the values are short
   and specific and get a row of their own underneath. The hierarchy is the
   point — previously all three were the same size, so nothing told you the
   third card was a different KIND of thing from the first two. */
.mvv { margin-top: 56px; }

.mvv-statements {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 26px;
}
.mvv-card {
  text-align: left;
  padding: 38px 34px 34px;
}
.mvv-card p {
  color: var(--mist);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  letter-spacing: var(--tracking-body);
  max-width: 46ch;
  margin: 0;
}

/* Small caps label doing the job the old <h3> did, but at label weight so it
   sits under the statement rather than competing with it. */
.mvv-label {
  display: block;
  font-family: var(--font-body);
  font-size: var(--text-caption);
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mist);
  margin-bottom: 18px;
}

/* ---- The three principles --------------------------------------------- */
.mvv-principles {
  margin-top: 40px;
  padding-top: 34px;
  border-top: 1px solid var(--line);
}
.mvv-principles > .mvv-label { margin-bottom: 22px; }

.mvv-principle-list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 26px;
  list-style: none;
  margin: 0;
  padding: 0;
}
/* Deliberately not cards. Three more bordered boxes directly under two
   bordered boxes is the sameness this section was being criticised for; a
   rule and an indent separate them without adding another frame. */
.mvv-principle {
  padding-left: 18px;
  border-left: 2px solid var(--accent);
}
.mvv-principle h3 {
  font-size: var(--text-subheading);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-subheading);
  line-height: var(--leading-subheading);
  color: var(--ink);
  margin: 0 0 8px;
}
.mvv-principle p {
  color: var(--mist);
  font-size: var(--text-body-sm);
  line-height: var(--leading-body-sm);
  letter-spacing: var(--tracking-body-sm);
  margin: 0;
}

@media (max-width: 860px) {
  .mvv-statements { grid-template-columns: 1fr; }
  .mvv-principle-list { grid-template-columns: 1fr; gap: 22px; }
  .mvv-principles { margin-top: 30px; padding-top: 26px; }
}

.mvv-icon {
  position: relative;
  width: 74px;
  height: 74px;
  margin: 0 0 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  clip-path: polygon(25% 3%, 75% 3%, 100% 50%, 75% 97%, 25% 97%, 0% 50%);
  border: 1px solid var(--icon-tile-border);
  transition: transform var(--transition);
}
.mvv-icon svg { width: 30px; height: 30px; position: relative; z-index: 2; }

.mvv-icon-violet { background: linear-gradient(135deg, rgba(0, 113, 227, 0.26), var(--accent-tint)); color: var(--accent); }
.mvv-icon-blue   { background: linear-gradient(135deg, rgba(0, 113, 227, 0.26), var(--accent-tint));   color: var(--accent); }
.mvv-icon-cyan   { background: linear-gradient(135deg, rgba(41, 151, 255, 0.26), var(--accent-tint));   color: var(--accent); }

/* Was a breathing blurred glow behind the icon, plus a dashed ring rotating
   forever around it. Both are atmosphere on decorative furniture — the icon
   tile carries itself. */
.mvv-icon::before { content: none; }
/* Slow rotating dashed ring — reads as a quiet "always on" system indicator */
.mvv-icon::after { content: none; }
.mvv-card:nth-child(2) .mvv-icon::before,
.mvv-card:nth-child(2) .mvv-icon::after { animation-delay: -1.5s; }
.mvv-card:nth-child(3) .mvv-icon::before,
.mvv-card:nth-child(3) .mvv-icon::after { animation-delay: -3s; }

@keyframes mvvBreathe {
  0%, 100% { transform: scale(0.9); opacity: 0.12; }
  50% { transform: scale(1.1); opacity: 0.26; }
}
@keyframes mvvSpin { to { transform: rotate(360deg); } }

.mvv-card:hover .mvv-icon { transform: none; }
.mvv-card:hover .mvv-icon::before { opacity: 0.32; }

@media (prefers-reduced-motion: reduce) {
  .mvv-icon::before, .mvv-icon::after { animation: none; }
}
@media (max-width: 900px) {
  .mvv-statements { grid-template-columns: 1fr; gap: 18px; }
}
/* The old three-card grid's stagger. The entrance is driven from
   js/pages/animate.js against [data-anim="values"] now, and motion.css already
   forces transition-delay:0 on those cards, so these were dead. */

/* Utility */
.mt-lg { margin-top: 56px; }
.text-center { text-align: center; }

/* ==========================================================================
   Unified premium glass finish — applied last so it wins the cascade.
   Every glass surface site-wide gets the same static light-catch top/left
   borders used on the "Get Started" nav button, so the whole product reads
   as one continuous material. No sweep animation — just the resting look.
   ========================================================================== */
.card,
.work-card,
.editorial-quote,
.stat-card,
.service-cta,
.video-frame,
.back-to-top,
.toast {
  border-top-color: var(--glass-border-top);
  border-left-color: var(--glass-border-left);
}
/* Card surfaces are deliberately absent from this list. This block lights the
   top and left edges on hover, which on a card is a second outline change on
   top of the one that used to sit on .card:hover — and the outline is the
   only thing drawing a card now that the fill sits so close to the page, so
   it has to stay put. Buttons keep the edge lift: they are not defined by
   their border in the same way. */
.service-cta:hover,
.back-to-top:hover {
  border-top-color: var(--glass-border-top-hover);
  border-left-color: var(--glass-border-left-hover);
}

/* ==========================================================================
   ANIMATION ENHANCEMENTS — pass 2
   Bringing motion to the sections that were still landing static: hero
   copy on every page, footers, CTA banners, checklists, and form fields.
   Everything here respects prefers-reduced-motion.
   ========================================================================== */

/* ---- Hero copy: blurred + slightly scaled down, then resolves into focus (fast, all together) ---- */
.hero-inner > *,
.page-hero .hero-inner > * {
  opacity: 0;
  transform: translateY(8px);
  animation: heroFadeUp 0.45s cubic-bezier(0.28, 0.11, 0.32, 1) forwards;
}
.hero-inner > *:nth-child(1), .page-hero .hero-inner > *:nth-child(1) { animation-delay: 0s; }
.hero-inner > *:nth-child(2), .page-hero .hero-inner > *:nth-child(2) { animation-delay: 0.02s; }
.hero-inner > *:nth-child(3), .page-hero .hero-inner > *:nth-child(3) { animation-delay: 0.04s; }
.hero-inner > *:nth-child(4), .page-hero .hero-inner > *:nth-child(4) { animation-delay: 0.06s; }
@keyframes heroFadeUp {
  0% { opacity: 0; transform: translateY(8px); }
  100% { opacity: 1; transform: translateY(0); }
}

.hero-visual {
  opacity: 0;
  transform: translateX(10px);
  animation: heroSlideIn 0.45s var(--ease-apple) forwards;
  animation-delay: 0.02s;
}
@keyframes heroSlideIn {
  0% { opacity: 0; transform: translateX(10px); }
  100% { opacity: 1; transform: translateX(0); }
}

/* ---- Reusable stagger-delay utilities for any .reveal element ---- */
.reveal.delay-1 { transition-delay: 0.1s; }
.reveal.delay-2 { transition-delay: 0.2s; }
.reveal.delay-3 { transition-delay: 0.3s; }
.reveal.delay-4 { transition-delay: 0.4s; }

/* ---- CTA banners: headline, copy and button rise in on scroll ---- */
.cta-banner.reveal h2,
.cta-banner.reveal p,
.cta-banner.reveal .btn {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.7s cubic-bezier(0.28, 0.11, 0.32, 1), transform 0.7s cubic-bezier(0.28, 0.11, 0.32, 1);
}
.cta-banner.reveal.in-view h2 { opacity: 1; transform: none; transition-delay: 0.05s; }
.cta-banner.reveal.in-view p { opacity: 1; transform: none; transition-delay: 0.16s; }
.cta-banner.reveal.in-view .btn { opacity: 1; transform: none; transition-delay: 0.27s; }

/* ---- Footer: whole grid rises in, columns staggered, links nudge on hover ---- */
.footer-grid.reveal > * {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.65s cubic-bezier(0.28, 0.11, 0.32, 1), transform 0.65s cubic-bezier(0.28, 0.11, 0.32, 1);
}
.footer-grid.reveal.in-view > * { opacity: 1; transform: none; }
.footer-grid.reveal.in-view > *:nth-child(1) { transition-delay: 0s; }
.footer-grid.reveal.in-view > *:nth-child(2) { transition-delay: 0.1s; }
.footer-grid.reveal.in-view > *:nth-child(3) { transition-delay: 0.2s; }
.footer-grid.reveal.in-view > *:nth-child(4) { transition-delay: 0.3s; }
.footer-grid ul li a { display: inline-block; transition: color var(--transition), transform 0.25s ease; }
.footer-grid ul li a:hover { transform: translateX(4px); }

/* ---- Checklists: items slide in left-to-right once their card reveals ---- */
.checklist li { opacity: 0; transform: translateX(-14px); }
.reveal.in-view .checklist li {
  animation: checklistIn 0.55s cubic-bezier(0.28, 0.11, 0.32, 1) forwards;
}
.reveal.in-view .checklist li:nth-child(1) { animation-delay: 0.12s; }
.reveal.in-view .checklist li:nth-child(2) { animation-delay: 0.26s; }
.reveal.in-view .checklist li:nth-child(3) { animation-delay: 0.4s; }
.reveal.in-view .checklist li:nth-child(4) { animation-delay: 0.54s; }
@keyframes checklistIn { to { opacity: 1; transform: translateX(0); } }

/* ---- Form fields: rise in one after another once their section reveals ---- */
.form-field { opacity: 0; transform: translateY(16px); }
.reveal.in-view .form-field {
  animation: formFieldIn 0.55s cubic-bezier(0.28, 0.11, 0.32, 1) forwards;
}
.reveal.in-view .form-field:nth-child(1) { animation-delay: 0.05s; }
.reveal.in-view .form-field:nth-child(2) { animation-delay: 0.12s; }
.reveal.in-view .form-field:nth-child(3) { animation-delay: 0.19s; }
.reveal.in-view .form-field:nth-child(4) { animation-delay: 0.26s; }
.reveal.in-view .form-field:nth-child(5) { animation-delay: 0.33s; }
.reveal.in-view .form-field:nth-child(6) { animation-delay: 0.4s; }
@keyframes formFieldIn { to { opacity: 1; transform: translateY(0); } }
.form-field input, .form-field select, .form-field textarea { transition: border-color var(--transition), box-shadow var(--transition), transform 0.2s ease; }


/* ---- Card icons: a small confident pop + tilt on hover, site-wide ---- */
.card-icon svg { transition: transform 0.4s cubic-bezier(0.28, 0.11, 0.32, 1); }
.card:hover .card-icon svg { transform: none; }
.service-outcome-line svg { transition: transform 0.3s ease, color 0.3s ease; }
.card:hover .service-outcome-line svg { transform: none; }

/* ---- Avatar rings (About > Team): gentle breathing ring + hover spin-in ---- */
.avatar-ring { transition: transform 0.4s cubic-bezier(0.28, 0.11, 0.32, 1); }
.card:hover .avatar-ring { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .hero-inner > *, .page-hero .hero-inner > *, .hero-visual { animation: none; opacity: 1; transform: none; filter: none; }
  .cta-banner.reveal h2, .cta-banner.reveal p, .cta-banner.reveal .btn,
  .footer-grid.reveal > *, .checklist li, .form-field {
    opacity: 1; transform: none; transition: none; animation: none;
  }
  .work-card.is-fading { opacity: 1; transform: none; }
  .filter-chip.chip-pop { animation: none; }
}

/* ==========================================================================
   Theme toggle

   A 32px circular icon button that sits beside search in the nav, matched to
   the search button's own metrics so the two read as a pair rather than as
   two separate ideas.

   It cycles Auto → Light → Dark. Auto is the default and the first stop,
   because a two-way switch has no way to say "go back to following my
   machine" — and someone whose laptop turns dark at sunset has already
   answered this question once.

   The icon is swapped by js/core/theme.js rather than by CSS, so the control
   reports the actual preference (Auto shows a half-filled disc) instead of
   just the resolved colour.
   ========================================================================== */
.theme-toggle {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 32px;
  height: 32px;
  padding: 0;
  border-radius: var(--radius-pill);
  cursor: pointer;
  color: var(--mist);
  background: transparent;
  border: 1px solid transparent;
  transition: color var(--transition), background-color var(--transition),
              border-color var(--transition);
}
.theme-toggle:hover,
.theme-toggle:focus-visible { color: var(--ink); background: var(--fill-subtle); }
.theme-toggle:active { background: var(--fill-hover); }
.theme-toggle:focus-visible { outline: 2px solid var(--accent-fill); outline-offset: 2px; }

.theme-toggle-icon { display: block; width: 18px; height: 18px; }
.theme-toggle-icon svg { width: 100%; height: 100%; }

/* The glyph turns over rather than cross-fading — a swap you can follow reads
   as one control changing state, where a fade reads as two icons. */
.theme-toggle-icon svg { animation: themeIconIn 320ms var(--ease-apple); }
@keyframes themeIconIn {
  0%   { opacity: 0; transform: rotate(-35deg) scale(0.82); }
  100% { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .theme-toggle-icon svg { animation: none; }
}

/* Auto's half-filled disc needs a touch more presence than the line icons,
   which read heavier at the same stroke weight. */
.theme-toggle[data-state="auto"] .theme-toggle-icon { opacity: 0.92; }

/* In the mobile shell the control moves into the "More" sheet as a labelled
   row, because a 32px unlabelled glyph in a phone header is a guess. */
.m-sheet-links .theme-toggle,
.m-sheet .theme-toggle {
  width: 100%;
  height: auto;
  justify-content: flex-start;
  gap: 14px;
  padding: 15px 16px;
  border-radius: var(--radius);
  /* Matches .m-sheet-links a exactly — the row is one of the list, not a
     control that wandered in from elsewhere. */
  background: var(--surface-canvas);
  border: 1px solid var(--line);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--text-body);
  letter-spacing: var(--tracking-body);
  min-height: 52px;
}
.m-sheet-links .theme-toggle .theme-toggle-icon,
.m-sheet .theme-toggle .theme-toggle-icon { width: 20px; height: 20px; color: var(--mist); }
.m-sheet-links .theme-toggle .theme-toggle-label,
.m-sheet .theme-toggle .theme-toggle-label { margin-left: auto; color: var(--mist); font-size: var(--text-body-sm); }


/* ==========================================================================
   Card titles promoted from h3 to h2 for a correct heading outline.
   The visual weight is unchanged — only the level in the document changed.
   ========================================================================== */
.card > .card-title,
.card-title {
  font-family: var(--font-display);
  font-size: var(--text-subheading);
  line-height: var(--leading-subheading);
  letter-spacing: var(--tracking-subheading);
  font-weight: var(--font-weight-semibold);
  color: var(--ink);
  margin: 0 0 10px;
}


/* ==========================================================================
   AUDIT FIXES — desktop & shared
   Everything below was added in response to the design + mobile audits. It is
   kept in one block so it can be read, moved into the files it belongs to, or
   reverted as a unit.
   ========================================================================== */

/* ---- Skip link ----------------------------------------------------------
   100+ interactive elements sit between the top of the page and the content
   on the homepage. Visually hidden until focused, then it lands on top of
   the sticky header rather than underneath it. */
.skip-to-content {
  position: fixed;
  top: 8px;
  left: 8px;
  z-index: 2147483001;          /* above the tour launcher, which is 2147483000 */
  padding: 12px 18px;
  border-radius: var(--radius);
  background: var(--accent-fill);
  color: var(--on-accent);
  font-family: var(--font-body);
  font-size: var(--text-body-sm);
  font-weight: var(--font-weight-semibold);
  text-decoration: none;
  transform: translateY(calc(-100% - 16px));
  transition: transform 160ms var(--ease-apple);
}
.skip-to-content:focus-visible {
  transform: none;
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* ---- Line breaking ------------------------------------------------------
   At 56px the difference between a balanced headline and a poured one is the
   difference between type that reads as set and type that reads as filled in.
   `balance` is capped at ~6 lines by the spec, which is why it goes on
   headings only; `pretty` is the cheap one for body copy and only fixes the
   last line, which is where the orphans were. */
h1, h2, h3, .hero-title, .section-head h2, .chapter-title {
  text-wrap: balance;
}
p, li, blockquote, figcaption, .lead, .card p {
  text-wrap: pretty;
}

/* ---- Non-text contrast (WCAG 1.4.11) ------------------------------------
   A form control's border is the only thing identifying it as a control, so
   it has to clear 3:1. --line is #d2d2d7, which is 1.51:1 on white. The
   system already ships --line-strong (#858585, 3.39:1) for exactly this and
   it simply was not being used here. Decorative rules keep --line. */
.form-field input,
.form-field select,
.form-field textarea,
.site-search-input {
  border-color: var(--line-strong);
}

/* Muted text on a filled surface was the one text pair that missed AA:
   #6e6e73 on --surface-pebble is 3.92:1. A shade darker clears it without
   introducing a fourth grey anywhere else. */
.surface-pebble .muted,
[class*="filled"] .muted,
.tier-btn .tier-sub,
.cart-item-row .ci-price { color: #5f5f65; }

/* ---- Form states --------------------------------------------------------
   Errors sit under the field they belong to. The colour is carried by an
   icon-free text line rather than by the border alone, so it does not rely
   on colour perception. */
.field-err {
  margin: 6px 0 0;
  font-size: var(--text-body-sm);
  line-height: 1.4;
  color: #b3261e;
  text-align: left;
}
.form-field input[aria-invalid="true"],
.form-field textarea[aria-invalid="true"] {
  border-color: #b3261e;
  box-shadow: 0 0 0 1px #b3261e;
}
.form-status {
  margin: 14px 0 0;
  font-size: var(--text-body-sm);
  line-height: 1.5;
  min-height: 1.2em;
  color: var(--mist);
}
.form-status.is-ok    { color: #0f7a3d; font-weight: var(--font-weight-semibold); }
.form-status.is-error { color: #b3261e; font-weight: var(--font-weight-semibold); }
.label-opt { color: var(--mist); font-weight: var(--font-weight-regular); }
.contact-link { color: inherit; text-decoration: underline; text-underline-offset: 3px; }

/* Direct contact card (contact.html) — one row per channel, icon chip on the
   left. The card centres its text elsewhere, so the list is a left-aligned
   block centred as a whole: icons line up in one column. */
.dc-list {
  list-style: none;
  margin: 16px auto 0;
  padding: 0;
  display: grid;
  gap: 10px;
  width: fit-content;
  max-width: 100%;
  text-align: left;
}
.dc-list li {
  display: grid;
  grid-template-columns: 34px auto;
  grid-template-rows: auto auto;
  column-gap: 12px;
  align-items: center;
}
.dc-ico {
  grid-row: 1 / span 2;
  width: 34px; height: 34px;
  border-radius: 10px;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--accent-fill, #0071e3) 10%, transparent);
  color: var(--accent-fill, #0071e3);
}
.dc-ico svg { width: 18px; height: 18px; }
.dc-label {
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mist);
  line-height: 1.2;
}
.dc-val {
  color: var(--ink);
  font-size: var(--text-body-sm, 0.95rem);
  line-height: 1.35;
  text-decoration: none;
  overflow-wrap: anywhere;
}
a.dc-val:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ---- Client marquee legibility -----------------------------------------
   --accent-soft (#2997ff) is 2.77:1 on the light canvas and style.css is
   explicit that it is "decorative only — never a control, never a word".
   The marquee was using it for words. Light gets --accent (5.11:1); dark
   keeps the soft blue, which is 6.96:1 against black and was always the
   value this effect was designed against. */
.client-marquee-led,
.client-marquee-track span { color: var(--accent); }
[data-theme="dark"] .client-marquee-led,
[data-theme="dark"] .client-marquee-track span { color: var(--accent-soft); }

/* ---- Buttons must never exceed their container --------------------------
   The pricing CTA was sized purely by its label with no cap, so on any phone
   at or below 390px it ran off the right edge — 30px off at 390, 62px at 320
   — inside a container that does not scroll. This is the general guard; the
   label was shortened as well. */
.btn {
  max-width: 100%;
  white-space: normal;
}

/* ---- Intrinsic dimensions need a height:auto companion -------------------
   Every <img> now carries width/height attributes so the browser can reserve
   the right box before the file decodes (CLS). Those attributes are
   presentational hints that set a DEFINITE height, which suppresses both
   `aspect-ratio` and any CSS that sizes the image by width alone — the demo
   thumbnails went from 65px to 900px tall the moment the attributes landed.

   `height: auto` hands sizing back to CSS while the attributes keep doing
   their real job, which is supplying the ratio. Deliberately a bare element
   selector: any component that genuinely wants a fixed height sets it with a
   class and wins on specificity without needing an exception here. */
img { height: auto; }


/* ==========================================================================
   BRAND LOCKUP — 2026 logo
   --------------------------------------------------------------------------
   Two real files rather than one inverted file. The previous system shipped a
   single Carbon silhouette and flipped it with `filter: invert()` in dark,
   which was the right call for a flat mark — but the dark artwork now carries
   a lavender halo that no filter can reproduce, so inverting would have thrown
   away half of the identity.

   Both PNGs are exported on an identical canvas with the artwork registered to
   the same pixel box, so swapping themes changes the image and moves nothing.
   THEME_BOOT sets data-theme before the stylesheets load, so the correct one is
   the only one ever painted — there is no flash and no layout shift.

   Sizing note: the canvas carries 30% padding around the artwork to hold the
   dark version's glow without clipping it. The ink is 62.5% of the canvas
   height, so a rendered height of 54px puts the wordmark at the same 34px it
   was before. Every height below is set on that basis.
   ========================================================================== */

.logo-img {
  display: block;
  width: auto;
  height: 100%;
  /* The lockups are already the right colour per theme — the legacy invert
     filter must not touch them. */
  filter: none;
  mix-blend-mode: normal;
}

/* Only one of the pair is ever displayed.
   Qualified with the element type on purpose: the older `.logo-mark img`
   rule sets `display: block` at (0,1,1), so a bare `.logo-img-dark` at
   (0,1,0) loses to it no matter where it sits in the file and BOTH lockups
   render. Matching its specificity and coming later is what makes the swap
   actually take. */
img.logo-img-dark { display: none; }
[data-theme="dark"] img.logo-img-light { display: none; }
[data-theme="dark"] img.logo-img-dark  { display: block; }

/* ---- Header ----
   NO `overflow: hidden` here, and the omission is load-bearing.

   .nav is `grid-template-columns: 1fr auto 1fr` with the logo in the first
   1fr track. A grid item will not normally shrink below its own content,
   because its automatic minimum size is its content size — but `overflow`
   set to anything other than `visible` collapses that minimum to zero. With
   it, the track crushed the lockup as the viewport narrowed: 149px wide at
   1280, 74px at 940, and completely gone by 870.

   It was originally added to crop the lockup's padded canvas, which was
   pointless — that padding is transparent, so there was never anything to
   crop. min-width pins the floor explicitly rather than relying on the
   automatic one, so a future overflow rule cannot reintroduce this. */
.logo-mark {
  height: 54px;                 /* = 34px of wordmark */
  min-width: max-content;
}
.logo-mark img { height: 54px; width: auto; filter: none; }
.logo-mark:hover img { opacity: 0.7; }

@media (max-width: 860px) {
  .logo-mark { height: 45px; }
  .logo-mark img { height: 45px; }
}

/* ---- Footer lockup on the inner pages ---- */
.footer-logo-mark { height: 48px; min-width: max-content; }
.footer-logo-mark img { height: 48px; width: auto; filter: none; }

/* ---- Homepage finale, bottom bar ----------------------------------------
   This slot used to be the word "NetrAI" set in HTML with the "AI" tinted
   blue — a second, lower-fidelity wordmark competing with the real one three
   inches above it, and the only place on the site where the brand was drawn
   in live text rather than shown as artwork. Replaced with the lockup. */
.finale-logo {
  display: inline-flex;
  align-items: center;
  height: 46px;
  min-width: max-content;
  flex-shrink: 0;
}
.finale-logo img { height: 46px; filter: none; }
.finale-logo:hover img { opacity: 0.75; }

@media (max-width: 700px) {
  .finale-logo { height: 42px; }
  .finale-logo img { height: 42px; }
  .footer-logo-mark, .footer-logo-mark img { height: 42px; }
}

/* ---- Narrow desktop: the header drops to the mark ------------------------
   Between the mobile shell's 860px cutoff and about 1000px, the three-column
   nav does not fit: logo + pill + actions measured 994px of content in a
   900px window, which pushed "Get Started" and the theme toggle off the right
   edge. The page did not scroll sideways — body clips it — so the controls
   were simply unreachable, which is worse than a visible overflow.

   That band was always too tight. It only became visible once the logo stopped
   collapsing: previously the 1fr track crushed the lockup to nothing and the
   nav "fitted" by eating its own logo.

   The wordmark is the part that can go. The lockup's glyph occupies a square
   window at the very left of the canvas — 352x352 of a 973x352 file, verified
   against the alpha channel — so cover-cropping to a 1:1 box yields exactly
   the mark, with its padding intact and no second image to download. */
@media (min-width: 861px) and (max-width: 1000px) {
  .logo-mark img {
    width: 54px;
    aspect-ratio: 1;
    object-fit: cover;
    object-position: left center;
  }
  .logo-mark { min-width: 54px; }

  /* Reclaim the rest from the gutters rather than from any one element. */
  .nav { column-gap: var(--spacing-20); padding-inline: clamp(16px, 2.4vw, 28px); }
  .nav-actions { gap: 8px; }

  /* At the very bottom of the band the pill is still the widest thing in the
     row — 539px of the 861 available, against a 54px logo and 217px of
     actions. Seven links each give up 3px a side, which is 42px back and
     enough to clear it. The type size is untouched: the labels stay at 14px,
     they just sit closer together. */
  .nav-links a:not(.btn) { padding-inline: 12px; }
  .nav-links { padding: 4px; }
}

/* ---- The nav CTA stays on one line --------------------------------------
   `.btn { white-space: normal }` was added to stop the pricing CTA running
   off the right edge on small phones, and it did — but it applies to every
   button, and in the header it let "Get Started" wrap to two lines and
   balloon the pill vertically at narrow desktop widths. The header has a
   fixed height and one short label; it wants the old behaviour back. */
.nav-cta .btn,
.nav-actions .btn { white-space: nowrap; }

/* ---- Gap above the footer ----------------------------------------------
   The last section's own bottom padding (up to 172px) was stacking with the
   footer's 96px top margin and 64px top padding — over 300px of empty band
   between the last content and the footer on every page. The footer now
   sits directly under the last section, and that section keeps only a
   modest bottom padding. Specificity is raised on purpose so the mobile
   stylesheets, which load later, do not reintroduce the margin. */
html body .site-footer,
html body .site-finale { margin-top: 0; }
html body main > section:last-child { padding-bottom: clamp(48px, 5vw, 80px); }
/* Phones: the mobile styles give tel/mailto/wa links a 44px tap height, which
   left the Direct contact rows unevenly spaced. Give every row that height. */
@media (max-width: 860px) {
  .dc-list { gap: 8px; }
  .dc-list li { min-height: 48px; }
  html body .dc-list a.dc-val { min-height: 0; padding: 0; display: inline; }
  /* ...and keep the big tap target: the link's hit area covers the whole
     48px row, icon and label included. */
  .dc-list li { position: relative; }
  .dc-list a.dc-val::after { content: ""; position: absolute; inset: 0; }
}
