/* ============================================================
   pepbits.com homepage — design system
   Ported from "Pepbits Landing v3": warm paper ground, lime charge,
   binary/"bits" motif. Single light identity (no theme presets).
   Type: Bricolage Grotesque (display + body) · IBM Plex Mono (labels)
         · Instrument Serif (italic accents)
   ============================================================ */

:root {
  /* base — warm paper */
  --bg:        #F5F2E8;
  --bg-2:      #EDE9DA;
  --surface:   #FBF9F1;
  --surface-2: #E7E2D0;
  /* Derived from --ink, so a theme sets one colour and the rules that
     lean on it at partial strength follow. */
  --line:      color-mix(in srgb, var(--ink) 14%, transparent);
  --line-soft: color-mix(in srgb, var(--ink) 9%, transparent);
  /* ink-on-paper tint, used wherever the dark build used a white wash */
  --tint:      color-mix(in srgb, var(--ink) 5%, transparent);
  --tint-2:    color-mix(in srgb, var(--ink) 9%, transparent);

  /* text */
  --ink:       #171B12;
  --ink-nav:   #3A4030;   /* header labels */
  --ink-soft:  #454B3B;   /* the light second line of the hero headline */
  --ink-2:     #5E6452;
  --ink-meta:  #6B7060;   /* instrumentation and corner readouts */
  --ink-3:     #8A8F7E;

  /* the charge */
  --lime-b:    #C6F52E;
  --lime-c:    #86CC00;
  --green-d:   #477E00;
  --green-m:   #5A9E00;
  --warm:      #C2410C;
  --warm-2:    #FF6A32;

  /* product accents — jewel tones tuned to read on paper */
  --indigo:    #4338CA;
  --cyan:      #0E7490;
  --violet:    #7C3AED;
  --blue:      #1D4FD8;
  --teal:      #0F766E;
  --magenta:   #BE185D;
  --lime:      #4D7C0F;
  --amber:     #B45309;

  --accent:    var(--lime-c);
  --accent-2:  var(--green-d);

  /* Signals — colour used to mean something rather than to decorate.
     The product pages lean on these, so the meaning follows a theme
     change instead of being written into the page. */
  --ok:        #047857;
  --pending:   #B45309;

  /* Panels lift off the ground with a tinted shadow rather than a black
     one, so a dark theme can set a light shadow colour and the same rules
     keep working. */
  --shadow:      #1E325A;
  --shadow-soft: 0 12px 34px color-mix(in srgb, var(--shadow) 12%, transparent);
  --shadow-lift: 0 30px 80px color-mix(in srgb, var(--shadow) 15%, transparent);

  /* A wash the colour of the card surface, so anything that used a
     hard-coded white overlay follows the theme onto a dark ground. */
  --wash:      color-mix(in srgb, var(--surface) 60%, transparent);
  --wash-2:    color-mix(in srgb, var(--surface) 85%, transparent);
  --wash-3:    color-mix(in srgb, var(--surface) 95%, transparent);

  /* The readable label colour on a filled accent button. Not derivable
     from the ground: on this palette the fill is lime and the label has to
     be ink, while a dark theme with a bright fill wants its own near-black
     ground. Each theme sets it. */
  --on-accent: #171B12;

  /* the dark slab: marquee band, terminal, build visual */
  --slab:       #14180C;
  --on-slab:    #F2F0E4;
  --on-slab-2:  #D7D3C2;  /* terminal body */
  --on-slab-3:  #7E8470;  /* terminal comments */
  --dot-amber:  #E8B931;  /* the middle traffic-light dot */

  --maxw: 1240px;
  --radius: 14px;
  --radius-sm: 9px;

  --ff-display: "Bricolage Grotesque", system-ui, sans-serif;
  --ff-body: "Bricolage Grotesque", system-ui, sans-serif;
  --ff-mono: "IBM Plex Mono", ui-monospace, monospace;
  --ff-serif: "Instrument Serif", Georgia, serif;
}

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

html { scroll-behavior: smooth; }

body {
  font-family: var(--ff-body);
  background: var(--bg);
  color: var(--ink);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

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

/* persistent dotted "bits" field behind everything */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  background-image: radial-gradient(circle at 1px 1px, color-mix(in srgb, var(--ink) 13%, transparent) 1px, transparent 0);
  background-size: 26px 26px;
  mask-image: radial-gradient(ellipse 120% 80% at 50% 0%, black 30%, transparent 80%);
  pointer-events: none;
  z-index: 0;
}

a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }

.wrap { width: 100%; max-width: none; margin-inline: auto; padding-inline: 40px; }
/* Opt out of container-fluid. .wrap runs edge to edge, which stretches
   cards, a timeline and the footer's link columns across the whole of a
   wide screen; anything carrying this holds to --maxw and centres instead.
   Full-bleed bands (the hero, the marquee, the section grounds) are
   unaffected — it is only the content inside them that is held. */
.wrap.wrap-hold { max-width: var(--maxw); }

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

/* ---------- landing motion vocabulary ---------- */
@keyframes blink    { 0%, 54% { opacity: 1; } 55%, 100% { opacity: 0; } }
@keyframes cuedrop  { 0% { transform: translateY(-14px); opacity: 0; } 35% { opacity: 1; } 100% { transform: translateY(22px); opacity: 0; } }
@keyframes rise     { from { opacity: 0; transform: translateY(30px); filter: blur(10px); } to { opacity: 1; transform: none; filter: none; } }
@keyframes glowp    { 0%, 100% { text-shadow: 0 0 10px color-mix(in srgb, var(--lime-c) 20%, transparent); } 50% { text-shadow: 0 0 36px color-mix(in srgb, var(--lime-c) 65%, transparent); } }
@keyframes bob      { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }
@keyframes ringp    { 0% { box-shadow: 0 10px 30px color-mix(in srgb, var(--lime-c) 25%, transparent), 0 0 0 0 color-mix(in srgb, var(--lime-c) 50%, transparent); } 70% { box-shadow: 0 10px 30px color-mix(in srgb, var(--lime-c) 25%, transparent), 0 0 0 18px color-mix(in srgb, var(--lime-c) 0%, transparent); } 100% { box-shadow: 0 10px 30px color-mix(in srgb, var(--lime-c) 25%, transparent), 0 0 0 0 color-mix(in srgb, var(--lime-c) 0%, transparent); } }
@keyframes dotblink { 0%, 60% { opacity: 1; } 61%, 100% { opacity: 0.15; } }
@keyframes beat     { 0%, 30%, 100% { transform: scale(1); } 8% { transform: scale(1.08); } 16% { transform: scale(0.98); } 24% { transform: scale(1.05); } }

/* ---------- shared bits ---------- */
.eyebrow {
  font-family: var(--ff-mono);
  font-size: 12px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--accent-2);
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.eyebrow::before {
  content: "";
  width: 7px; height: 7px;
  background: var(--accent);
  box-shadow: 10px 0 0 var(--accent-2), 20px 0 0 var(--ink-3);
}

h1, h2, h3 { font-family: var(--ff-display); font-weight: 800; letter-spacing: -0.03em; line-height: 1.04; }

/* italic serif accent, straight from the landing page */
.ital { font-family: var(--ff-serif); font-style: italic; font-weight: 400; letter-spacing: -0.015em; }

.section-head { max-width: 720px; margin-bottom: 56px; }
.section-head h2 { font-size: clamp(30px, 4.2vw, 52px); margin: 18px 0 16px; }
.section-head p { color: var(--ink-2); font-size: clamp(16px, 1.5vw, 19px); max-width: 600px; }

/* buttons — landing uses squared-off mono keys, not pills */
.btn {
  font-family: var(--ff-mono);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 16px 26px;
  border-radius: 8px;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  cursor: pointer;
  border: 1.5px solid transparent;
  transition: transform .25s ease, background .25s ease, border-color .25s ease, box-shadow .25s ease, color .25s ease;
  white-space: nowrap;
}
.btn:hover { transform: translateY(-2px); }
.btn-primary {
  background: var(--lime-b);
  /* not var(--ink): on a dark theme the ink is light and the fill is still
     bright, so the label has to be the theme's own on-fill colour */
  color: var(--on-accent);
  box-shadow: 0 10px 30px color-mix(in srgb, var(--lime-c) 30%, transparent);
}
.btn-primary:hover { background: var(--ink); color: var(--bg); box-shadow: 0 14px 38px color-mix(in srgb, var(--ink) 30%, transparent); }
.btn-ghost {
  background: transparent;
  border-color: color-mix(in srgb, var(--ink) 40%, transparent);
  color: var(--ink);
}
.btn-ghost:hover { border-color: var(--ink); background: var(--tint); }
.btn .arr { transition: transform .2s ease; }
.btn:hover .arr { transform: translateX(3px); }

/* ============================================================
   NAV
   ============================================================ */
.nav {
  position: sticky; top: 0; z-index: 50;
  backdrop-filter: blur(14px);
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  border-bottom: 1px solid var(--line);
}
/* Animated accent line sweeping along the header's bottom edge. */
.nav::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: linear-gradient(90deg, transparent 0%, var(--accent) 25%, var(--accent-2) 50%, var(--accent) 75%, transparent 100%);
  background-size: 200% 100%;
  animation: navsweep 4.5s linear infinite;
}
@keyframes navsweep { from { background-position: 200% 0; } to { background-position: -200% 0; } }
.nav-inner { display: flex; align-items: center; justify-content: space-between; height: 70px; }

/* wordmark: "pep" heavy + "bits" mono green + blinking caret */
.brand { display: inline-flex; align-items: baseline; gap: 1px; color: var(--ink); }

/* The mark sits ahead of the wordmark. Sized in em against the wordmark's
   own type rather than in pixels, so it tracks the brand at every
   breakpoint instead of needing its own media query.

   align-self:center because the row is baseline-aligned for the two text
   halves; a graphic has no baseline worth aligning to and would hang off
   the bottom of the line box.

   The gradient is the brand's own and deliberately does not follow the
   theme: it is the one fixed thing on a site where a visitor can repaint
   everything else. */
/* The landing page's copy. Sized against the viewport so it holds its
   presence on a phone without crowding the headline underneath, and given
   the same entrance the rest of the hero uses so it arrives with the page
   rather than appearing after it.

   pointer-events stays off with the rest of .hero-inner: the canvas behind
   the hero is interactive, and a graphic that swallowed the pointer would
   leave a dead patch in the middle of it. */
/* ---------- the mark's plate ----------
   A tile behind the logo in all three places it appears.

   Themed rather than the white rect the export shipped with: that would sit
   as a white card on six of the ten palettes. Surface and line are the same
   tokens the cards use, so the plate belongs to whatever theme is active
   while the mark's own gradient stays fixed.

   box-sizing:border-box so the declared height stays the height. Each
   caller sets its own padding — the mark is 21px in the header and 78px in
   the hero, and one padding cannot serve both. */
.brand-mark {
  box-sizing: border-box;
  /* The plate picks up the mark's own hues — cyan through violet to pink,
     on the same diagonal the logo's gradient runs.

     Layered over the theme's surface rather than replacing it, and each
     stop kept low so the ground still reads as the active palette: a plate
     at full strength competes with the strokes sitting on it, and the mark
     is fine line work with nothing to spare.

     color-mix against surface rather than transparent, so the tint blends
     with the theme instead of showing the page through it. */
  background:
    linear-gradient(135deg,
      color-mix(in srgb, #1CC2E6 26%, var(--surface)) 0%,
      color-mix(in srgb, #2A8CFF 22%, var(--surface)) 28%,
      color-mix(in srgb, #9A5CFF 24%, var(--surface)) 55%,
      color-mix(in srgb, #F94FA3 24%, var(--surface)) 80%,
      color-mix(in srgb, #FF7A48 22%, var(--surface)) 100%);
  border: 1px solid color-mix(in srgb, #9A5CFF 30%, var(--line));
}

/* The landing page's lockup: mark and wordmark on one line, centred.

   The whole group animates rather than its two halves separately — a mark
   and its own name arriving at different moments reads as a loading fault,
   not as a flourish. */
.hero-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(10px, 1.4vw, 18px);
  margin-bottom: clamp(20px, 3vw, 34px);
  animation: rise .9s cubic-bezier(.2, .7, .2, 1) .06s both;
}
.hero-inner .brand-mark {
  display: block;
  height: clamp(64px, 10vw, 104px);
  width: auto;
  flex: 0 0 auto;
  padding: clamp(10px, 1.5vw, 15px) clamp(13px, 2vw, 20px);
  border-radius: clamp(14px, 2vw, 22px);
}
/* Same two-part treatment as the header — display face for "pep", mono for
   "bits" — at the size this page can give it. */
.hero-word { display: inline-flex; align-items: baseline; letter-spacing: -0.02em; }
.hero-word .bp {
  font-family: var(--ff-display); font-weight: 800;
  font-size: clamp(38px, 6vw, 62px); color: var(--ink);
}
.hero-word .bb {
  font-family: var(--ff-mono); font-weight: 600;
  font-size: clamp(34px, 5.4vw, 56px); color: var(--accent-2);
}
@media (prefers-reduced-motion: reduce) {
  .hero-brand { animation: none; opacity: 1; transform: none; filter: none; }
}

/* The footer's copy of the mark. Larger than the header's and set on its
   own line, because here it is the block's opening rather than a companion
   to a wordmark sitting beside it. */
/* The footer's lockup. Smaller than the hero's — down here it opens a
   column of copy rather than a page — and left-aligned with the paragraph
   beneath it rather than centred. */
.foot-brand {
  display: flex;
  align-items: center;
  gap: 11px;
  margin-bottom: 20px;
}
.foot-say .brand-mark {
  display: block;
  height: 52px;
  width: auto;
  flex: 0 0 auto;
  padding: 8px 11px;
  border-radius: 12px;
}
.foot-word { display: inline-flex; align-items: baseline; letter-spacing: -0.02em; }
.foot-word .bp { font-family: var(--ff-display); font-weight: 800; font-size: 30px; color: var(--ink); }
.foot-word .bb { font-family: var(--ff-mono);    font-weight: 600; font-size: 27px; color: var(--accent-2); }

.brand .brand-mark {
  align-self: center;
  height: 1.9em;
  width: auto;
  margin-right: 10px;
  flex: 0 0 auto;
  padding: 5px 7px;
  border-radius: 8px;
}
.brand .bp { font-family: var(--ff-display); font-weight: 800; font-size: 21px; letter-spacing: -0.02em; }
.brand .bb { font-family: var(--ff-mono); font-weight: 600; font-size: 19px; color: var(--accent-2); }
.brand .caret { display: inline-block; width: 0.5em; height: 2px; background: var(--accent); margin-left: 3px; animation: blink 1.1s steps(1) infinite; }

/* ============================================================
   MOTION — set in the admin console, stamped on <html> as data-mo
   ============================================================
   Every variant ships in this stylesheet and is selected by a token, so
   changing the setting is a different attribute on one element rather than
   a regenerated stylesheet. The file stays cacheable and an editor's choice
   applies on the next request.

   Tokens are matched with ~=, which matches whole words only, so "accent"
   can never be found inside "wm-typewriter".

   Speed scales every duration and delay below. It is a plain multiplier so
   the relationships between staggered items survive being sped up. */
:root { --mo-scale: 1; }
html[data-mo~="sp-calm"]   { --mo-scale: 1.4; }
html[data-mo~="sp-lively"] { --mo-scale: 0.7; }

/* ---------- wordmark: shared ----------
   line-height is pinned for every variant, not just the typewriter: hiding
   overflow moves an inline-block's baseline to its bottom margin edge, and
   without this the word sits 4.7px lower than the rest of the header. */
.brand i { display: inline-block; font-style: normal; line-height: 1; }

/* ---------- wordmark: typewriter ----------
   The header already carries a blinking caret and sets "bits" in the mono
   face, so it reads as a prompt; this makes it behave like one.

   Letters animate max-width from zero rather than opacity, because a
   transparent letter still occupies its space and the caret would sit at the
   end of the finished word from the first frame, ahead of the text it is
   meant to be trailing. Collapsing the box lets the caret walk with the
   typing. max-width rather than width so it clamps to each glyph's natural
   size and nothing has to know how wide a character is.

   The keyframe pairs sit a hair apart so each character snaps in; easing
   reads as a fade, and a terminal does not fade. */
html[data-mo~="wm-typewriter"] .brand i {
  overflow: hidden;
  max-width: 0;
  opacity: 0;
  animation: btype calc(14s * var(--mo-scale)) linear infinite;
}
@keyframes btype {
  0%,   1.9%  { max-width: 0;     opacity: 0; }
  2%,  80%    { max-width: 1.4em; opacity: 1; }
  80.1%, 100% { max-width: 0;     opacity: 0; }
}
html[data-mo~="wm-typewriter"] .brand .bp i:nth-child(1) { animation-delay: calc(0.00s * var(--mo-scale)); }
html[data-mo~="wm-typewriter"] .brand .bp i:nth-child(2) { animation-delay: calc(0.13s * var(--mo-scale)); }
html[data-mo~="wm-typewriter"] .brand .bp i:nth-child(3) { animation-delay: calc(0.26s * var(--mo-scale)); }
html[data-mo~="wm-typewriter"] .brand .bb i:nth-child(1) { animation-delay: calc(0.39s * var(--mo-scale)); }
html[data-mo~="wm-typewriter"] .brand .bb i:nth-child(2) { animation-delay: calc(0.52s * var(--mo-scale)); }
html[data-mo~="wm-typewriter"] .brand .bb i:nth-child(3) { animation-delay: calc(0.65s * var(--mo-scale)); }
html[data-mo~="wm-typewriter"] .brand .bb i:nth-child(4) { animation-delay: calc(0.78s * var(--mo-scale)); }
/* Hovering holds the word complete: someone reaching for the logo should
   get a logo, not a half-typed word. */
html[data-mo~="wm-typewriter"] .brand:hover i {
  animation-play-state: paused; max-width: 1.4em; opacity: 1;
}

/* ---------- wordmark: accent wave ----------
   Lifts and glows but never sets `color`, so each theme keeps its own ink
   for "pep" and accent for "bits". Per-letter because a wave that travels
   needs each glyph on its own clock. */
html[data-mo~="wm-wave"] .brand i {
  animation: brandwave calc(7s * var(--mo-scale)) ease-in-out infinite;
}
@keyframes brandwave {
  0%, 66%, 100% { transform: translateY(0);    text-shadow: none; }
  33%           { transform: translateY(-3px);
                  text-shadow: 0 0 14px color-mix(in srgb, var(--accent) 55%, transparent); }
}
html[data-mo~="wm-wave"] .brand .bp i:nth-child(1) { animation-delay: calc(0.00s * var(--mo-scale)); }
html[data-mo~="wm-wave"] .brand .bp i:nth-child(2) { animation-delay: calc(0.07s * var(--mo-scale)); }
html[data-mo~="wm-wave"] .brand .bp i:nth-child(3) { animation-delay: calc(0.14s * var(--mo-scale)); }
html[data-mo~="wm-wave"] .brand .bb i:nth-child(1) { animation-delay: calc(0.21s * var(--mo-scale)); }
html[data-mo~="wm-wave"] .brand .bb i:nth-child(2) { animation-delay: calc(0.28s * var(--mo-scale)); }
html[data-mo~="wm-wave"] .brand .bb i:nth-child(3) { animation-delay: calc(0.35s * var(--mo-scale)); }
html[data-mo~="wm-wave"] .brand .bb i:nth-child(4) { animation-delay: calc(0.42s * var(--mo-scale)); }

/* ---------- wordmark: gradient sweep ----------
   The nav labels' technique applied to the wordmark. Applied to each half
   separately so "pep" keeps ink and "bits" keeps accent-2 as their base —
   one gradient across the whole word would flatten that distinction.

   Guarded, because without background-clip the transparent fill leaves the
   letters invisible rather than un-animated. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  html[data-mo~="wm-sweep"] .brand .bp,
  html[data-mo~="wm-sweep"] .brand .bb {
    background-size: 220% 100%;
    background-repeat: no-repeat;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
    animation: brandsweep calc(6s * var(--mo-scale)) linear infinite;
  }
  html[data-mo~="wm-sweep"] .brand .bp {
    background-image: linear-gradient(100deg,
      var(--ink) 0%, var(--ink) 40%, var(--accent) 50%, var(--ink) 60%, var(--ink) 100%);
  }
  html[data-mo~="wm-sweep"] .brand .bb {
    background-image: linear-gradient(100deg,
      var(--accent-2) 0%, var(--accent-2) 40%, var(--accent) 50%, var(--accent-2) 60%, var(--accent-2) 100%);
    animation-delay: calc(-0.4s * var(--mo-scale));
  }
}
/* Same range discipline as the nav labels: outside 0..100% the 220%-wide
   image slides clear of the box and leaves part of the text uncovered,
   which — with a transparent fill — means invisible. */
@keyframes brandsweep { from { background-position: 100% 0; } to { background-position: 0% 0; } }

/* wm-still adds no rule at all: the shared .brand i above is the whole of it. */

/* ---------- the switches ----------
   Each asks for the absence of a token rather than comparing to "off", so a
   setting that is off contributes nothing to the attribute. */

/* The accent line keeps its colour and stops travelling, rather than
   disappearing — the header still needs its bottom edge. */
html:not([data-mo~="accent"]) .nav::after { animation: none; }

/* The shimmer has to put the solid colour back, not just stop: the labels
   are painted by a gradient through transparent text, so removing the
   animation alone would leave them mid-sweep forever. */
html:not([data-mo~="shimmer"]) .nav-links a,
html:not([data-mo~="shimmer"]) .nav-links a:not(.on) {
  animation-name: rise;
  background-image: none;
  color: var(--ink-nav);
  -webkit-text-fill-color: var(--ink-nav);
}
html:not([data-mo~="shimmer"]) .nav-links a.on {
  color: var(--ink); -webkit-text-fill-color: var(--ink);
}

/* The scripts also stop drawing when this is off — see the head script —
   so this is belt and braces for a page that renders before they run. */
html:not([data-mo~="canvas"]) canvas { display: none; }

/* Reveals are gated in JS, which simply never adds body.anim. This covers
   the window before the script runs, and any page that sets .anim itself. */
html:not([data-mo~="reveals"]) body.anim .reveal {
  opacity: 1; transform: none; filter: none; transition: none;
}

.nav-links { display: flex; align-items: center; gap: clamp(16px, 2.6vw, 34px); }

/* Set in the display face rather than small mono caps: more character, and it
   pairs with the headline. Each item carries an underline that wipes in from
   the left on hover, and the row lands in a stagger on load. */
.nav-links a {
  position: relative;
  font-family: var(--ff-display);
  font-size: 15px; font-weight: 600; letter-spacing: -0.01em;
  color: var(--ink-nav);
  padding: 4px 1px 6px;
  transition: color .22s ease, transform .22s cubic-bezier(.2,.7,.2,1);
}
.nav-links a::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--accent);
  transform: scaleX(0); transform-origin: right;
  transition: transform .32s cubic-bezier(.2,.7,.2,1);
}
.nav-links a:hover { color: var(--ink); transform: translateY(-1px); }
.nav-links a:hover::after { transform: scaleX(1); transform-origin: left; }

/* current page marker — set by the activePage argument on the nav fragment */
.nav-links a.on { color: var(--ink); }
.nav-links a.on::after { transform: scaleX(1); }

/* entrance: the row assembles left to right under the brand, then each item
   keeps a slow lime shimmer running across its letters so the nav is never
   static. Both animations are listed together, so the per-item delays below
   carry two values: one for the entrance, one to put the shimmer out of phase. */
/* The range matters. The image is 220% of the label, and a percentage
   position aligns that point of the image with the same point of the box,
   so the offset is P x (W - 2.2W) = -1.2PW. Outside 0%..100% the image
   slides clear of the box and leaves part of it uncovered — and since the
   text is painted transparent and filled by this gradient, uncovered means
   invisible. The old 160%..-60% range hid up to 72% of every label for
   most of the cycle. Within 0..100% the box is always fully covered and
   the bright band still sweeps the whole way across. */
@keyframes navshimmer { from { background-position: 100% 0; } to { background-position: 0% 0; } }

.nav-links a { animation: rise .6s cubic-bezier(.2,.7,.2,1) both; }
.nav-links a:nth-child(1) { animation-delay: .30s; }
.nav-links a:nth-child(2) { animation-delay: .36s; }
.nav-links a:nth-child(3) { animation-delay: .42s; }
.nav-links a:nth-child(4) { animation-delay: .48s; }
.nav-links a:nth-child(5) { animation-delay: .54s; }
.nav-links a:nth-child(6) { animation-delay: .60s; }

/* Guarded: without background-clip:text the transparent fill would leave the
   labels invisible, so browsers lacking it keep the plain colour above. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .nav-links a:not(.on) {
    background-image: linear-gradient(100deg,
      var(--ink-nav) 0%, var(--ink-nav) 38%,
      var(--lime-c) 48%, var(--green-m) 52%,
      var(--ink-nav) 62%, var(--ink-nav) 100%);
    background-size: 220% 100%;
    background-repeat: no-repeat;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
    animation: rise .6s cubic-bezier(.2,.7,.2,1) both,
               navshimmer 7s linear infinite;
  }
  /* hover drops the gradient so the colour change still reads */
  .nav-links a:not(.on):hover {
    background-image: none;
    color: var(--ink);
    -webkit-text-fill-color: var(--ink);
  }
  .nav-links a:nth-child(1):not(.on) { animation-delay: .30s, -0.0s; }
  .nav-links a:nth-child(2):not(.on) { animation-delay: .36s, -1.2s; }
  .nav-links a:nth-child(3):not(.on) { animation-delay: .42s, -2.4s; }
  .nav-links a:nth-child(4):not(.on) { animation-delay: .48s, -3.6s; }
  .nav-links a:nth-child(5):not(.on) { animation-delay: .54s, -4.8s; }
  .nav-links a:nth-child(6):not(.on) { animation-delay: .60s, -6.0s; }
}
/* holds the hamburger only; empty-width on desktop, where it is hidden */
.nav-cta { display: flex; align-items: center; }

/* hamburger menu button (mobile only) */
.menu-btn {
  display: none; width: 44px; height: 44px; flex: none;
  align-items: center; justify-content: center; cursor: pointer;
  background: transparent; border: 1.5px solid color-mix(in srgb, var(--ink) 35%, transparent); border-radius: 7px;
  transition: border-color .2s ease, background .2s ease;
}
.menu-btn:hover { border-color: var(--accent-2); }
.menu-btn .bars { display: grid; gap: 4px; width: 18px; }
.menu-btn .bars i { height: 2px; width: 100%; background: var(--ink); border-radius: 2px; transition: transform .25s ease, opacity .2s ease; }
.menu-btn .bars i:nth-child(2) { background: var(--accent); }
.nav.open .menu-btn .bars i:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav.open .menu-btn .bars i:nth-child(2) { opacity: 0; }
.nav.open .menu-btn .bars i:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* mobile dropdown panel */
.mobile-menu {
  display: none; flex-direction: column; gap: 4px;
  padding: 10px 20px 22px; border-bottom: 1px solid var(--line-soft);
  background: color-mix(in srgb, var(--bg) 97%, transparent); backdrop-filter: blur(10px);
}
.mobile-menu a:not(.btn) { padding: 14px 6px; font-size: 19px; color: var(--ink); border-bottom: 1px solid var(--line-soft); font-family: var(--ff-display); font-weight: 700; letter-spacing: -0.02em; transition: color .2s ease, padding-left .2s ease; }
.mobile-menu a:not(.btn):hover { color: var(--accent-2); padding-left: 10px; }
.mobile-menu a:not(.btn):active { color: var(--accent-2); }
.nav.open .mobile-menu { display: flex; animation: menudrop .22s ease; }
@keyframes menudrop { from { opacity: 0; transform: translateY(-8px); } }

/* ============================================================
   HERO — interactive bit field
   ============================================================ */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
  cursor: crosshair;
  user-select: none; -webkit-user-select: none;
  touch-action: pan-y;
}
/* the particle canvas fills the hero; hero-bits.js fades it in */
.hero-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; opacity: 0; transition: opacity 1.4s ease; }
/* paper wash so the headline stays legible over the field */
.hero-wash {
  position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse 60% 52% at 50% 46%, color-mix(in srgb, var(--bg) 90%, transparent) 0%, color-mix(in srgb, var(--bg) 50%, transparent) 46%, color-mix(in srgb, var(--bg) 0%, transparent) 76%);
}
/* min-width:0 because this is a flex item inside .hero, where the default
   min-width:auto refuses to shrink below the content's own minimum. The
   hero's primary button carries a long label and .btn is white-space:nowrap,
   which put that floor at 428px — so on a 390px screen the hero sat 19px
   over each edge, and .hero{overflow-x:hidden} clipped it rather than
   scrolling, which is why a scrollWidth check never saw it. */
.hero-inner { position: relative; z-index: 2; text-align: center; padding: 120px clamp(20px, 5vw, 48px) 110px; max-width: 1150px; min-width: 0; pointer-events: none; }

.hero-binary {
  margin: 0; font-family: var(--ff-mono);
  font-size: clamp(10px, 1.3vw, 13px); letter-spacing: 0.22em;
  color: var(--ink-meta); text-transform: uppercase;
  animation: rise .8s cubic-bezier(.2, .7, .2, 1) .05s both;
}
.hero-binary .eq { color: var(--accent-2); }

.hero .hero-display { margin: 22px 0 18px; font-size: clamp(54px, 9.5vw, 136px); line-height: 0.93; font-weight: 800; letter-spacing: -0.04em; text-wrap: balance; }
.hero .hero-display .l1 { display: inline-block; animation: rise .9s cubic-bezier(.2, .7, .2, 1) .15s both; }
.hero .hero-display .l2 { display: inline-block; font-weight: 300; color: var(--ink-soft); animation: rise .9s cubic-bezier(.2, .7, .2, 1) .32s both; }
/* the word that carries the identity: serif italic, glowing, beating */
.hero .hero-display .pulse {
  display: inline-block; font-family: var(--ff-serif); font-style: italic; font-weight: 400;
  color: var(--green-m); letter-spacing: -0.015em; padding-right: 0.05em; transform-origin: 50% 72%;
  animation: rise .9s cubic-bezier(.2, .7, .2, 1) .46s both,
             glowp 2.6s ease-in-out 1.8s infinite,
             beat 2.6s ease-in-out 1.8s infinite;
}
.hero .hero-display .caret-lg { display: inline-block; width: 0.1em; height: 0.72em; background: var(--accent); margin-left: 0.08em; transform: translateY(0.08em); animation: blink 1.1s steps(1) infinite; }

/* The descriptive heading. Subordinate to the brand line in size but the
   page's actual H1 — it names the subject in words a search engine and a
   reader can both use. */
.hero .hero-h1 {
  margin: 0 auto 22px;
  max-width: 780px;
  font-family: var(--ff-display);
  font-size: clamp(20px, 2.4vw, 30px);
  font-weight: 600;
  line-height: 1.22;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-wrap: balance;
  animation: rise .9s cubic-bezier(.2, .7, .2, 1) .52s both;
}
.hero p.lead a {
  color: var(--accent-2);
  border-bottom: 1px solid color-mix(in srgb, var(--accent-2) 45%, transparent);
}
.hero p.lead a:hover { color: var(--ink); border-color: var(--ink); }

.hero p.lead { margin: 0 auto; max-width: 660px; font-size: clamp(16px, 1.7vw, 19px); line-height: 1.65; color: var(--ink-2); text-wrap: pretty; animation: rise .9s cubic-bezier(.2, .7, .2, 1) .58s both; }
.hero p.lead .ital { color: var(--ink); }
.hero-actions { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; margin-top: 38px; pointer-events: auto; animation: rise .9s cubic-bezier(.2, .7, .2, 1) .72s both; }

/* corner instrumentation */
.hero-meta {
  position: absolute; bottom: 22px; z-index: 2; pointer-events: none;
  display: flex; align-items: center; gap: 8px;
  font-family: var(--ff-mono); font-size: 11px; letter-spacing: 0.14em;
  color: var(--ink-meta); text-transform: uppercase;
  animation: rise .8s cubic-bezier(.2, .7, .2, 1) .9s both;
}
.hero-meta.left { left: clamp(20px, 4vw, 48px); }
.hero-meta.right { right: clamp(20px, 4vw, 48px); }
.hero-meta .live { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); animation: dotblink 1.4s steps(1) infinite; }
.hero-meta .count { color: var(--accent-2); font-weight: 600; }

.hero-cue { position: absolute; left: 50%; bottom: 18px; transform: translateX(-50%); z-index: 2; pointer-events: none; display: flex; flex-direction: column; align-items: center; gap: 7px; animation: rise .8s cubic-bezier(.2, .7, .2, 1) 1s both; }
.hero-cue span.lbl { font-family: var(--ff-mono); font-size: 10px; letter-spacing: 0.3em; color: var(--ink-meta); text-transform: uppercase; }
.hero-cue .rail { display: block; width: 1px; height: 30px; background: color-mix(in srgb, var(--ink) 20%, transparent); overflow: hidden; position: relative; }
.hero-cue .rail i { position: absolute; left: 0; top: 0; width: 1px; height: 10px; background: var(--accent-2); animation: cuedrop 1.7s ease-in-out infinite; }

/* ============================================================
   PRODUCTS
   ============================================================ */
.products { padding: clamp(76px, 10vw, 150px) 0 100px; }
.prod-grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: 20px; }
.card {
  position: relative;
  background: var(--surface);
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
  padding: 28px;
  overflow: hidden;
  transition: transform .25s ease, border-color .25s ease, box-shadow .3s ease;
  --c: var(--indigo);
}
.card::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(420px 200px at var(--mx, 80%) -10%, var(--c), transparent 70%);
  opacity: 0.08; transition: opacity .3s ease; pointer-events: none;
}
.card:hover { transform: translateY(-5px); border-color: var(--c); box-shadow: 0 24px 50px -28px color-mix(in srgb, var(--ink) 45%, transparent); }
.card:hover::before { opacity: 0.16; }

.prod-icon {
  width: 46px; height: 46px; border-radius: 12px;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--c) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--c) 38%, transparent);
  margin-bottom: 20px;
}
.prod-icon svg { width: 24px; height: 24px; stroke: var(--c); fill: none; stroke-width: 1.7; }
.card .tag { font-family: var(--ff-mono); font-size: 11.5px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--c); }
.card h3 { font-size: 25px; margin: 8px 0 10px; }
.card p { color: var(--ink-2); font-size: 15px; }
.card .feats { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 18px; }
.card .feats b { font-family: var(--ff-mono); font-weight: 400; font-size: 11.5px; color: var(--ink-2); background: var(--tint); border: 1px solid var(--line-soft); padding: 4px 9px; border-radius: 6px; }
.card .status { position: absolute; top: 20px; right: 20px; font-family: var(--ff-mono); font-size: 10.5px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); display: flex; align-items: center; gap: 6px; }
.card .status::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--c); box-shadow: 0 0 8px var(--c); }

/* sizing */
.span-6 { grid-column: span 6; }
.span-4 { grid-column: span 4; }
.span-12 { grid-column: span 12; }

/* feature card (large) */
.card.feature { display: grid; grid-template-columns: 1.1fr 1fr; gap: 30px; align-items: center; padding: 36px; }
.card.feature .feature-art {
  align-self: stretch; min-height: 240px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); position: relative; overflow: hidden;
  background:
    repeating-linear-gradient(135deg, color-mix(in srgb, var(--ink) 3.5%, transparent) 0 10px, transparent 10px 20px),
    linear-gradient(180deg, var(--bg-2), var(--bg));
  display: grid; place-items: center;
}
.card.feature .feature-art .ph { font-family: var(--ff-mono); font-size: 12px; color: var(--ink-3); letter-spacing: 0.08em; }
.card.feature h3 { font-size: 30px; }

/* The feature visual only shows on the (rotating) full-width card. */
.card:not(.feature) .feature-art { display: none; }
/* A product's first image fills the feature visual when present. */
.card.feature .feature-art img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* Soft fade when a new product is promoted to the feature slot. */
.card.feature.just-featured { animation: featurePop .55s ease both; }
@keyframes featurePop { from { opacity: .25; transform: scale(.985); } to { opacity: 1; transform: none; } }

/* Modal media gallery (images + videos, multiple per product). */
.gallery { display: grid; gap: 12px; }
.g-main { position: relative; border-radius: var(--radius-sm); overflow: hidden; border: 1px solid var(--line); background: var(--bg-2); aspect-ratio: 16 / 10; }
.g-main-media { width: 100%; height: 100%; display: block; background-size: cover; background-position: center; }
.g-thumbs { display: flex; flex-wrap: wrap; gap: 8px; }
.g-thumb { width: 66px; height: 46px; padding: 0; border-radius: 8px; overflow: hidden; border: 1px solid var(--line); background: var(--bg-2); cursor: pointer; display: grid; place-items: center; }
.g-thumb .g-thumb-img { display: block; width: 100%; height: 100%; background-size: cover; background-position: center; }
.g-thumb .g-vid { color: var(--c); font-size: 13px; }
.g-thumb.on { border-color: var(--c); box-shadow: 0 0 0 2px color-mix(in srgb, var(--c) 35%, transparent); }

/* ============================================================
   CUSTOM / "BUILD ANYTHING"
   ============================================================ */
.build { padding: 100px 0; background: var(--bg-2); border-block: 1.5px solid var(--line); }
.build-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 56px; align-items: center; }
.build-list { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 30px; }
.build-list .chip {
  border: 1.5px solid var(--line); border-radius: var(--radius-sm); padding: 16px 18px;
  background: var(--surface);
  display: flex; align-items: center; gap: 12px; transition: border-color .2s ease, transform .2s ease;
}
.build-list .chip:hover { border-color: var(--accent-2); transform: translateX(4px); }
.build-list .chip .dot { width: 9px; height: 9px; border-radius: 2px; background: var(--c, var(--accent)); flex: none; }
.build-list .chip span { font-size: 15px; color: var(--ink); font-weight: 500; }
.build-visual {
  border: 1.5px solid var(--ink); border-radius: var(--radius); padding: 30px; position: relative; overflow: hidden;
  background: var(--slab);
  color: var(--on-slab);
}
.build-visual .terminal { font-family: var(--ff-mono); font-size: 13.5px; line-height: 1.9; color: var(--on-slab-2); }
.build-visual .terminal .pl { color: var(--lime-b); }
.build-visual .terminal .cm { color: var(--on-slab-3); }
.build-visual .terminal .ok { color: var(--lime-b); }
.build-visual .terminal .hl { color: var(--on-slab); }
.term-head { display: flex; gap: 7px; margin-bottom: 18px; }
.term-head i { width: 11px; height: 11px; border-radius: 50%; background: color-mix(in srgb, var(--on-slab) 20%, transparent); }
.term-head i:first-child { background: var(--warm-2); }
.term-head i:nth-child(2) { background: var(--dot-amber); }
.term-head i:nth-child(3) { background: var(--lime-b); }
.cursor { display: inline-block; width: 8px; height: 16px; background: var(--lime-b); vertical-align: -2px; animation: blink 1.1s steps(1) infinite; }

/* ============================================================
   PROCESS
   ============================================================ */
.process { padding: 100px 0; }
.steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; counter-reset: step; }
.step { border-top: 1.5px solid var(--line); padding-top: 22px; position: relative; }
.step::before {
  counter-increment: step; content: "[ " counter(step, decimal-leading-zero) " ]";
  font-family: var(--ff-mono); font-size: 13px; color: var(--accent-2); letter-spacing: 0.1em;
}
.step h3 { font-size: 21px; margin: 12px 0 8px; }
.step p { color: var(--ink-2); font-size: 14.5px; }
.step .bar { position: absolute; top: -1.5px; left: 0; height: 2px; width: 0; background: var(--accent); transition: width .8s ease; }
.step.in .bar { width: 46px; }

/* ============================================================
   INNER PAGE HERO — smaller sibling of the home hero, no canvas
   ============================================================ */
.page-hero { padding: clamp(72px, 9vw, 132px) 0 clamp(44px, 6vw, 76px); text-align: center; }
.page-hero .hero-binary { animation: rise .8s cubic-bezier(.2,.7,.2,1) .05s both; }
.page-hero h1 { margin: 20px 0 24px; font-size: clamp(40px, 6.6vw, 88px); line-height: 0.98; font-weight: 800; letter-spacing: -0.035em; text-wrap: balance; animation: rise .9s cubic-bezier(.2,.7,.2,1) .15s both; }
.page-hero h1 .ital { color: var(--green-m); animation: glowp 2.6s ease-in-out 1.8s infinite; }
.page-hero .lead { margin: 0 auto; max-width: 680px; font-size: clamp(16px, 1.7vw, 19px); line-height: 1.65; color: var(--ink-2); text-wrap: pretty; animation: rise .9s cubic-bezier(.2,.7,.2,1) .32s both; }
.page-hero .lead .ital { color: var(--ink); }
.page-hero .hero-actions { animation: rise .9s cubic-bezier(.2,.7,.2,1) .46s both; }

.note { font-family: var(--ff-mono); font-size: 13px; letter-spacing: 0.04em; color: var(--ink-3); }
.note a { color: var(--accent-2); border-bottom: 1px dashed var(--accent-2); }

@media (max-width: 680px) {
  .build-list[style] { grid-template-columns: 1fr !important; }
}

/* ============================================================
   MODULE CARDS — the AllyVora module grid
   Uniform 3-up grid, numbered, with a hover charge: the top rule
   fills with the module's accent, the icon lifts, the waveform runs.
   ============================================================ */
.mod-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
  counter-reset: mod;
}
/* Four cards in a 3-up grid leave one orphan on its own row. A set of four
   gets a 2x2 instead, which also echoes the stat grid it sits under. */
.mod-grid.mod-grid-2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 660px) { .mod-grid.mod-grid-2 { grid-template-columns: 1fr; } }

.mod {
  --c: var(--indigo);
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
  padding: 26px 24px 24px;
  overflow: hidden;
  isolation: isolate;
  transition: transform .3s cubic-bezier(.2,.7,.2,1), border-color .3s ease, box-shadow .3s ease;
}
/* the rule across the top fills with the accent on hover */
.mod::before {
  content: "";
  position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: var(--c);
  transform: scaleX(0); transform-origin: left;
  transition: transform .45s cubic-bezier(.2,.7,.2,1);
}
/* a soft accent wash rising from the bottom */
.mod::after {
  content: "";
  position: absolute; inset: auto 0 0 0; height: 62%;
  background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--c) 9%, transparent));
  opacity: 0; transition: opacity .35s ease;
  pointer-events: none; z-index: -1;
}
.mod:hover, .mod:focus-within {
  transform: translateY(-6px);
  border-color: color-mix(in srgb, var(--c) 55%, var(--line));
  box-shadow: 0 26px 50px -30px color-mix(in srgb, var(--ink) 55%, transparent);
}
.mod:hover::before, .mod:focus-within::before { transform: scaleX(1); }
.mod:hover::after, .mod:focus-within::after { opacity: 1; }

/* header row: [ 0N ] on the left, waveform on the right */
.mod-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 18px; }
.mod-num {
  counter-increment: mod;
  content: "";
  font-family: var(--ff-mono); font-size: 11.5px; font-weight: 600;
  letter-spacing: 0.18em; color: var(--ink-3);
  transition: color .3s ease;
}
.mod-num::before { content: "[ " counter(mod, decimal-leading-zero) " ]"; }
.mod:hover .mod-num { color: var(--c); }
.mod-wave {
  font-family: var(--ff-mono); font-size: 12px; letter-spacing: 0.06em;
  color: var(--ink-3); opacity: 0; transform: translateX(6px);
  transition: opacity .3s ease, transform .3s ease, color .3s ease;
}
.mod:hover .mod-wave { opacity: 1; transform: none; color: var(--c); animation: bob 2.8s ease-in-out infinite; }

.mod-icon {
  width: 46px; height: 46px; border-radius: 12px;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--c) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--c) 38%, transparent);
  margin-bottom: 18px;
  transition: transform .35s cubic-bezier(.2,.7,.2,1), background .3s ease, border-color .3s ease;
}
.mod:hover .mod-icon {
  transform: translateY(-3px) rotate(-4deg);
  background: color-mix(in srgb, var(--c) 20%, transparent);
  border-color: var(--c);
}
.mod-icon svg { width: 23px; height: 23px; stroke: var(--c); fill: none; stroke-width: 1.7; }

.mod .tag {
  font-family: var(--ff-mono); font-size: 11px; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--c);
}
.mod h3 { font-size: 22px; margin: 9px 0 10px; letter-spacing: -0.025em; }
.mod p { color: var(--ink-2); font-size: 14.5px; line-height: 1.62; text-wrap: pretty; }

.mod-feats { display: flex; flex-wrap: wrap; gap: 6px; margin-top: auto; padding-top: 20px; }
.mod-feats b {
  font-family: var(--ff-mono); font-weight: 400; font-size: 11px;
  color: var(--ink-2); background: var(--tint);
  border: 1px solid var(--line-soft); padding: 4px 9px; border-radius: 6px;
  transition: border-color .25s ease, color .25s ease, background .25s ease;
}
.mod:hover .mod-feats b { border-color: color-mix(in srgb, var(--c) 32%, transparent); }

/* staggered entrance — each card lands a beat after the one before it */
body.anim .mod-grid .reveal:nth-child(1) { transition-delay: .00s; }
body.anim .mod-grid .reveal:nth-child(2) { transition-delay: .06s; }
body.anim .mod-grid .reveal:nth-child(3) { transition-delay: .12s; }
body.anim .mod-grid .reveal:nth-child(4) { transition-delay: .18s; }
body.anim .mod-grid .reveal:nth-child(5) { transition-delay: .24s; }
body.anim .mod-grid .reveal:nth-child(6) { transition-delay: .30s; }
body.anim .mod-grid .reveal:nth-child(7) { transition-delay: .36s; }
body.anim .mod-grid .reveal:nth-child(8) { transition-delay: .42s; }
body.anim .mod-grid .reveal:nth-child(9) { transition-delay: .48s; }

/* Same cascade for the other grouped reveals, so a legal page reads down the
   way the card grids do rather than landing as one block. The legal pages
   alternate heading and paragraph, so the step is half the grid's: a pair
   arrives about as fast as one card does. */
body.anim .legal .reveal:nth-child(2)  { transition-delay: .03s; }
body.anim .legal .reveal:nth-child(3)  { transition-delay: .06s; }
body.anim .legal .reveal:nth-child(4)  { transition-delay: .09s; }
body.anim .legal .reveal:nth-child(5)  { transition-delay: .12s; }
body.anim .legal .reveal:nth-child(6)  { transition-delay: .15s; }
body.anim .legal .reveal:nth-child(7)  { transition-delay: .18s; }
body.anim .legal .reveal:nth-child(8)  { transition-delay: .21s; }

body.anim .build-list .reveal:nth-child(2) { transition-delay: .06s; }
body.anim .build-list .reveal:nth-child(3) { transition-delay: .12s; }
body.anim .build-list .reveal:nth-child(4) { transition-delay: .18s; }
body.anim .build-list .reveal:nth-child(5) { transition-delay: .24s; }
body.anim .build-list .reveal:nth-child(6) { transition-delay: .30s; }

@media (max-width: 980px) { .mod-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 660px) { .mod-grid { grid-template-columns: 1fr; } }
@media (prefers-reduced-motion: reduce) {
  .mod, .mod-icon, .mod::before, .mod::after { transition: none; }
  .mod:hover .mod-wave { animation: none; }
  body.anim .mod-grid .reveal,
  body.anim .legal .reveal,
  body.anim .build-list .reveal { transition-delay: 0s !important; }
}

/* ============================================================
   ABOUT US — story, stats, timeline
   ============================================================ */
.story-grid { display: grid; grid-template-columns: 1.25fr 1fr; gap: clamp(32px, 5vw, 68px); align-items: start; padding-bottom: clamp(60px, 8vw, 110px); }
.story-copy p { color: var(--ink-2); font-size: 17px; line-height: 1.75; text-wrap: pretty; }
.story-copy p + p { margin-top: 18px; }
.story-copy p:first-child { font-size: 20px; color: var(--ink); }

.stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.stat {
  position: relative; overflow: hidden;
  border: 1.5px solid var(--line); border-radius: var(--radius-sm);
  padding: 22px 20px; background: var(--surface);
  transition: border-color .3s ease, transform .3s ease;
}
/* the accent rule that fills on hover, the same gesture the module cards
   make, so a figure and a card behave alike */
.stat::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: var(--accent);
  transform: scaleX(0); transform-origin: left;
  transition: transform .35s cubic-bezier(.2, .7, .2, 1);
}
.stat:hover { border-color: color-mix(in srgb, var(--accent) 55%, transparent); transform: translateY(-3px); }
.stat:hover::before { transform: scaleX(1); }
.stat b { display: block; font-family: var(--ff-display); font-size: clamp(30px, 3.6vw, 44px); font-weight: 800; letter-spacing: -0.03em; color: var(--ink); line-height: 1; }
.stat span { display: block; margin-top: 8px; font-family: var(--ff-mono); font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-3); }

.timeline { list-style: none; display: grid; gap: 0; margin-top: 8px; }
.timeline li {
  position: relative;
  display: grid; grid-template-columns: 120px 1fr; gap: 24px;
  padding: 26px 0 26px 26px;
  border-top: 1.5px solid var(--line);
  transition: background .3s ease;
}
.timeline li:last-child { border-bottom: 1.5px solid var(--line); }
/* a spine down the left with a marker per entry, so the years read as one
   run rather than four separate rows */
.timeline li::before {
  content: ""; position: absolute; left: 3px; top: 0; bottom: 0;
  width: 1.5px; background: var(--line);
}
.timeline li:first-child::before { top: 50%; }
.timeline li:last-child::before { bottom: 50%; }
.timeline li::after {
  content: ""; position: absolute; left: 0; top: calc(50% - 4px);
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--bg); border: 2px solid var(--accent-2);
  transition: background .3s ease, transform .3s ease;
}
.timeline li:hover { background: var(--tint); }
.timeline li:hover::after { background: var(--accent); transform: scale(1.25); }
.timeline .yr { font-family: var(--ff-mono); font-size: 13px; font-weight: 600; letter-spacing: 0.14em; color: var(--accent-2); padding-top: 4px; }
.timeline h3 { font-size: 21px; margin-bottom: 8px; }
.timeline p { color: var(--ink-2); font-size: 15px; max-width: 640px; }

@media (max-width: 900px) {
  .story-grid { grid-template-columns: 1fr; }
  .timeline li { grid-template-columns: 1fr; gap: 8px; padding-left: 22px; }
}

/* ============================================================
   CTA / CONTACT
   ============================================================ */
.cta { padding: 40px 0 110px; }
.cta-box {
  border: 1.5px solid var(--line); border-radius: 20px; padding: clamp(48px, 8vw, 84px) 56px; text-align: center; position: relative; overflow: hidden;
  background: var(--surface);
}
.cta-box::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: radial-gradient(circle at 1px 1px, color-mix(in srgb, var(--ink) 12%, transparent) 1px, transparent 0);
  background-size: 22px 22px;
  mask-image: radial-gradient(ellipse 70% 100% at 50% 100%, black, transparent 75%);
}
.cta-box h2 { font-size: clamp(40px, 6.5vw, 88px); letter-spacing: -0.035em; line-height: 0.98; margin-bottom: 18px; position: relative; }
.cta-box p { color: var(--ink-2); font-size: clamp(15px, 1.6vw, 18px); max-width: 580px; margin: 0 auto 32px; position: relative; }
.cta-actions { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; position: relative; }
/* the primary CTA breathes a lime ring */
.cta-actions .btn-primary { animation: ringp 3.2s ease-in-out infinite; }

/* ============================================================
   FOOTER — paper ground, oversized wordmark
   Deliberately light: the marquee band above it is var(--slab), so a dark
   footer would read as one continuous slab. The wordmark is set huge and
   clipped at the baseline, which is the piece that makes it ours.
   ============================================================ */
.footer { background: var(--bg); border-top: 1.5px solid var(--ink); padding: clamp(38px, 5vw, 60px) 0 26px; overflow: hidden; }

.foot-status {
  display: flex; align-items: center; gap: 10px;
  font-family: var(--ff-mono); font-size: 11px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--ink-3);
  padding-bottom: clamp(28px, 4vw, 44px);
}
.foot-status .live { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); animation: dotblink 1.4s steps(1) infinite; flex: none; }
.foot-status .foot-bin { margin-left: auto; color: var(--accent-2); letter-spacing: 0.3em; }

.foot-grid { display: grid; grid-template-columns: 1.1fr 1.4fr; gap: clamp(30px, 5vw, 72px); align-items: start; }

.foot-say p { font-size: clamp(17px, 1.9vw, 21px); line-height: 1.55; color: var(--ink); max-width: 380px; text-wrap: pretty; }
.foot-say .ital { color: var(--green-m); }
.foot-mail {
  display: inline-flex; align-items: center; gap: 9px; margin-top: 22px;
  font-family: var(--ff-mono); font-size: 13px; font-weight: 600;
  letter-spacing: 0.08em; color: var(--ink);
  border-bottom: 2px solid var(--lime-b); padding-bottom: 3px;
  transition: color .2s ease, border-color .2s ease;
}
.foot-mail:hover { color: var(--accent-2); border-color: var(--accent-2); }
.foot-mail .arr { transition: transform .2s ease; }
.foot-mail:hover .arr { transform: translateX(3px); }

.foot-links { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.foot-links h4 { font-family: var(--ff-mono); font-size: 10.5px; letter-spacing: 0.2em; text-transform: uppercase; color: var(--ink-3); font-weight: 400; margin-bottom: 14px; }
.foot-links ul { list-style: none; display: grid; gap: 9px; }
.foot-links a { font-size: 14.5px; color: var(--ink-2); transition: color .18s ease, padding-left .18s ease; }
.foot-links a:hover { color: var(--ink); padding-left: 4px; }

/* the signature mark: as wide as the viewport, cropped at the baseline */
.foot-mark {
  /* held to the same measure as the footer's columns above it, so the
     wordmark starts where the "Platforms" heading does rather than at the
     window edge */
  margin: clamp(36px, 5vw, 64px) auto 0;
  max-width: var(--maxw);
  padding-inline: 40px;
  font-family: var(--ff-display); font-weight: 800;
  font-size: clamp(72px, 19vw, 280px); line-height: 0.78;
  letter-spacing: -0.05em; white-space: nowrap;
  max-height: 0.62em; overflow: hidden;
  user-select: none;
}
.foot-mark .bp { color: var(--ink); }
.foot-mark .bb { color: var(--green-m); }
.foot-mark .caret { display: inline-block; width: 0.09em; height: 0.5em; background: var(--lime-b); margin-left: 0.04em; animation: blink 1.1s steps(1) infinite; }

.foot-bottom {
  display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--line);
  font-family: var(--ff-mono); font-size: 11.5px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ink-3);
}

@media (max-width: 860px) {
  .foot-grid { grid-template-columns: 1fr; gap: 34px; }
  .foot-links { grid-template-columns: repeat(3, 1fr); }

  /* The six desktop links only just fitted at 681px — about 3px of slack,
     with 33px tap targets. Everything below 860px gets the menu instead. */
  .nav-links { display: none; }
  .menu-btn { display: inline-flex; }
}
@media (max-width: 560px) {
  .foot-links { grid-template-columns: 1fr 1fr; gap: 22px; }
  .foot-status { flex-wrap: wrap; }
  .foot-status .foot-bin { margin-left: 0; width: 100%; }
  .foot-mark { padding-inline: 18px; }
  .foot-bottom { flex-direction: column; align-items: flex-start; }
}
@media (prefers-reduced-motion: reduce) {
  .foot-status .live, .foot-mark .caret { animation: none; }

  /* The wordmark holds still, but `animation: none` would strand the letters
     at the entrance's starting frame — offset and transparent — because it
     runs with `both`. Clearing the transform and opacity puts them where the
     animation would have finished. */
  /* No typing at all: `animation: none` would leave every letter at the
     declared max-width:0 / opacity:0, i.e. an empty header, so the finished
     state is restored explicitly. */
  /* Beats every wordmark variant — and has to out-specify them to do it.
     The gates are html[data-mo~="wm-x"] .brand i, which is two attributes
     and two elements; a bare `.brand i` here loses to that and the
     typewriter kept typing for readers who had asked it not to. Matching
     html[data-mo] ties the specificity, and this block is later in the file.

     `animation: none` alone would strand the
     typewriter's letters at max-width:0 — an empty header — so the finished
     state is restored explicitly, and the sweep's transparent fill is put
     back to a solid colour. */
  html[data-mo] .brand i {
    animation: none;
    max-width: none;
    opacity: 1;
    transform: none;
    text-shadow: none;
  }
  /* Both halves need `color` put back, not just the fill: the sweep paints
     through transparent text, and currentColor resolves to that same
     transparent — so restoring only -webkit-text-fill-color left the
     wordmark invisible rather than still. */
  html[data-mo] .brand .bp,
  html[data-mo] .brand .bb {
    animation: none;
    background-image: none;
  }
  html[data-mo] .brand .bp { color: var(--ink);      -webkit-text-fill-color: var(--ink); }
  html[data-mo] .brand .bb { color: var(--accent-2); -webkit-text-fill-color: var(--accent-2); }
  .nav::after { animation: none; }
}

/* ---------- reveal animation ----------
   Visible by default. Only when JS adds .anim to <body> do we hide,
   then reveal via .in — so content always shows if JS fails.
   Matches the landing page's rise: lift + de-blur. */
body.anim .reveal { opacity: 0; transform: translateY(18px); filter: blur(8px); transition: opacity calc(.7s * var(--mo-scale)) cubic-bezier(.2,.7,.2,1), transform calc(.7s * var(--mo-scale)) cubic-bezier(.2,.7,.2,1), filter calc(.7s * var(--mo-scale)) cubic-bezier(.2,.7,.2,1); }
body.anim .reveal.in { opacity: 1; transform: none; filter: none; }

@media (prefers-reduced-motion: reduce) {
  /* stop the shimmer and put the solid colour back, or the gradient-clipped
     text would be left transparent with no animation to reveal it */
  .nav-links a, .nav-links a:not(.on) {
    animation: none;
    background-image: none;
    color: var(--ink-nav);
    -webkit-text-fill-color: var(--ink-nav);
  }
  .nav-links a.on { color: var(--ink); -webkit-text-fill-color: var(--ink); }
  body.anim .reveal { opacity: 1; transform: none; filter: none; transition: none; }
  .cursor, .nav::after,
  .hero .hero-display .pulse, .hero .hero-display .caret-lg, .brand .caret,
  .hero-meta .live, .hero-cue .rail i, .cta-actions .btn-primary { animation: none; }
  .hero-binary, .hero .hero-display .l1, .hero .hero-display .l2, .hero .hero-h1,
  .hero p.lead, .hero-actions, .hero-meta, .hero-cue { animation: none; opacity: 1; filter: none; transform: none; }
}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 980px) {
  .span-6, .span-4 { grid-column: span 6; }
  .card.feature { grid-template-columns: 1fr; }
  .build-grid { grid-template-columns: 1fr; gap: 36px; }
  .steps { grid-template-columns: repeat(2, 1fr); gap: 28px; }
  .footer-grid { grid-template-columns: 1fr 1fr; gap: 32px; }
}
@media (max-width: 780px) {
  .hero-cue { display: none; }
}
@media (max-width: 680px) {
  .wrap { padding-inline: 18px; }
  .nav-inner { height: 62px; }
  .prod-grid { grid-template-columns: repeat(6, 1fr); gap: 16px; }
  .span-6, .span-4, .span-12 { grid-column: span 6; }
  .card { padding: 24px; }
  .card.feature { padding: 26px; }
  .build-list { grid-template-columns: 1fr; }
  .steps { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: 1fr 1fr; gap: 28px; }
  .footer-bottom { flex-direction: column; align-items: flex-start; }
  .hero-inner { padding: 100px 20px 96px; }
  .products, .build, .process { padding: 70px 0; }
  .section-head { margin-bottom: 40px; }
  .cta-box { padding: 44px 22px; }
}

@media (max-width: 430px) {
  .footer-grid { grid-template-columns: 1fr; }
  .hero-actions { width: 100%; }
  /* Full width already, so the label may as well wrap onto a second line
     rather than set a minimum the column cannot honour. */
  .hero-actions .btn { width: 100%; justify-content: center; white-space: normal; text-align: center; }
  .hero-meta.right { display: none; }
  .term-input-row { flex-wrap: wrap; }
  .modal.show { padding: 0; }
  .modal-panel { border-radius: 0; min-height: 100%; padding: 20px 18px 32px; }
  .modal-info h3 { font-size: 26px; }
  .cta-actions .btn { width: 100%; justify-content: center; white-space: normal; text-align: center; }
}

/* ============================================================
   INTERACTIVE ADDITIONS — view cue, modal, mock UI, terminal
   ============================================================ */

/* clickable product cards */
.card[data-product] { cursor: pointer; transform-style: preserve-3d; }
.view-cue {
  position: absolute; bottom: 22px; right: 24px;
  font-family: var(--ff-mono); font-size: 12px; letter-spacing: 0.04em;
  color: var(--c); display: inline-flex; align-items: center; gap: 6px;
  opacity: 0; transform: translateX(-6px); transition: opacity .25s ease, transform .25s ease;
}
.card:hover .view-cue, .card:focus-visible .view-cue { opacity: 1; transform: none; }
.card.feature .view-cue { bottom: 28px; right: 28px; }
.card:focus-visible { outline: 2px solid var(--c); outline-offset: 3px; }

/* ---------- terminal: interactive ---------- */
.term-title { margin-left: 8px; font-family: var(--ff-mono); font-size: 12px; color: color-mix(in srgb, var(--on-slab) 50%, transparent); }
.term-input-row { display: flex; align-items: center; gap: 8px; margin-top: 6px; font-family: var(--ff-mono); font-size: 13.5px; }
.term-input-row .pl { color: var(--lime-b); white-space: nowrap; }
.term-input {
  flex: 1; min-width: 0; background: transparent; border: none; outline: none;
  font-family: var(--ff-mono); font-size: 13.5px; color: var(--on-slab);
  caret-color: var(--lime-b);
}
.term-input::placeholder { color: color-mix(in srgb, var(--on-slab) 40%, transparent); }
.term-input:disabled { color: color-mix(in srgb, var(--on-slab) 40%, transparent); }
#terminal { max-height: 340px; overflow-y: auto; scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--on-slab) 25%, transparent) transparent; }
#termOut > div { margin-bottom: 2px; }
.terminal .run { color: var(--dot-amber); }
.terminal .link { color: var(--lime-b); border-bottom: 1px dashed var(--lime-b); }
.terminal a { color: var(--lime-b); }
.term-launch { margin-top: 6px; }
.term-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; transition: opacity .2s ease; }
.term-chips button {
  font-family: var(--ff-mono); font-size: 12px; color: color-mix(in srgb, var(--on-slab) 75%, transparent);
  background: color-mix(in srgb, var(--on-slab) 6%, transparent); border: 1px solid color-mix(in srgb, var(--on-slab) 20%, transparent); border-radius: 999px;
  padding: 6px 12px; cursor: pointer; transition: border-color .2s ease, color .2s ease, transform .15s ease;
}
.term-chips button:hover { border-color: var(--lime-b); color: var(--on-slab); transform: translateY(-1px); }

/* ============================================================
   MODAL
   ============================================================ */
.modal { position: fixed; inset: 0; z-index: 100; display: none; }
.modal.show { display: flex; align-items: flex-start; justify-content: center; padding: 4.5vh 20px 5vh; overflow-y: auto; }
.modal-backdrop { position: fixed; inset: 0; background: color-mix(in srgb, var(--ink) 55%, transparent); backdrop-filter: blur(10px); animation: mfade .25s ease; }
@keyframes mfade { from { opacity: 0; } }
.modal-panel {
  position: relative; width: min(1060px, 100%);
  background: var(--surface);
  border: 1.5px solid var(--line); border-radius: 20px; padding: 26px;
  box-shadow: 0 40px 100px -30px color-mix(in srgb, var(--ink) 50%, transparent);
  --c: var(--indigo);
  animation: mpop .32s cubic-bezier(.2,.8,.2,1);
}
@keyframes mpop { from { opacity: 0; transform: translateY(26px) scale(.98); } }
.modal-panel::before {
  content: ""; position: absolute; inset: 0; border-radius: 20px; pointer-events: none;
  background: radial-gradient(600px 240px at 80% -10%, var(--c), transparent 65%); opacity: 0.08;
}
.modal-close {
  position: absolute; top: 18px; right: 18px; z-index: 2;
  width: 38px; height: 38px; border-radius: 50%; cursor: pointer;
  background: var(--tint); border: 1px solid var(--line); color: var(--ink-2);
  font-size: 15px; transition: background .2s ease, color .2s ease, border-color .2s ease;
}
.modal-close:hover { background: var(--tint-2); color: var(--ink); border-color: var(--c); }

.modal-nav { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 22px; padding-right: 48px; position: relative; }
.modal-nav button {
  font-family: var(--ff-mono); font-size: 12px; letter-spacing: 0.02em; color: var(--ink-3);
  background: transparent; border: 1px solid var(--line); border-radius: 999px;
  padding: 7px 13px; cursor: pointer; transition: all .18s ease; --c: var(--indigo);
}
.modal-nav button:hover { color: var(--ink); border-color: var(--c); }
.modal-nav button.on { color: var(--surface); background: var(--c); border-color: var(--c); font-weight: 700; }

.modal-body { display: grid; grid-template-columns: 1fr 1.12fr; gap: 30px; align-items: center; position: relative; }
.modal-info .tag { font-family: var(--ff-mono); font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase; }
.modal-info h3 { font-size: 34px; margin: 8px 0 14px; }
.modal-info > p { color: var(--ink-2); font-size: 15.5px; line-height: 1.6; }
.modal-feats { display: flex; flex-wrap: wrap; gap: 8px; margin: 22px 0 26px; }
.modal-feats b {
  font-family: var(--ff-mono); font-weight: 400; font-size: 12px; color: var(--ink-2);
  background: var(--tint); border: 1px solid var(--line-soft); padding: 6px 11px; border-radius: 7px;
}
.modal-actions { display: flex; gap: 12px; flex-wrap: wrap; }

/* ---------- mock app screen ---------- */
.modal-mock { perspective: 1200px; }
.mock {
  --c: var(--indigo);
  border: 1.5px solid var(--line); border-radius: 14px; overflow: hidden;
  background: var(--bg); box-shadow: 0 30px 60px -30px color-mix(in srgb, var(--ink) 45%, transparent);
  animation: mockin .5s cubic-bezier(.2,.8,.2,1);
}
@keyframes mockin { from { opacity: 0; transform: rotateY(-8deg) translateY(10px); } }
.mock-bar { display: flex; align-items: center; gap: 6px; padding: 11px 14px; border-bottom: 1px solid var(--line); background: var(--bg-2); }
.mock-bar i { width: 9px; height: 9px; border-radius: 50%; background: var(--line); }
.mock-bar i:first-child { background: var(--warm-2); }
.mock-bar i:nth-child(2) { background: var(--dot-amber); }
.mock-bar i:nth-child(3) { background: var(--lime-c); }
.mock-url { margin-left: 10px; font-family: var(--ff-mono); font-size: 11px; color: var(--ink-3); }
.mock-app { display: flex; min-height: 300px; }
.mock-side { width: 138px; flex: none; padding: 14px 10px; border-right: 1px solid var(--line); background: var(--bg-2); display: flex; flex-direction: column; gap: 4px; }
.ms-logo { width: 22px; height: 22px; border-radius: 6px; background: linear-gradient(135deg, var(--c), transparent); margin: 2px 4px 12px; }
.ms-item { display: flex; align-items: center; gap: 9px; padding: 8px 9px; border-radius: 8px; font-size: 12.5px; color: var(--ink-3); }
.ms-item i { width: 7px; height: 7px; border-radius: 2px; background: var(--line); flex: none; }
.ms-item.on { background: color-mix(in srgb, var(--c) 12%, transparent); color: var(--ink); }
.ms-item.on i { background: var(--c); box-shadow: 0 0 8px var(--c); }
.mock-main { flex: 1; padding: 18px; min-width: 0; }
.ms-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
.ms-head b { font-family: var(--ff-display); font-size: 18px; }
.ms-ai { font-family: var(--ff-mono); font-size: 11px; color: var(--c); border: 1px solid color-mix(in srgb, var(--c) 38%, transparent); border-radius: 999px; padding: 4px 10px; }
.ms-metrics { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 16px; }
.ms-metric { border: 1px solid var(--line); border-radius: 10px; padding: 11px 12px; background: var(--tint); }
.ms-k { display: block; font-size: 10.5px; color: var(--ink-3); font-family: var(--ff-mono); letter-spacing: 0.04em; margin-bottom: 6px; }
.ms-v { font-family: var(--ff-display); font-size: 20px; color: var(--ink); }
.ms-chart { display: flex; align-items: flex-end; gap: 8px; height: 72px; padding: 12px; border: 1px solid var(--line); border-radius: 10px; margin-bottom: 14px; }
.ms-chart i { flex: 1; border-radius: 4px 4px 2px 2px; background: linear-gradient(180deg, var(--c), color-mix(in srgb, var(--c) 25%, transparent)); min-height: 6px; }
.ms-list { display: flex; flex-direction: column; gap: 8px; }
.ms-row { display: flex; align-items: center; gap: 11px; padding: 9px 10px; border: 1px solid var(--line-soft); border-radius: 9px; }
.ms-av { width: 26px; height: 26px; border-radius: 7px; background: color-mix(in srgb, var(--c) 25%, var(--surface)); flex: none; }
.ms-rt { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.ms-rt b { font-size: 12.5px; color: var(--ink); font-family: var(--ff-body); font-weight: 600; }
.ms-rt span { font-size: 11px; color: var(--ink-3); }
.ms-st { font-family: var(--ff-mono); font-size: 10.5px; color: var(--c); white-space: nowrap; }

@media (max-width: 880px) {
  .modal-body { grid-template-columns: 1fr; gap: 24px; }
  .modal-mock { order: -1; }
  .modal-info h3 { font-size: 28px; }
}

/* ============================================================
   SITE-WIDE PAGES — products, services, about, contact, legal, 404
   These used to run on a separate Tailwind layout with its own header
   and footer. They now share this one, so the pieces their bodies need
   that the landing never did live here.
   ============================================================ */

/* keyboard-only skip target */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  font-family: var(--ff-mono); font-size: 13px;
  /* the ground on the ink, not the charge on the ink: on a dark theme the
     ink is light and the charge is bright, which left the first control a
     keyboard user reaches unreadable */
  background: var(--ink); color: var(--bg);
  padding: 12px 18px; border-radius: 0 0 8px 0;
}
.skip-link:focus { left: 0; }

/* ---------- module card extras ---------- */
.mod .mod-tagline {
  color: var(--c);
  font-weight: 600;
  font-size: 14px;
  margin: -4px 0 10px;
}
.mod-link {
  font-family: var(--ff-mono); font-size: 12px; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--c);
  margin-top: 18px;
  display: inline-flex; align-items: center; gap: 7px;
  opacity: 0; transform: translateY(4px);
  transition: opacity .28s ease, transform .28s ease;
}
.mod:hover .mod-link, .mod:focus-within .mod-link { opacity: 1; transform: none; }
.mod-link .arr { transition: transform .2s ease; }
.mod-link:hover .arr { transform: translateX(3px); }
/* the link is the only reason a keyboard user enters the card */
.mod-link:focus-visible { opacity: 1; transform: none; outline: 2px solid var(--c); outline-offset: 3px; }

/* ---------- chip carrying a title and a line of body ---------- */
.build-list .chip.chip-stack { align-items: flex-start; }
.chip-stack .dot { margin-top: 6px; }
.chip-stack b, .chip-stack i {
  display: block; font-style: normal;
}
.chip-stack b { font-size: 15px; font-weight: 700; color: var(--ink); }
.chip-stack i { margin-top: 5px; font-size: 14px; color: var(--ink-2); line-height: 1.55; }

/* ---------- engagement tiers ---------- */
.tier-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.tier {
  --c: var(--indigo);
  display: flex; flex-direction: column;
  border: 1.5px solid var(--line); border-radius: var(--radius);
  background: var(--surface);
  padding: 28px 26px;
  transition: transform .3s cubic-bezier(.2,.7,.2,1), border-color .3s ease, box-shadow .3s ease;
}
.tier:hover { transform: translateY(-5px); border-color: var(--c); box-shadow: 0 26px 50px -30px color-mix(in srgb, var(--ink) 50%, transparent); }
/* the middle tier is the one we recommend, so it carries the charge */
.tier.tier-on { border-color: var(--c); box-shadow: 0 0 0 1.5px var(--c) inset; }
.tier .tag {
  font-family: var(--ff-mono); font-size: 11.5px; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--c);
}
.tier p { margin-top: 12px; color: var(--ink-2); font-size: 15px; line-height: 1.62; }
.tier b {
  margin-top: auto; padding-top: 24px;
  font-family: var(--ff-display); font-size: 26px; font-weight: 800;
  letter-spacing: -0.03em; color: var(--ink);
}

/* ============================================================
   CONTACT
   ============================================================ */
.contact-grid { display: grid; grid-template-columns: 1.6fr 1fr; gap: clamp(24px, 3vw, 40px); align-items: start; }

.form-panel {
  border: 1.5px solid var(--line); border-radius: 20px;
  background: var(--surface);
  padding: clamp(28px, 4vw, 44px);
}
.form-panel h2 { font-size: clamp(26px, 3vw, 36px); margin: 16px 0 8px; }
.form-panel h2 .ital { color: var(--green-m); }
.form-note { color: var(--ink-2); font-size: 15px; }

.form { margin-top: 30px; display: grid; gap: 20px; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.field { display: grid; gap: 7px; }
.field label {
  font-family: var(--ff-mono); font-size: 11.5px; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-2);
}
.field label .opt { color: var(--ink-3); font-weight: 400; }
.field input, .field textarea {
  font-family: var(--ff-body); font-size: 15px; color: var(--ink);
  background: var(--bg);
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 13px 15px;
  width: 100%;
  transition: border-color .2s ease, box-shadow .2s ease, background .2s ease;
}
.field textarea { resize: vertical; min-height: 140px; line-height: 1.6; }
.field input::placeholder, .field textarea::placeholder { color: var(--ink-3); }
.field input:focus, .field textarea:focus {
  outline: none;
  border-color: var(--accent-2);
  background: var(--surface);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--lime-c) 22%, transparent);
}
.field-err { font-family: var(--ff-mono); font-size: 12px; color: var(--warm); }
/* a field the browser or the server has rejected */
.field input[aria-invalid="true"], .field textarea[aria-invalid="true"] { border-color: var(--warm); }

.form-foot { display: flex; align-items: center; justify-content: space-between; gap: 18px; flex-wrap: wrap; margin-top: 4px; }
.form-foot .note { max-width: 300px; }

.contact-aside { display: grid; gap: 18px; }
.side-card {
  border: 1.5px solid var(--line); border-radius: var(--radius);
  background: var(--surface); padding: 26px 24px;
}
.side-card h3 { font-size: 20px; margin-bottom: 18px; }

.chan-list { list-style: none; display: grid; gap: 18px; }
.chan-list li { display: flex; align-items: flex-start; gap: 13px; }
.chan-icon {
  width: 38px; height: 38px; flex: none; border-radius: 10px;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--lime-c) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--lime-c) 35%, transparent);
}
.chan-icon svg { width: 19px; height: 19px; stroke: var(--green-d); fill: none; stroke-width: 1.7; }
.chan-body { display: grid; gap: 3px; min-width: 0; }
.chan-body i {
  font-style: normal; font-family: var(--ff-mono);
  font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-3);
}
.chan-body a, .chan-body b { font-size: 15px; font-weight: 600; color: var(--ink); word-break: break-word; }
.chan-body a { border-bottom: 1.5px solid var(--lime-b); transition: color .18s ease, border-color .18s ease; }
.chan-body a:hover { color: var(--accent-2); border-color: var(--accent-2); }
.chan-body em { font-style: normal; font-size: 13px; color: var(--ink-3); }

.faq { display: grid; gap: 16px; }
.faq dt { font-size: 15px; font-weight: 700; color: var(--ink); }
.faq dd { margin-top: 5px; font-size: 14.5px; color: var(--ink-2); line-height: 1.6; }

@media (max-width: 980px) {
  .contact-grid { grid-template-columns: 1fr; }
  .tier-grid { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .field-row { grid-template-columns: 1fr; }
  .form-foot { flex-direction: column; align-items: stretch; }
  .form-foot .btn { justify-content: center; }
}

/* ============================================================
   LEGAL PROSE — privacy, terms
   ============================================================ */
.legal { max-width: 720px; }
.legal h2 {
  font-size: clamp(21px, 2.4vw, 27px);
  margin: 42px 0 12px;
  padding-top: 22px;
  border-top: 1.5px solid var(--line);
}
.legal h2:first-child { margin-top: 0; padding-top: 0; border-top: none; }
.legal p { color: var(--ink-2); font-size: 16.5px; line-height: 1.75; text-wrap: pretty; }
.legal a { color: var(--accent-2); border-bottom: 1px dashed var(--accent-2); }
.legal a:hover { color: var(--ink); border-color: var(--ink); }

/* inline link inside a CTA panel */
.note-link { color: var(--green-m); border-bottom: 2px solid var(--lime-b); font-weight: 600; }
.note-link:hover { color: var(--ink); border-color: var(--ink); }

@media (prefers-reduced-motion: reduce) {
  .mod-link, .tier { transition: none; }
}

/* ============================================================
   TOUCH AND SMALL SCREENS

   Measured on real viewports rather than guessed: at 390px the footer
   links rendered 17px tall, form labels at 11.5px and the footer group
   headings at 10.5px. Nothing here changes the desktop rendering.
   ============================================================ */
@media (max-width: 860px) {
  /* 17px tall with no padding is under even the 24px WCAG 2.2 minimum.
     The list gap drops because the padding now does that job. */
  .foot-links a { display: inline-block; padding-block: 10px; }
  .foot-links ul { gap: 0; }
  .foot-links h4 { font-size: 11.5px; margin-bottom: 8px; }

  /* form labels were 11.5px — too small to read comfortably on a phone */
  .field label { font-size: 13px; }
  .form-note, .note { font-size: 14px; }
}

@media (max-width: 430px) {
  /* two 135px columns left the figures cramped against their captions */
  .stat-grid { grid-template-columns: 1fr; }
  .tier-grid { grid-template-columns: 1fr; }
}

@media (max-width: 360px) {
  .foot-links { grid-template-columns: 1fr; gap: 18px; }
}

/* Coarse pointers get the full 44px on anything that is a control,
   including the links inside the mobile menu. */
@media (hover: none) and (pointer: coarse) {
  .btn { min-height: 44px; }
  .menu-btn { width: 46px; height: 46px; }
  .mobile-menu a:not(.btn) { padding-block: 16px; }
  /* repeated from the 860px block: a large tablet is a touch device at a
     width the breakpoint above never reaches */
  .foot-links a { display: inline-block; padding-block: 10px; }
  .foot-links ul { gap: 0; }
  /* hover-only affordances never resolve on touch, so do not depend on them */
  .mod:hover, .tier:hover, .side-card:hover { transform: none; }
}

/* ============================================================
   THEME SWITCHER

   Lives in the header beside the menu button. The palettes themselves are
   already in the document (/theme.css carries one block per theme), so
   choosing is a single attribute write on <html> — no request, no repaint
   gap, and every page picks it up because every colour is a token.
   ============================================================ */
/* The switcher is shared chrome, so it sets its own shape rather than
   reading --radius-sm. Three of the five pages redefine that token to 999px
   for their pill buttons, which turned the dropdown into a giant ellipse:
   the panel painted only inside the ellipse, so its corners showed the page
   through and it read as a transparent blob. Nothing here may depend on a
   token a page is free to redefine. */
.theme-pick {
  position: relative;
  --tp-radius: 12px;
  --tp-radius-sm: 8px;
}

.theme-btn {
  width: 44px; height: 44px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; background: transparent;
  border: 1.5px solid color-mix(in srgb, var(--ink) 35%, transparent);
  border-radius: var(--tp-radius-sm);
  transition: border-color .2s ease, background .2s ease;
}
.theme-btn:hover { border-color: var(--accent-2); }
.theme-btn:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
.nav.theme-open .theme-btn { border-color: var(--accent-2); background: var(--tint); }

/* the button's own mark: the current ground with the current charge on it */
.theme-swatch {
  position: relative; width: 18px; height: 18px;
  border-radius: 50%; overflow: hidden;
  border: 1.5px solid var(--ink);
}
.theme-swatch i, .theme-swatch u { position: absolute; inset: 0; display: block; }
.theme-swatch i { background: var(--bg); }
.theme-swatch u { background: var(--lime-b); clip-path: polygon(0 100%, 100% 0, 100% 100%); }

.theme-menu {
  display: none;
  position: absolute; top: calc(100% + 10px); right: 0;
  /* wide enough that the longest name never wraps: a wrapped name made
     the rows uneven and the list ragged */
  width: max-content; min-width: 260px; max-width: min(320px, calc(100vw - 32px));
  padding: 10px;
  background: var(--surface);
  border: 1.5px solid var(--line);
  border-radius: var(--tp-radius);
  box-shadow: var(--shadow-soft);
  z-index: 60;
}
.nav.theme-open .theme-menu { display: block; animation: menudrop .18s ease; }

.theme-menu-head {
  font-family: var(--ff-mono); font-size: 10px;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ink-3);
  margin: 2px 8px 10px;
}

/* light and dark are the first thing anyone is choosing between, so they
   are sections rather than a pill on each row */
.theme-group + .theme-group { margin-top: 6px; padding-top: 8px; border-top: 1px solid var(--line-soft); }
.theme-group-head {
  font-family: var(--ff-mono); font-size: 9.5px;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 8px 4px;
}

.theme-opt {
  display: flex; align-items: center; gap: 11px;
  width: 100%; min-height: 44px; padding: 8px 9px;
  background: none; border: 0; border-radius: var(--tp-radius-sm);
  cursor: pointer; text-align: left;
  font-family: var(--ff-body); font-size: 14.5px;
  color: var(--ink);
  transition: background .15s ease;
}
.theme-opt:hover { background: var(--tint); }
.theme-opt:focus-visible { outline: 2px solid var(--accent-2); outline-offset: -2px; }
.theme-opt[aria-checked="true"] { background: var(--tint-2); }

/* Each row previews itself: the chip is painted from that theme's own
   colours, passed in as inline custom properties, so the list shows what
   you are choosing rather than naming it. */
.theme-chip {
  position: relative; flex: none;
  width: 22px; height: 22px; border-radius: 50%;
  overflow: hidden;
  border: 1.5px solid color-mix(in srgb, var(--sw-ink) 55%, transparent);
  background: var(--sw-bg);
}
.theme-chip i, .theme-chip u { position: absolute; inset: 0; display: block; }
.theme-chip i { background: var(--sw-bg); }
.theme-chip u { background: var(--sw-ac); clip-path: polygon(0 100%, 100% 0, 100% 100%); }

.theme-name { flex: 1 1 auto; white-space: nowrap; }

/* which one a reader who has never chosen would see */
.theme-default {
  flex: none;
  font-family: var(--ff-mono); font-size: 9px;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-3);
}

/* fixed box, so the right edge stays straight whether or not it is showing */
.theme-tick {
  flex: none; width: 14px; text-align: center;
  color: var(--accent-2); font-size: 13px; opacity: 0;
}
.theme-opt[aria-checked="true"] .theme-tick { opacity: 1; }

/* On a phone the menu is wider than the button's corner allows, so it
   anchors to the header edge instead of to the control. */
@media (max-width: 420px) {
  .theme-menu { right: -6px; min-width: min(288px, calc(100vw - 28px)); }
}

@media (prefers-reduced-motion: reduce) {
  .nav.theme-open .theme-menu { animation: none; }
}

/* ============================================================
   ABOUT — VALUES

   A richer treatment of the module card for the one place the site is
   describing itself rather than a product. Everything below is scoped to
   .values-grid, so /products and /services keep the quieter card.
   ============================================================ */

.values-grid .mod { padding: 30px 28px 28px; }

/* the accent rule draws itself in as the card arrives, rather than waiting
   for a hover that never comes on a touch screen */
.values-grid .mod::before { transform: scaleX(0); }
body.anim .values-grid .reveal.in.mod::before { transform: scaleX(1); transition-delay: .25s; }

/* the icon keeps a slow float, so the section has life at rest */
.values-grid .mod-icon { animation: val-float 5.5s ease-in-out infinite; }
.values-grid .mod:nth-child(2) .mod-icon { animation-delay: -1.4s; }
.values-grid .mod:nth-child(3) .mod-icon { animation-delay: -2.8s; }
.values-grid .mod:nth-child(4) .mod-icon { animation-delay: -4.2s; }
@keyframes val-float { 0%, 100% { transform: translateY(-2px); } 50% { transform: translateY(3px); } }

.values-grid .mod:hover .mod-icon,
.values-grid .mod:focus-within .mod-icon { animation-play-state: paused; }

/* A live equaliser instead of the static glyph row. Five bars on their own
   offsets, running all the time rather than only under a pointer — this is
   the page's one piece of ambient motion. */
.mod-eq { display: flex; align-items: flex-end; gap: 3px; height: 16px; }
.mod-eq i {
  width: 3px; height: 100%;
  background: var(--ink-3);
  border-radius: 1px;
  transform-origin: bottom;
  animation: val-eq 1.4s ease-in-out infinite;
  transition: background .3s ease;
}
.mod-eq i:nth-child(1) { animation-delay: -.10s; }
.mod-eq i:nth-child(2) { animation-delay: -.55s; }
.mod-eq i:nth-child(3) { animation-delay: -.90s; }
.mod-eq i:nth-child(4) { animation-delay: -.35s; }
.mod-eq i:nth-child(5) { animation-delay: -.70s; }
@keyframes val-eq { 0%, 100% { transform: scaleY(.22); } 50% { transform: scaleY(1); } }
.values-grid .mod:hover .mod-eq i,
.values-grid .mod:focus-within .mod-eq i { background: var(--c); }

/* the number picks up the accent as the card arrives too */
body.anim .values-grid .reveal.in .mod-num { color: var(--c); }

.values-grid .mod:hover, .values-grid .mod:focus-within { transform: translateY(-8px); }

@media (prefers-reduced-motion: reduce) {
  .values-grid .mod-icon { animation: none; }
  .mod-eq i { animation: none; transform: scaleY(.6); }
  .values-grid .mod::before { transform: scaleX(1); }
}

/* ---- Latest-articles strip (fragments/article-strip.html) ---- */
.art-strip { padding: 64px 0; }
.art-grid { display: grid; gap: 24px; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
.art-card { background: var(--surface); border: 1.5px solid var(--line); border-radius: var(--radius, 8px); overflow: hidden; }
.art-card-link { display: block; padding: 20px; color: inherit; text-decoration: none; height: 100%; }
.art-card-link:hover h3 { text-decoration: underline; }
.art-card h3 { font-size: 22px; margin: 10px 0 8px; }
.art-card p { color: var(--ink-2); margin: 0 0 14px; }
.art-meta { font-family: var(--ff-mono); font-size: 12px; color: var(--ink-3); }
.art-back { margin-top: 32px; }
