/* Direction B: Prompt. The logo is a terminal prompt, >_, and the page is built from it. */

/* Fonts: self-hosted (SIL OFL, from Google Fonts; see fonts/LICENSE). Latin subset, variable files. */
@font-face { font-family: "Instrument Sans"; font-style: normal; font-weight: 400 700; font-display: swap; src: url("fonts/instrument-sans-latin.woff2") format("woff2"); }
@font-face { font-family: "Instrument Serif"; font-style: normal; font-weight: 400; font-display: swap; src: url("fonts/instrument-serif-latin.woff2") format("woff2"); }
@font-face { font-family: "Instrument Serif"; font-style: italic; font-weight: 400; font-display: swap; src: url("fonts/instrument-serif-italic-latin.woff2") format("woff2"); }
@font-face { font-family: "JetBrains Mono"; font-style: normal; font-weight: 100 800; font-display: swap; src: url("fonts/jetbrains-mono-latin.woff2") format("woff2"); }

/* ---------- Tokens ---------- */
:root {
  /* Colour */
  --color-ground: #4f1693; /* brighter; was #350f62 */
  --color-ground-raised: #582493;
  --color-ground-lift: #5d279b;
  --color-line: #6c2db4;
  --color-line-strong: #833fcf;
  --color-text: #f4f2f8;
  --color-text-muted: #cbbde0;
  --color-text-quiet: #b3a5cf;
  --color-violet: #9e6bf2; /* the logo's own purple */
  --color-violet-bright: #c79afc;
  /* Highlighted words: a violet a little toward pink, so it stands off the purple ground (the designer
     chose it, 2026-10-08, over #c79afc, which read pale). The logo's mark stays --color-violet. */
  --color-highlight: #e08cff;
  --color-green-deep: #0ea877; /* a touch darker than the green, for the cogs in a green word */
  /* Two gentle purples a stacked list takes by turns, for a little flair. */
  --color-lilac: #f3a6ff;
  --color-lavender: #a9b2ff;
  --color-on-violet: #1a0b30;
  --color-red: #ef4444; /* the app's red: Listen, recording, delete (agentsy-style-guide.md, destructive) */
  --color-green: #10b981; /* the app's green: AgentsyTheme.success */
  --color-deep: #22103a; /* deep purple: the four boxes under "AI where it matters." (the lightest their pulse reached; steady now) */
  /* What the page sinks into behind the open menu. */
  /* A much darker purple, drifting through the ground in soft patches. Channels only, so
     each patch can fade it out. */
  --shade: 20 5 40; /* a touch lighter; was 5 1 12 */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0.07 0 0 0 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");

  /* Families */
  --font-display: "Instrument Serif", Georgia, "Times New Roman", serif;
  --font-body: "Instrument Sans", -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* Type scale */
  /* Titles, large text and the space between sections are each a set share of the screen: the
     share they are on a 16 inch MacBook Pro's window (1728 by about 1007), where the site was designed,
     taken of the screen's width or height, whichever is smaller. So any smaller screen shows the same
     page scaled down, in proportion, rather than titles that shrink more slowly than the screen. Each
     stops at the size it has there (the clamp's top), and a phone's floor (its bottom) keeps phones
     as they were. */
  --text-mono-s: 0.75rem;
  --text-mono: 0.8125rem;
  --text-mono-l: 0.9375rem;
  --text-body-s: 0.9375rem;
  --text-body: 1.0625rem;
  --text-body-l: clamp(1.1875rem, min(1.39vw, 2.38svh), 1.5rem);
  --text-mission: clamp(1.375rem, min(2.08vw, 3.57svh), 2.25rem);
  --text-statement: clamp(2.25rem, min(4.63vw, 7.94svh), 5rem);
  --chunk-foot-bottom: clamp(1.5rem, 4vh, 3rem); /* the close's distance from the bottom of the screen */
  --chunk-hold: 0svh; /* extra scroll each chunk holds still for: none */
  --text-display-xs: clamp(1.5rem, min(1.85vw, 3.18svh), 2rem);
  --text-display-s: clamp(1.875rem, min(2.55vw, 4.37svh), 2.75rem);
  --text-display-m: clamp(2.5rem, min(4.17vw, 7.15svh), 4.5rem);
  --text-display-l: clamp(3rem, min(5.32vw, 9.14svh), 5.75rem);
  --text-display-xl: clamp(4.5rem, min(9.72vw, 16.68svh), 10.5rem);

  --leading-hero: 0.98;
  --leading-display: 1.04;
  --leading-snug: 1.3;
  --leading-body: 1.6;
  --tracking-hero: -0.02em;
  --tracking-display: -0.012em;
  --tracking-mono: 0.02em;
  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;

  /* Spacing */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4rem;
  --space-9: 6rem;
  --space-section: clamp(5rem, min(9.26vw, 15.9svh), 10rem);
  /* The page's side margin, never less than the notch on a phone held sideways (viewport-fit=cover
     lets the page run under it), the same both sides so everything stays centred. */
  --gutter: max(clamp(1.25rem, 0.5rem + 3vw, 3.5rem), env(safe-area-inset-left, 0px), env(safe-area-inset-right, 0px));
  --container: 77.5rem;
  --measure: 34rem;
  --measure-wide: 46rem;

  /* Shape */
  --hairline: 1px;
  --rule: 2px;
  --radius-s: 6px;
  --radius-m: 10px;
  --radius-l: 14px;
  --dot: 0.5625rem;
  --check-box: 1.375rem;
  --node: 0.625rem;

  /* Components */
  --nav-height: 4.5rem;
  --hero-stage-bottom: clamp(3rem, min(5.56vw, 9.53svh), 6rem);
  --dur-mission: 1800ms;
  --cover-fade: clamp(4rem, 10vh, 9rem); /* how soft the edge is where the headline covers the drawing */
  /* The header sits close to the screen's edges, wider than the page's text column. */
  --header-inset: clamp(1.25rem, 0.8rem + 1.8vw, 2.75rem);
  --menu-width: min(73.6vw, 32rem);
  /* How far the menu's left edge fades out into the dimmed page. */
  --text-menu: clamp(2rem, 1.6rem + 1.6vw, 3rem);
  --tap-target: 2.75rem;
  --burger-width: 3.25rem;
  --burger-line: 1.5px;
  --burger-gap: 0.3125rem;
  --logo-width: clamp(8rem, 6.75rem + 2.5vw, 10rem);
  --logo-mark-stop: 24.6%;
  --button-height-s: 2.375rem;
  --button-height: 3rem;
  --chevron-h: 0.56em;
  --chevron-gap: 0.11em; /* with --cursor-gap, the same ink gap either side of the headline, about 0.17em */
  --cursor-w: 0.34em;
  --cursor-h: 0.11em;
  --cursor-gap: 0.184em;
  --cursor-drop: -0.13em;
  --marker-w: 1.5rem;

  /* The struck lines */
  --stair: min(4.5rem, 6vw); /* how far each step of the staircase pushes a line left */
  --strike-weight: 1.85px; /* the cut's line, and half the gap a cut letter opens */
  --dur-strike: 720ms;
  --ease-strike: cubic-bezier(0.55, 0.05, 0.3, 1);

  /* Motion */
  --dur-fast: 160ms;
  --dur-tick: 420ms;
  --stagger-tick: 200ms;
  --dur-ground-drift: 48s;
  --type-char: 70ms;
  --type-fallback: 3s;
  --ease-out: cubic-bezier(0.22, 0.8, 0.24, 1);
  /* The menu: the panel slides in, then each item lands in turn, top first. */
  --dur-menu: 280ms;
  /* How long the dark spots take to spread when the menu opens. */
  --dur-spots-spread: 500ms;
  /* Closing plays the opening backwards, this much faster. */
  --menu-close-speed: 1.35;
  --dur-menu-item: 340ms;
  --menu-item-lead: 60ms;
  --menu-item-stagger: 40ms;
  --menu-item-travel: 200px;
  --menu-item-start-scale: 0.8;
}

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
/* The page stops at its ends: a trackpad or a phone does not pull it past them, so the moving
   background is never dragged along with the words. It never moves sideways
   either: nothing may be panned to, and there is no sideways bounce.
   The page also runs under a phone's clock and toolbar (viewport-fit=cover in each page's head),
   so the moving background fills the whole screen; the header keeps clear of the clock. */
html { -webkit-text-size-adjust: 100%; background: var(--color-ground); overscroll-behavior: none; overflow-x: clip; }
body { overscroll-behavior: none; }
/* The page scrolls freely everywhere, on every screen: nothing snaps and nothing takes the scroll
   over. Everything that moves follows from where
   things are on screen, so the page reads right wherever a scroll comes to rest. */
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }

/* The ground: our purple, with soft patches of a much darker purple drifting through it. Most
   of the screen stays our purple. Two layers, two patches each, on different slow clocks so the
   pattern never visibly repeats. They sit behind everything and never scroll. */
body::before, body::after {
  content: ""; position: fixed; inset: -25%; z-index: -1; pointer-events: none;
}
body::before {
  background:
    radial-gradient(40% 34% at 22% 26%, rgb(var(--shade) / 0.97) 0%, rgb(var(--shade) / 0.76) 20%, rgb(var(--shade) / 0.45) 42%, rgb(var(--shade) / 0.16) 68%, transparent 100%),
    radial-gradient(34% 42% at 80% 74%, rgb(var(--shade) / 0.94) 0%, rgb(var(--shade) / 0.73) 20%, rgb(var(--shade) / 0.43) 42%, rgb(var(--shade) / 0.16) 68%, transparent 100%);
}
body::after {
  background:
    radial-gradient(36% 28% at 72% 20%, rgb(var(--shade) / 0.9) 0%, rgb(var(--shade) / 0.7) 20%, rgb(var(--shade) / 0.41) 42%, rgb(var(--shade) / 0.15) 68%, transparent 100%),
    radial-gradient(42% 30% at 30% 82%, rgb(var(--shade) / 0.94) 0%, rgb(var(--shade) / 0.73) 20%, rgb(var(--shade) / 0.43) 42%, rgb(var(--shade) / 0.16) 68%, transparent 100%);
}
@media (prefers-reduced-motion: no-preference) {
  body::before { animation: ground-drift-one var(--dur-ground-drift) ease-in-out infinite alternate; }
  body::after { animation: ground-drift-two calc(var(--dur-ground-drift) * 1.37) ease-in-out infinite alternate; }
}
/* With script, the patches move to a small canvas that wanders them freely across the screen
   (script.js). These layers stay as the still version for anyone without script. */
.has-moving-ground body::before, .has-moving-ground body::after { display: none; }
/* The moving ground: fixed, as tall as the screen gets (a phone's address bar sliding never resizes
   it), and carrying the grain, so the grain is painted once on a layer that never scrolls rather
   than across the whole page, which Safari on a phone repainted as it scrolled. */
.ground-canvas { position: fixed; top: 0; left: 0; z-index: -1; width: 100%; height: 100%; height: 100lvh; pointer-events: none; background: var(--grain); }
/* On a phone Safari paints the strips behind the clock and behind its address bar one flat colour,
   the page's own (theme-color, --color-ground), and the dark patches running up to the page's edge
   met those strips in a hard line. On a touch screen the patches fade out
   near the top and the bottom, so the page reaches its edges in exactly that colour. */
@media (hover: none) and (pointer: coarse) {
  .ground-canvas {
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 14%, #000 86%, transparent 100%);
    mask-image: linear-gradient(to bottom, transparent 0, #000 14%, #000 86%, transparent 100%);
  }
}
.has-moving-ground body { background: none; }
/* Held still while the menu is open. The drift shows through the menu's soft edge, and kept
   the edge looking like it never settled. */
body:has(.nav-menu[open])::before, body:has(.nav-menu[open])::after { animation-play-state: paused; }
@keyframes ground-drift-one { to { transform: translate(7%, 5%) rotate(9deg) scale(1.08); } }
@keyframes ground-drift-two { to { transform: translate(-6%, -7%) rotate(-11deg) scale(1.12); } }
/* The body carries only a faint grain, which paints over the navy patches and breaks up the
   rings a soft gradient shows on colours this dark. The purple itself is on html. */
body {
  margin: 0;
  min-height: 100dvh;
  background: var(--grain);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}
h1, h2, h3, p, ul, ol { margin: 0; }
ul[role="list"], ol[role="list"] { list-style: none; padding: 0; }
img, svg { display: block; max-width: 100%; }
a { color: inherit; }

:focus-visible {
  outline: var(--rule) solid var(--color-violet-bright);
  outline-offset: var(--space-1);
  border-radius: var(--radius-s);
}

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

/* Out of sight, and out of the overscroll above the page, until a keyboard reaches it. */
.skip-link {
  position: absolute; left: var(--gutter); top: var(--space-2); z-index: 10;
  padding: var(--space-2) var(--space-4);
  background: var(--color-violet); color: var(--color-on-violet);
  font-family: var(--font-mono); font-size: var(--text-mono);
  transform: translateY(-200%); opacity: 0;
}
.skip-link:focus { transform: none; opacity: 1; }

.container { width: min(100% - 2 * var(--gutter), var(--container)); margin-inline: auto; }

.italic { font-style: italic; }
.line { display: block; }
.tm { font-size: 0.4em; vertical-align: 1.2em; font-style: normal; margin-left: 0.05em; }

/* ---------- Shared type ---------- */
.label {
  /* A small pill of soft violet, like the vibe coding checks. */
  display: flex; width: fit-content;
  margin-bottom: var(--space-5); padding: 0.35em 0.95em; border-radius: 999px;
  background: rgb(158 107 242 / 0.3); border: var(--hairline) solid rgb(158 107 242 / 0.55);
  font-family: var(--font-body); font-size: var(--text-body-s); font-weight: var(--weight-medium); line-height: var(--leading-snug);
  color: var(--color-text);
}

/* The lasers and what they etch (hero-graphic.js). It covers the screen and stays put while
   the page scrolls, behind everything on the page. */
.hero-graphic {
  position: fixed; top: 0; left: 0; z-index: -1; width: 100%; height: 100%; height: 100lvh; pointer-events: none;
  /* The headline covers the drawing as it scrolls up over it: everything from the top of the
     letters down is hidden, with a soft fade above them. hero-graphic.js keeps --cover at the
     letters' top as the page scrolls. */
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(var(--cover, 200vh) - var(--cover-fade)), transparent var(--cover, 200vh));
  mask-image: linear-gradient(to bottom, #000 calc(var(--cover, 200vh) - var(--cover-fade)), transparent var(--cover, 200vh));
}
/* When the mission line sits on the drawing, the drawing also fades away in a soft oval round
   the words, so nothing of the bridge runs through them. Both masks apply together. The oval
   fades in with the words (.is-cleared), not before. */
@property --clear-strength { syntax: "<number>"; inherits: false; initial-value: 0; }
.hero-graphic.has-clearing {
  transition: --clear-strength var(--dur-mission) var(--ease-out);
  -webkit-mask-image:
    radial-gradient(var(--clear-w) var(--clear-h) at var(--clear-x) var(--clear-y), rgb(0 0 0 / calc(1 - var(--clear-strength))) 45%, #000 100%),
    linear-gradient(to bottom, #000 calc(var(--cover, 200vh) - var(--cover-fade)), transparent var(--cover, 200vh));
  -webkit-mask-composite: source-in;
  mask-image:
    radial-gradient(var(--clear-w) var(--clear-h) at var(--clear-x) var(--clear-y), rgb(0 0 0 / calc(1 - var(--clear-strength))) 45%, #000 100%),
    linear-gradient(to bottom, #000 calc(var(--cover, 200vh) - var(--cover-fade)), transparent var(--cover, 200vh));
  mask-composite: intersect;
}
.hero-graphic.is-cleared { --clear-strength: 1; }
/* While a roadblock of the hero's opening passes over a little tower at the road's end, the drawing
   fades away under its words (hero-graphic.js moves the oval with them). */
.hero-graphic.has-road-clearing {
  /* The headline's cover, intersected with the union of the oval round the words and everything
     from the road line down, so the land line and the violet ground under it are never touched,
     only what stands above the road. Layers composite from the bottom up. */
  -webkit-mask-image:
    linear-gradient(to bottom, #000 calc(var(--cover, 200vh) - var(--cover-fade)), transparent var(--cover, 200vh)),
    linear-gradient(to bottom, transparent calc(var(--road-line, 0px)), #000 calc(var(--road-line, 0px) + 1px)),
    radial-gradient(var(--road-w) var(--road-h) at var(--road-x) var(--road-y), rgb(0 0 0 / calc(1 - var(--road-strength))) 55%, #000 100%);
  -webkit-mask-composite: source-in, source-over;
  mask-image:
    linear-gradient(to bottom, #000 calc(var(--cover, 200vh) - var(--cover-fade)), transparent var(--cover, 200vh)),
    linear-gradient(to bottom, transparent calc(var(--road-line, 0px)), #000 calc(var(--road-line, 0px) + 1px)),
    radial-gradient(var(--road-w) var(--road-h) at var(--road-x) var(--road-y), rgb(0 0 0 / calc(1 - var(--road-strength))) 55%, #000 100%);
  mask-composite: intersect, add;
  transition: --road-strength 260ms ease-out;
}
@property --road-strength { syntax: "<number>"; inherits: false; initial-value: 0; }
.hero-graphic.has-road-clearing.is-over-post { --road-strength: 1; }
.h2, .h3, .advantage-title, .final-title, .hero-title {
  font-family: var(--font-display); font-weight: var(--weight-regular);
}
.hero-title { position: relative; z-index: 1; }
/* Centred by what is seen, from the chevron's tip to the cursor's end: the cursor hangs past the
   line without taking room, and the chevron's ink starts a little inside its box, so the line
   centred as laid out sat 0.26em right of the middle. Moved back by that. */
.hero-title { translate: calc(-0.5 * (var(--cursor-w) + var(--cursor-gap)) - 0.029em) 0; }
/* While the hero's opening plays the prompt is hidden; it fades in where it types from (script.js). */
.hero-title .prompt-chevron { transition: opacity 450ms ease-out; }
.hero-title .cursor { transition: opacity 450ms ease-out; }
/* Hidden from the first paint, not once the script runs: set by the script, it flashed on load. */
.has-motion .hero-stage:has([data-hero-intro]) .hero-title:not(.is-prompt-shown) :is(.prompt-chevron, .cursor) { opacity: 0; }
.h2 {
  font-size: var(--text-display-m); line-height: var(--leading-display);
  letter-spacing: var(--tracking-display); text-wrap: balance; max-width: 16ch;
}
.h2-wide { max-width: 22ch; }
.h3 { font-size: var(--text-display-xs); line-height: var(--leading-snug); text-wrap: balance; }

.dash-list { display: grid; gap: var(--space-2); color: var(--color-text-muted); }
.dash-list li { display: grid; grid-template-columns: var(--marker-w) 1fr; }
/* Each point's bullet is a small outlined circle, centred on the first line. */
.dash-list li::before {
  content: ""; width: 0.4em; height: 0.4em; margin-top: calc(0.5lh - 0.2em + 0.04em);
  border: 1.5px solid; border-radius: 50%; color: var(--color-text-quiet); box-sizing: border-box;
}


/* ---------- Buttons and links ---------- */
.button {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-3);
  min-height: var(--button-height-s); padding-inline: var(--space-4);
  background: var(--color-violet); color: var(--color-on-violet);
  font-family: var(--font-body); font-size: var(--text-body-s); font-weight: var(--weight-medium);
  line-height: 1; text-decoration: none; white-space: nowrap;
  border-radius: var(--radius-s);
}
.button:hover { background: var(--color-violet-bright); }
.button-large { min-height: var(--button-height); padding-inline: var(--space-5); font-size: var(--text-body); }
.button-arrow { font-family: var(--font-mono); }

.text-link {
  color: var(--color-text); font-size: var(--text-body);
  text-decoration: underline; text-decoration-color: var(--color-line-strong);
  text-underline-offset: 0.3em; text-decoration-thickness: var(--hairline);
}
.text-link:hover { text-decoration-color: var(--color-violet); }
/* Small links get a finger-sized hit area without moving anything: padding out, margin back in. */
.text-link, .brand { display: inline-block; padding-block: 0.5rem; margin-block: -0.5rem; }

/* ---------- Header ---------- */
/* The logo and the menu stay at the top of the screen the whole way down the page. */
.site-header { position: sticky; top: 0; z-index: 10; padding-top: env(safe-area-inset-top); }
/* The logo and the menu's lines each wear a soft fade of the page's own colour, shrink-wrapped to
   their shapes, so words scrolling under them never clash with them directly.
   No CSS filter: on the logo, which is drawn through a mask, Safari painted a filter as a white box.
   The logo's fade is an image made from the logo itself (brand/agentsy-logo-glow.webp, padded 28% of
   the logo's width each side and 130% of its height), the lines' are soft shadows. Only in the
   header: nothing scrolls under the footer's logo, and its wider box stretched the glow into a smear. */
.site-header .brand { position: relative; display: inline-block; isolation: isolate; }
.site-header .brand::before {
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  inset: -129.6% -28%;
  background: url("brand/agentsy-logo-glow.webp") center / 100% 100% no-repeat;
}
/* Each line's fade sits behind all three lines: as a shadow on the line itself, each line's fade
   lay over the line above it, so the bottom line, with none over it, looked brighter. */
.burger { isolation: isolate; }
.burger span { position: relative; }
.burger span::before {
  content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit;
  box-shadow: 0 0 4px 1px rgb(79 22 147), 0 0 12px 4px rgb(79 22 147 / 0.9), 0 0 22px 6px rgb(79 22 147 / 0.6);
}
.header-row { display: flex; align-items: center; justify-content: space-between; min-height: var(--nav-height); padding-inline: var(--header-inset); }

.brand { text-decoration: none; }
.logo { display: block; width: var(--logo-width); }
.logo img { width: 100%; height: auto; }
/* The white logo is white all through. Paint it through its own shape so the >_ mark is violet. */
@supports ((mask-image: url("x.png")) or (-webkit-mask-image: url("x.png"))) {
  .logo {
    background: linear-gradient(90deg, var(--color-violet) var(--logo-mark-stop), var(--color-text) var(--logo-mark-stop));
    -webkit-mask: url("brand/agentsy-logo-white.webp") center / contain no-repeat;
    mask: url("brand/agentsy-logo-white.webp") center / contain no-repeat;
  }
  .logo img { opacity: 0; }
}

.menu-links a, .footer-links a {
  font-size: var(--text-body-s); color: var(--color-text-muted); text-decoration: none;
}
.menu-links a:hover, .footer-links a:hover { color: var(--color-text); }

/* One menu at every width: three wide lines on the right. */
.nav-menu summary { list-style: none; }
.nav-menu summary::-webkit-details-marker { display: none; }
.menu-button {
  display: inline-flex; align-items: center; justify-content: flex-end;
  min-width: var(--tap-target); min-height: var(--tap-target);
  cursor: pointer; color: var(--color-text);
}
.burger { display: grid; gap: var(--burger-gap); width: var(--burger-width); }
.burger span { display: block; height: var(--burger-line); background: currentColor; border-radius: var(--burger-line); }
.menu-button { position: relative; z-index: 3; }
.menu-button:hover, .nav-menu[open] .menu-button { color: var(--color-violet); }

/* Open: the page dims, and a full-height panel comes in from the right. Its left edge
   fades out into the dim rather than ending on a line. */
/* The page darkens in spots, not evenly: the same dark patches as the ground, laid over the
   page and spread wide. --spot-spread scales every patch at once. */
@property --spot-spread { syntax: "<number>"; inherits: false; initial-value: 1; }
.menu-dim {
  position: fixed; inset: 0; z-index: 1;
  --spot-spread: 2;
  background:
    radial-gradient(calc(30% * var(--spot-spread)) calc(26% * var(--spot-spread)) at 20% 25%, rgb(var(--shade) / 0.97) 0%, rgb(var(--shade) / 0.8) 25%, rgb(var(--shade) / 0.5) 50%, rgb(var(--shade) / 0.18) 75%, transparent 100%),
    radial-gradient(calc(26% * var(--spot-spread)) calc(32% * var(--spot-spread)) at 80% 72%, rgb(var(--shade) / 0.97) 0%, rgb(var(--shade) / 0.8) 25%, rgb(var(--shade) / 0.5) 50%, rgb(var(--shade) / 0.18) 75%, transparent 100%),
    radial-gradient(calc(28% * var(--spot-spread)) calc(22% * var(--spot-spread)) at 72% 18%, rgb(var(--shade) / 0.97) 0%, rgb(var(--shade) / 0.8) 25%, rgb(var(--shade) / 0.5) 50%, rgb(var(--shade) / 0.18) 75%, transparent 100%),
    radial-gradient(calc(32% * var(--spot-spread)) calc(24% * var(--spot-spread)) at 28% 82%, rgb(var(--shade) / 0.97) 0%, rgb(var(--shade) / 0.8) 25%, rgb(var(--shade) / 0.5) 50%, rgb(var(--shade) / 0.18) 75%, transparent 100%);
}
.menu-panel {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 2;
  width: var(--menu-width);
  display: flex; flex-direction: column; justify-content: flex-start;
  padding: calc(env(safe-area-inset-top) + var(--nav-height) + var(--space-7)) var(--header-inset) calc(env(safe-area-inset-bottom) + var(--space-7));
}
/* Right-aligned. The panel's right padding is the header's inset, so every item ends exactly
   where the burger's lines end. */
.menu-links { display: grid; gap: var(--space-3); justify-items: end; text-align: right; }
.menu-links li { transform-origin: 50% 50%; }
.menu-links a {
  font-family: var(--font-display); font-size: var(--text-menu); line-height: var(--leading-display);
  letter-spacing: var(--tracking-display); color: var(--color-text); text-decoration: none;
}
.menu-links a:hover { color: var(--color-violet-bright); }
.menu-links .menu-cta { color: var(--color-violet-bright); }
/* The page holds still while the menu is open. The lock is on html: on body it made body a scroll box
   of its own (html clips sideways), so the sticky header stuck to the top of the page instead of
   the screen and the button to close the menu went with it (2026-10-09). */
html:has(.nav-menu[open]) { overflow: hidden; }
/* Truly gone while closed. A closed details element only hides its content, so without this
   the panel's animations ran the first time it opened and never again. */
.nav-menu:not([open]) > :not(summary) { display: none; }

/* With script, the straight gradient edge gives way to a drawn one: irregular, feathered,
   and rippling down its length as the panel comes in. */

/* The menu's motion lives in script.js: one timeline drives the panel, the items, the spots
   and the edge, forwards to open and backwards to close. Without script the menu simply
   appears in its open state. */
.menu-links li { will-change: transform, opacity; }

/* ---------- Hero ---------- */
.hero { padding-block: 0; }
/* The first screen holds the headline and the mission line under it, centred and sitting at the
   bottom, with the drawing centred in the space above. The rest of the hero waits below. */
.hero-stage {
  position: relative;
  min-height: calc(100svh - var(--nav-height));
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  padding: 0 var(--gutter) var(--hero-stage-bottom); text-align: center;
}
.hero-text { display: flex; flex-direction: column; align-items: center; }
/* On a phone the bridge and the words under it are one group, centred on the screen under the
   header. The bridge stands on the words (hero-graphic.js), its top about 52% of the screen's width
   above them, so that much room is kept above the words and the rest is shared out evenly. */
@media (max-width: 639px) {
  .hero-stage { justify-content: center; padding-top: 52vw; padding-bottom: 0; }
}
/* The hero's opening (hero-graphic.js): a question in the sky above the land, and roadblocks that
   ride the road down into the gap. Only with motion, and only until the headline types. */
.hero-intro { display: none; }
.has-motion .hero-intro { display: block; }
.hero-roadblocks { display: none; } /* read by hero-graphic.js, which sets each on the road */
/* The opening question is fixed on screen like the drawing, so it stays over the bridge as the page
   scrolls, and the headline covers it as it covers the drawing (hero-graphic.js sets --cover-here). */
.hero-question {
  /* The padding holds the letters' tails inside the box: a mask clips to the box, and at this
     tight line height the tails of g and y hang below it and were cut off. The bottom padding is
     taken back off the shift up, so the words sit where they did. */
  position: fixed; left: 50%; top: var(--question-y, 30%); translate: -50% calc(-100% + 0.3em); z-index: 1;
  padding: 0.2em 0 0.3em;
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(var(--cover-here, 200vh) - var(--cover-fade)), transparent var(--cover-here, 200vh));
  mask-image: linear-gradient(to bottom, #000 calc(var(--cover-here, 200vh) - var(--cover-fade)), transparent var(--cover-here, 200vh));
  width: max-content; max-width: calc(100vw - 2 * var(--gutter)); margin: 0;
  font-family: var(--font-display); font-size: var(--text-display-m); line-height: var(--leading-display);
  text-align: center; text-wrap: balance; pointer-events: none;
  opacity: 0; transition: opacity 700ms var(--ease-out);
}
.hero-question.is-shown { opacity: 1; }
.hero-road { position: fixed; top: 0; left: 0; z-index: -1; overflow: visible; pointer-events: none; will-change: transform; } /* sized to the road by hero-graphic.js */
.hero-road text { font-family: var(--font-body); font-size: clamp(1.1rem, 0.7rem + 1.3vw, 2rem); font-weight: var(--weight-medium); fill: var(--color-text); }
.hero-mission {
  position: relative; z-index: 1;
  margin-top: var(--space-5); max-width: 22ch;
  font-size: max(1rem, calc(var(--hero-size) * 0.235)); font-weight: var(--weight-semibold); line-height: var(--leading-snug);
  letter-spacing: -0.01em; color: var(--color-text); text-wrap: balance;
}
.hero-mission-key { color: var(--color-highlight); }
/* A quiet way in for anyone already sure: it shows with the mission line. */
.hero-cta { position: relative; z-index: 1; margin-top: var(--space-4); font-size: var(--text-body); }
.has-motion .hero-cta { opacity: 0; transition: opacity 900ms var(--ease-out) 600ms; }
.has-motion .hero-mission.is-drawn ~ .hero-cta { opacity: 1; }
/* On a scene that asks for it, the mission line sits on the drawing: centred on the spot the
   scene gives, with its last line resting just above the road there. */
.hero-mission.is-on-scene {
  position: absolute; margin: 0; width: max-content; max-width: min(90vw, 22ch);
  left: var(--mission-x); bottom: auto; top: var(--mission-bottom);
  transform: translate(-50%, -100%);
}

/* The headline is as big as the type scale says, but never wider than the screen: its line, from the
   chevron to the cursor, is about 5.9 of its own size wide, so it is set at a 6.2th of the room. The mission line keeps the same share of
   it at every width (--hero-size). */
.hero-stage { --hero-size: min(var(--text-display-xl), calc((100vw - 2 * var(--gutter)) / 6.2)); }
.hero-title {
  font-size: var(--hero-size); line-height: var(--leading-hero);
  letter-spacing: var(--tracking-hero); text-wrap: balance;
}
.prompt-chevron {
  display: inline-block; vertical-align: 0.02em;
  height: var(--chevron-h); width: calc(var(--chevron-h) * 125 / 196);
  margin-right: var(--chevron-gap);
  fill: none; stroke: var(--color-violet); stroke-linejoin: round;
}
.cursor {
  display: inline-block; vertical-align: var(--cursor-drop);
  width: var(--cursor-w); height: var(--cursor-h);
  margin-left: var(--cursor-gap);
  margin-right: calc(-1 * (var(--cursor-w) + var(--cursor-gap)));
  background: var(--color-violet);
}
.hero-words .word { white-space: nowrap; }
.type-rest { visibility: hidden; }

.hero-lede { font-size: var(--text-body-l); line-height: var(--leading-snug); max-width: 24ch; text-wrap: pretty; }
/* ---------- The chunks after the hero ---------- */
/* Each chunk is one page: one screen, plus any extra scroll it holds still for (--chunk-hold).
   script.js fades and lifts each one in as it arrives and out as it leaves. */
.chunk { position: relative; height: calc(100svh + var(--chunk-hold)); }
/* The tree holds still for most of a screen of scroll, so it has time to grow and bring in its
   places before it can be scrolled past. */
.idea-tree, .what-we-do { --chunk-hold: 75svh; }
.chunk-stage { position: sticky; top: 0; height: 100svh; display: flex; align-items: center; }
/* Scroll-driven motion (script.js writes the keyframes): each chunk's words, drawing and ladder
   follow the chunk's own passage through the screen, in step with the scroll. */
.chunk { view-timeline-name: --chunk; view-timeline-axis: block; }
.has-scroll-timeline .chunk :is(.chunk-body, .chunk-art, .chunk-ladder, .chunk-foot) {
  animation: var(--chunk-motion, chunk-scroll) linear both;
  animation-timeline: --chunk;
  animation-range: cover 0% cover 100%;
}
.chunk-body { display: grid; justify-items: center; gap: var(--space-5); text-align: center; position: relative; z-index: 1; }
/* A chunk with an etched drawing (chunk-etching.js), behind everything. With data-place="below"
   the words sit high on the screen and the drawing fills the space below them. */
.chunk-art { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; }
.chunk[data-place="below"] .chunk-stage { align-items: flex-start; }
.chunk[data-place="below"] .chunk-body { padding-top: clamp(4rem, 12vh, 8rem); }
/* The places, stacked over the tree (chunk-etching.js places each line): shortest at the top,
   longest at the bottom. */
.chunk-ladder { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.place-stack.is-stacked { display: block; margin: 0; }
.place-stack.is-stacked > li {
  position: absolute; width: max-content;
  font-size: var(--text-body-l); color: var(--color-text);
}
/* Behind the stack the drawing fades out in a soft rounded hole round each line (--stack-hole,
   from chunk-etching.js), so the tree's lines never run through the words and the real background,
   drifting patches and all, shows behind them. It fades in as the lines rise (.is-cleared): the
   second, solid layer covers the holes and fades away. */
@property --stack-clear { syntax: "<number>"; inherits: false; initial-value: 0; }
.chunk-art.has-stack {
  --stack-clear: 0;
  transition: --stack-clear 1400ms var(--ease-out);
  -webkit-mask-image: var(--stack-hole), linear-gradient(rgb(0 0 0 / calc(1 - var(--stack-clear))) 0 0);
  mask-image: var(--stack-hole), linear-gradient(rgb(0 0 0 / calc(1 - var(--stack-clear))) 0 0);
  -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
}
.chunk-art.has-stack.is-cleared { --stack-clear: 1; }
/* Once the tree is drawn, each rises from the foot of the tree (--rise) into its place, fading in,
   one at a time. At the end of the cycle each fades where it is, then drops back down unseen. */
.has-motion .place-stack.is-stacked > li {
  opacity: 0; translate: 0 var(--rise, 0px);
  transition: opacity 500ms var(--ease-out), translate 0s 500ms;
}
.has-motion .place-stack.is-stacked > li.is-shown {
  opacity: 1; translate: 0 0;
  transition: opacity 1100ms cubic-bezier(0.33, 0, 0.2, 1), translate 1400ms cubic-bezier(0.25, 0.6, 0.2, 1);
}
/* Each line's bullet: a small filled leaf. */
.leaf-bullet { display: inline-block; width: 1.05em; height: 0.55em; margin-right: 0.45em; vertical-align: 0.12em; rotate: -24deg; }
/* Two leaves to a bullet (area-leaves.js), joined at the bottom left: a square, no turn of its own. */
#services .leaf-bullet { width: 1.15em; height: 1.15em; vertical-align: -0.12em; rotate: none; }
.leaf-bullet svg { display: block; width: 100%; height: 100%; overflow: visible; }
.leaf-bullet path { fill: color-mix(in srgb, var(--color-ground) 66%, var(--color-violet)); stroke: var(--color-violet); stroke-width: 1.3; stroke-linejoin: round; }
.chunk-title {
  font-family: var(--font-display); font-weight: var(--weight-regular);
  font-size: var(--text-statement); line-height: var(--leading-display);
  letter-spacing: var(--tracking-display); text-wrap: balance;
}
.chunk-text {
  font-size: var(--text-mission); line-height: var(--leading-snug);
  max-width: 30ch; text-wrap: balance; color: var(--color-text);
}
.chunk-key { color: var(--color-highlight); font-weight: var(--weight-semibold); }
/* Inside the ring the words are set a size smaller and narrower, so they sit inside a true
   circle on any screen. */
.what-we-do .chunk-title { font-size: var(--text-display-m); max-width: 11ch; }
.what-we-do .chunk-text { font-size: var(--text-body-l); max-width: 28ch; }
/* On a phone the words inside the ring are narrower and the two links stack, so the ring can sit
   closer round them; and the ring fades out at the screen's edges instead of being cut off. */
@media (max-width: 639px) {
  .what-we-do .chunk-text { font-size: var(--text-body); max-width: 24ch; }
  .what-we-do .cta-row { flex-direction: column; gap: var(--space-3); }
  .what-we-do .chunk-art {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 16%, #000 84%, transparent);
    mask-image: linear-gradient(to right, transparent, #000 16%, #000 84%, transparent);
  }
}
@media (max-height: 820px) and (min-width: 640px) {
  .what-we-do .chunk-title { font-size: var(--text-display-s); }
  .what-we-do .chunk-text { font-size: var(--text-body); }
  .what-we-do .chunk-difference { font-size: var(--text-body-l); }
  .what-we-do .chunk-body { gap: var(--space-4); }
}
.chunk-difference {
  margin-top: var(--space-2);
  font-family: var(--font-display); font-size: var(--text-display-xs); line-height: var(--leading-snug);
}
/* The close of the home page, at the foot of the last page: shown once its lines are in. */
.chunk-foot {
  position: absolute; left: 0; right: 0; bottom: var(--chunk-foot-bottom); z-index: 1;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--space-3) var(--space-6);
  padding-inline: var(--gutter);
}
.chunk-foot .hero-tagline { margin: 0; }
/* The tree page's sentence, in two halves: "From the first idea" under the trunk, and "to something
   people actually use." above the crown, shown once the tree has grown up to it. */
.idea-line {
  font-family: var(--font-display); font-size: var(--text-display-s); line-height: var(--leading-display);
  letter-spacing: var(--tracking-display); text-align: center; text-wrap: balance; max-width: 22ch;
}
.idea-from, .idea-to { font-style: italic; }
.idea-key { color: var(--color-highlight); }
/* A lazy fade: slow to arrive, drifting up a little as it comes. */
.has-motion [data-crown-line] { opacity: 0; translate: 0 8px; transition: opacity 2400ms cubic-bezier(0.45, 0, 0.25, 1), translate 2400ms cubic-bezier(0.45, 0, 0.25, 1); }
.has-motion [data-crown-line].is-shown { opacity: 1; translate: 0 0; }
/* Its contents fade, not the close itself: the page turn already moves and fades the close. */
.has-motion .chunk-foot > * { opacity: 0; translate: 0 10px; transition: opacity 800ms var(--ease-out), translate 800ms var(--ease-out); }
.has-motion .chunk-foot.is-shown > * { opacity: 1; translate: 0 0; }
/* Without script, the list sits under the line above. */
.place-stack:not(.is-stacked) > li { font-size: var(--text-body); }
.chunk .cta-row { justify-content: center; }
.place-stack {
  display: grid; justify-items: center; gap: var(--space-3) var(--space-7); margin-top: var(--space-3);
  font-size: var(--text-mission); line-height: var(--leading-snug); color: var(--color-text-muted);
}
.hero-side { display: grid; gap: var(--space-5); max-width: var(--measure); }
.hero-tagline { font-family: var(--font-display); font-size: var(--text-display-xs); line-height: var(--leading-snug); }
.cta-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-5); margin-top: var(--space-2); }

@media (min-width: 56rem) {
  .place-stack { grid-template-columns: 1fr 1fr; }
}

/* ---------- Sections ---------- */
/* The longer sections between and after the drawn screens. No rules between them: the ground
   runs on under the whole page, and space alone separates one from the next. */
.section { padding-block: var(--space-section); scroll-margin-top: var(--nav-height); }
/* A hairline across the top of a home section, as wide as the text, the same line that parts the
   statements in Why now. The first four screens run into each other and have none. */
.is-divided { position: relative; }
.is-divided::before {
  content: ""; position: absolute; top: 0; left: 50%; translate: -50% 0;
  width: min(100% - 2 * var(--gutter), var(--container)); height: var(--hairline);
  background: var(--color-line);
}
.flow-narrow { display: grid; gap: var(--space-7); justify-items: center; text-align: center; max-width: var(--measure-wide); }
.flow-narrow .places { justify-content: center; }

/* Each part of a section rises and fades in as it scrolls onto the screen, in step with the scroll.
   Where the browser cannot tie motion to the scroll, everything simply shows. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* The pipeline does not rise or fade: its rows got stuck part faded in Safari (2026-10-08), and its
       rope (pipeline-rope.js) already moves. The team cards and the article list
       don't fade either: on a phone they sit half faded below the first screen, and checkers read that as
       text too faint to read. */
    .flow .container > :not(.areas, .pipeline, .vibe-hold, .service-list, .case-rope, .team-grid, .insight-list),
    .flow :is(.areas, .vibe-stage, .service-list) > *,
    .full-screen .container > :not(.final-action), .full-screen :is(.advantage-premise, .advantage-loop) > * {
      animation: flow-rise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 70%;
    }
    /* A supporting page's closing words arrive together, as one group, measured from the group
       entering: one at a time, the line and the button under the title were still missing while
       the title showed. */
    .subpage-cta .container { view-timeline-name: --cta; }
    .subpage-cta.full-screen .container > * { animation-timeline: --cta; animation-range: entry 0% entry 85%; }
  }
}

/* "scary", in "AI isn't scary.", trembles as if it is scared, without a pause. It shifts and tilts
   on two short loops of different lengths, so the shake never quite repeats. */
.scary-word { display: inline-block; transform-origin: 50% 85%; }
@media (prefers-reduced-motion: no-preference) {
  .scary-word { animation: scared-shift 0.29s linear infinite, scared-tilt 0.37s linear infinite; }
}
@keyframes scared-shift {
  0%, 100% { translate: 0 0; }
  20% { translate: -0.022em 0.008em; }
  40% { translate: 0.018em -0.006em; }
  60% { translate: -0.012em -0.008em; }
  80% { translate: 0.022em 0.006em; }
}
@keyframes scared-tilt {
  0%, 100% { rotate: 0deg; }
  25% { rotate: 1.4deg; }
  50% { rotate: -1.1deg; }
  75% { rotate: 1deg; }
}
@keyframes flow-rise { from { opacity: 0; translate: 0 2.5rem; } }
@keyframes flow-leave { to { opacity: 0; translate: 0 -1rem; } }

/* The Advantage and the close each take at least a whole screen, words in the middle. */
.full-screen { min-height: 100svh; display: grid; align-content: center; padding-block: calc(var(--nav-height) + var(--space-7)) var(--space-8); }

.split { display: grid; gap: var(--space-7); }
.split-body { display: grid; gap: var(--space-7); align-content: start; }
@media (min-width: 64rem) {
  .split { grid-template-columns: 5fr 7fr; gap: var(--space-8); }
}

/* What we do: a diff */
.diff { display: grid; gap: var(--space-3); font-size: var(--text-body-l); line-height: var(--leading-snug); }
.diff-line { display: grid; grid-template-columns: var(--marker-w) 1fr; }
.diff-mark { font-family: var(--font-mono); }
.is-removed { color: var(--color-text-quiet); }
/* Without the script, the strike is a red line drawn as a background, one per line of a wrapped
   sentence (clone). With it, script.js cuts each sentence through: the dash runs
   out as a rounded red line with a socket over each end (.cut-lines), and each letter (.cut) parts
   along the line as it passes, its top half lifting and its bottom half dropping. */
.is-removed .diff-text:not(.is-split) {
  background: linear-gradient(var(--color-red), var(--color-red)) no-repeat 0 58% / 100% var(--strike-weight);
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}
[data-strikes] .is-removed { position: relative; }
.is-removed .diff-mark { transition: color 160ms ease-out; }
.is-removed .diff-mark.is-red { color: var(--color-red); }
.is-removed .diff-mark.is-taken { color: transparent; }
.cut-word { white-space: nowrap; }
.cut { display: inline-block; position: relative; color: transparent; }
.cut::before, .cut::after {
  content: attr(data-l); position: absolute; inset: 0; color: var(--color-text-quiet);
  transition: translate 260ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
/* Each half is masked at the cut. Whole, the two meet edge to edge; once cut, each new edge fades
   over a couple of pixels, so it looks cut rather than clipped. */
.cut { --edge-fade: 0px; }
.cut.is-cut { --edge-fade: 2px; }
.cut::before {
  -webkit-mask-image: linear-gradient(#000 calc(var(--cut, 58%) - var(--edge-fade)), transparent var(--cut, 58%));
  mask-image: linear-gradient(#000 calc(var(--cut, 58%) - var(--edge-fade)), transparent var(--cut, 58%));
}
.cut::after {
  -webkit-mask-image: linear-gradient(transparent var(--cut, 58%), #000 calc(var(--cut, 58%) + var(--edge-fade)));
  mask-image: linear-gradient(transparent var(--cut, 58%), #000 calc(var(--cut, 58%) + var(--edge-fade)));
}
.cut.is-cut::before { translate: 0 calc(-2 * var(--strike-weight)); }
.cut.is-cut::after { translate: 0 calc(2 * var(--strike-weight)); }
.cut-lines { position: absolute; left: 0; top: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.cut-lines path { fill: none; stroke: var(--color-red); stroke-linecap: round; stroke-linejoin: round; }
/* The three old ways wait in a staircase, the top one pushed furthest left. Once the page has
   settled, each strike in turn draws across its line from the left, and the line moves with it
   into its place (script.js adds .is-struck). */
@media (prefers-reduced-motion: no-preference) {
  .has-motion [data-strikes] .is-removed {
    translate: calc(-1 * var(--step, 0) * var(--stair)) 0;
    transition: translate var(--dur-strike) var(--ease-strike);
  }
  .has-motion [data-strikes] .is-removed.is-struck { translate: 0 0; }
}
.is-added { color: var(--color-text); margin-top: var(--space-3); }
/* What it is instead, in the light pill under the three old ways: its words centred, the pill set
   well clear of the list. */
.diff-pill {
  width: fit-content; max-width: min(100%, 34rem); margin: var(--space-7) auto 0; padding: 1.4em 2.4em;
  color: var(--color-text); font-size: var(--text-body-l); line-height: var(--leading-snug); text-align: center; text-wrap: balance;
  background: rgb(205 172 255 / 0.16); border-radius: var(--vibe-round, 3.5rem);
}
/* The three old ways, as one block as wide as its longest line, centred under the title like the pill
   below them: each line still starts at the block's left. */
[data-strikes].diff { width: fit-content; max-width: 100%; margin-inline: auto; }

.places { display: flex; flex-wrap: wrap; gap: var(--space-2); }
/* A soft violet fill, with no outline. */
.places li {
  padding: var(--space-1) var(--space-3);
  font-family: var(--font-mono); font-size: var(--text-mono);
  border-radius: var(--radius-s); background: rgb(158 107 242 / 0.5);
}
.closing-line { font-family: var(--font-display); font-style: italic; font-size: var(--text-display-xs); line-height: var(--leading-snug); }

/* What that can look like: a ruled table */
/* What that can look like: four boxes apart, slightly rounded, each a steady deep purple; purple
   titles over white points. */
.areas { display: grid; gap: var(--space-4); margin-top: var(--space-8); }
.area {
  display: grid; gap: var(--space-5); align-content: start; padding: var(--space-6);
  background: var(--color-deep); border-radius: var(--radius-l);
  scroll-margin-top: calc(var(--nav-height) + var(--space-5));
}
.area .h3 { color: var(--color-highlight); }
.area .dash-list { color: var(--color-text); }
.area .dash-list li::before { color: var(--color-text); }
.area .h3 .leaf-bullet { margin-right: 0.5em; }
/* The leaves that fall onto "AI where it matters" (area-leaves.js): drawn over the page, under the
   header, and never in the way of a tap. */
.falling-leaves { position: fixed; left: 0; top: 0; width: 100%; height: 100lvh; z-index: 9; pointer-events: none; }
@media (min-width: 48rem) {
  .areas { grid-template-columns: 1fr 1fr; } .area { padding: var(--space-7); }
  /* Five boxes in two columns: the odd one out spans both, so no gap is left beside it. */
  .area:last-child:nth-child(odd) { grid-column: 1 / -1; }
}

/* "Low risk. By design.": four plain points under a heading, two across on a wide screen. */
.low-risk-list { display: grid; gap: var(--space-4); margin-top: var(--space-6); max-width: var(--measure); color: var(--color-text); font-size: var(--text-body-l); line-height: var(--leading-snug); }
@media (min-width: 48rem) { .low-risk-list { grid-template-columns: 1fr 1fr; gap: var(--space-5) var(--space-8); max-width: none; } }

/* Why now: two statements */
.statement { display: grid; gap: var(--space-6); }
/* The line between two statements gets a section's own space on each side, like the line between
   sections. */
.statement + .statement {
  /* A little less above the line than the section's space, since the words above end on a body
     line whose box runs a little below its letters, where a heading's top does not. */
  margin-top: calc(var(--space-section) - 0.18 * var(--text-display-m));
  padding-top: var(--space-section); border-top: var(--hairline) solid var(--color-line);
}
.statement-body { display: grid; gap: var(--space-3); max-width: var(--measure); color: var(--color-text-muted); font-size: var(--text-body-l); line-height: var(--leading-snug); }
/* The dark box the four in AI where it matters wear, for other blocks to wear too: "AI is changing
   what small teams can achieve" and "Keep the people. Lose the busywork.", their words white. */
.dark-box { max-width: none; padding: var(--space-6); background: var(--color-deep); border-radius: var(--radius-l); color: var(--color-text); }
@media (min-width: 48rem) { .dark-box { padding: var(--space-7); } }
@media (min-width: 64rem) { .statement:has(.dark-box) { grid-template-columns: 7fr 5fr; } }
.statement-end { color: var(--color-text); }
/* The three models: a band round a ring, the words curved along it between two hairlines, each
   word on its own shade of purple. The whole band turns slowly, clockwise. */
.model-ring { width: clamp(14rem, 12rem + 8vw, 19rem); margin-block: var(--space-4); }
.model-ring svg { width: 100%; height: auto; overflow: visible; }
.model-ring-edge { fill: none; stroke: var(--color-line-strong); stroke-width: 1; }
/* Each of the band's three segments, one model each, in its own shade of purple. */
.model-ring-segment-1 { fill: #3e1672; }
.model-ring-segment-2 { fill: #5b2a9d; }
.model-ring-segment-3 { fill: #7a43c8; }
/* A phrase picked out in the logo's purple, light enough to read at body size. */
.say-key { color: var(--color-highlight); }
/* Words set in purple are also bold, wherever they are. The serif has no bold
   of its own, so the browser thickens it. */
:is(.say-key, .idea-key, .chunk-key, .hero-mission-key, .area .h3, .menu-cta, .step-num, .case-link) { font-weight: var(--weight-semibold); }
.model-ring text { font-family: var(--font-mono); font-size: 22px; font-weight: var(--weight-medium); letter-spacing: 0.16em; fill: var(--color-text); }
.model-ring-turn { transform-box: view-box; transform-origin: 50% 50%; }
@media (prefers-reduced-motion: no-preference) {
  .model-ring-turn { animation: model-ring-turn 48s linear infinite; }
}
@keyframes model-ring-turn { to { rotate: 360deg; } }
/* A stacked list: green, beside a line drawn like the cut-through (script.js): rounded ends, each in
   a small open socket. The line is ::before; the two sockets are ::after. */
ul.stacked {
  --socket: 5px; --rule: var(--strike-weight);
  position: relative; display: grid; gap: var(--space-1); margin-block: var(--space-4); padding-left: var(--space-4);
  color: var(--color-green);
}
ul.stacked::before {
  content: ""; position: absolute; left: calc(var(--rule) / -2); top: calc(var(--socket) + 2px - var(--rule) / 2); bottom: calc(var(--socket) + 2px - var(--rule) / 2);
  width: var(--rule); border-radius: 999px; background: currentColor;
}
ul.stacked::after {
  content: ""; position: absolute; left: -7px; top: 0; bottom: 0; width: 14px; background: currentColor;
  --top: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 8'%3E%3Cpath d='M2 7A5 5 0 0 1 12 7' fill='none' stroke='%23000' stroke-width='1.85' stroke-linecap='round'/%3E%3C/svg%3E");
  --bottom: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 8'%3E%3Cpath d='M2 1A5 5 0 0 0 12 1' fill='none' stroke='%23000' stroke-width='1.85' stroke-linecap='round'/%3E%3C/svg%3E");
  -webkit-mask: var(--top) center top / 14px 8px no-repeat, var(--bottom) center bottom / 14px 8px no-repeat;
  mask: var(--top) center top / 14px 8px no-repeat, var(--bottom) center bottom / 14px 8px no-repeat;
}
@media (min-width: 64rem) {
  /* The words beside a statement's title sit level with its middle; where they are much taller
     than the title (Why now's ring and its dark box), they start level with its top. */
  .statement { grid-template-columns: 1fr 1fr; gap: var(--space-8); align-items: center; }
  .statement:has(.model-ring, .dark-box) { align-items: start; }
  /* Beside a form, the title starts level with the form's top; as it reaches the top of the screen
     it rides down with the page, until its foot is level with the foot of the form's button. */
  .statement:has(.contact-form) { align-items: start; }
  .statement:has(.contact-form) .statement-head {
    position: sticky; top: calc(var(--nav-height) + env(safe-area-inset-top) + var(--space-6));
  }
}

/* People */
.people-grid { display: grid; gap: var(--space-8); margin-top: var(--space-8); }
.people-list { font-size: var(--text-body-l); line-height: var(--leading-snug); gap: var(--space-3); max-width: var(--measure); }
.punchline { font-family: var(--font-display); font-size: var(--text-display-s); line-height: var(--leading-display); }
/* "busywork": the red word over a faint white copy of itself. The red turns to dust and blows away
   down and to the right, leaving the faint copy, then comes back (busywork-dust.js). */
.dust-word { position: relative; display: inline-block; color: var(--color-red); }
/* Only the word turns to dust; the full stop after it is in the line's own white. */
.keep-word { color: var(--color-green); }
/* Behind the word, the same word in a near-invisible white: hidden under the red, and left behind
   when the red turns to dust. Being the same text, it sits exactly where the red was. */
.dust-ghost { position: absolute; left: 0; top: 0; white-space: nowrap; color: rgb(255 255 255 / 0.1); }
.dust-fill { position: relative; z-index: 1; white-space: nowrap; }
.dust-layers { position: absolute; left: 0; top: 0; z-index: 2; pointer-events: none; }
.dust-layers[hidden] { display: none; }
.dust-layers canvas { position: absolute; left: 0; top: 0; will-change: transform, opacity; }
@media (min-width: 64rem) { .people-grid { grid-template-columns: 7fr 5fr; align-items: end; } }
/* In one column, as on a phone, the pill sits in the middle of the screen. */
@media (max-width: 63.99rem) { .people-grid .punchline { justify-self: center; } }

/* Vibe coding: a drawing (vibe-code.js) of two boxes, the heap and the finished code, as wide as
   the wider half of the title. On a wide screen "From vibe coded..." sits over the heap and "...to
   business critical." over the finished code; under the heap, "Vibe coding changed the starting
   line" and its three lines; under the finished code, "Agentsy helps take..." and its checks; and
   "We don't want to slow down experimentation" under both, in the middle. vibe-code.js sets
   --vibe-box to the boxes' width and --vibe-round to their corners' radius. */
.vibe-stage { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-5); }
/* Like the tree, the drawing holds still on screen while the page scrolls on for most of a screen
   more, then carries on. vibe-code.js sets --vibe-top: the middle of the screen if it fits there. */
.vibe-hold::after { content: ""; display: block; height: 75svh; }
.vibe-stage { position: sticky; top: var(--vibe-top, calc(var(--nav-height) + var(--space-4))); }
.vibe-stage > :not(.vibe-art) { position: relative; z-index: 1; }
.vibe-stage-title { grid-row: 1; }
.vibe-title-part { display: block; }
.vibe-art { grid-row: 2; position: relative; aspect-ratio: 3.2 / 1; margin-block: var(--space-5); }
.vibe-art canvas { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; }
.vibe-before { grid-row: 3; display: grid; gap: var(--space-6); align-content: start; }
.build-after { grid-row: 4; display: grid; gap: var(--space-6); align-content: start; }
.build-before { display: grid; gap: var(--space-1); color: var(--color-text); font-size: var(--text-body-l); line-height: var(--leading-snug); }
/* Sized in ems from --checks-size, so on a wide screen vibe-code.js can grow the type until the
   first row spans the box above exactly, and the pills and gaps grow with it. */
.build-after .checks { display: flex; flex-wrap: wrap; gap: 0.55em; font-size: var(--checks-size, var(--text-body-l)); }
/* The light purple pill: a closing line sits on it, its corners as round as the vibe coding boxes
   (vibe-code.js sets --vibe-round there; elsewhere it is about the same). */
.light-pill {
  width: fit-content; padding: var(--space-5) var(--space-7);
  background: rgb(205 172 255 / 0.16); border-radius: var(--vibe-round, 3.5rem);
}
/* Each point is a pill of soft violet with a plain white tick, still: they do not tick in. */
.build-after .check {
  font-family: var(--font-body); font-size: 1em; line-height: var(--leading-snug); gap: 0.4em;
  padding: 0.4em 0.8em 0.4em 0.6em; border-radius: 999px;
  background: rgb(158 107 242 / 0.3); border: var(--hairline) solid rgb(158 107 242 / 0.55);
}
.build-after .check-box { width: 1.05em; height: 1.05em; background: none; border: 0; }
.build-after .check-box svg { stroke: #fff; }
/* On a phone the drawing is wide and short, so its two boxes are not mostly empty, and it reaches
   to within a small margin of the screen's sides. vibe-code.js makes the lane between the boxes
   that same margin. */
@media (max-width: 639px) {
  /* Taller than wide enough for two boxes overlapping by their corners' radius, the right one that
     much lower (vibe-code.js), each about a third taller than it is wide. */
  .vibe-art { --vibe-edge: 0.75rem; aspect-ratio: 1.23 / 1; margin-inline: calc(50% - 50vw + var(--vibe-edge)); }
  /* The section is taller than a phone's screen, so it does not hold still: it simply scrolls. */
  .vibe-stage { position: static; }
  .vibe-hold::after { display: none; }
}
@media (min-width: 64rem) {
  .vibe-stage { grid-template-columns: var(--vibe-box, 40%) 1fr var(--vibe-box, 40%); }
  /* The title shares the drawing's columns, each half over its own box. */
  .vibe-stage-title { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; align-items: end; max-width: none; }
  .vibe-title-part { text-align: center; }
  .vibe-title-part:last-child { grid-column: 3; }
  .vibe-art { grid-column: 1 / -1; }
  /* Each group of words is centred under its own box, and the last two lines under both. */
  .vibe-before { grid-column: 1; grid-row: 3; }
  .build-after { grid-column: 3; grid-row: 3; }
  .vibe-before, .build-after { justify-items: center; text-align: center; }
  .build-after .checks { justify-content: center; }
}
}

.checks { display: grid; gap: var(--space-3); }
.check { display: flex; align-items: center; gap: var(--space-4); font-family: var(--font-display); font-size: var(--text-display-s); line-height: var(--leading-display); }
.check-box {
  flex: none; display: grid; place-items: center;
  width: var(--check-box); height: var(--check-box);
  background: var(--color-violet); border: var(--hairline) solid var(--color-violet); border-radius: var(--radius-s);
}
.check-box svg { width: 100%; height: 100%; fill: none; stroke: var(--color-on-violet); stroke-width: var(--rule); stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1; stroke-dashoffset: 0; }

/* Process: a pipeline. Each step has an outlined violet circle, with its number and title on the
   same middle; on a wide screen everything in a row is centred on the row's middle. A line, as
   thick as the circles' outline, joins each circle to the next: each row draws its own halves,
   down from its top to just short of its circle and on from just past it to its bottom, so the
   line meets itself at the rows' edges wherever the circles sit, and is rounded where it stops
   short of a circle. The lines between rows start at the numbers, clear of the circles. */
.pipeline {
  --pipe: 3px; /* the line, and each circle's outline */
  --dot: 1.25rem;
  --dot-gap: 0.375rem; /* between a circle and the line that leaves or reaches it */
  --step-pad: var(--space-5);
  --step-indent: calc(var(--dot) + var(--space-6));
  --title-line: calc(var(--text-display-xs) * var(--leading-snug));
  position: relative; margin-top: var(--space-8);
}
/* pipeline-rope.js draws the line and circles as a rope instead, and rings it now and then. */
.list-rope { position: absolute; top: 0; pointer-events: none; }
.has-rope .step::before, .has-rope .step::after, .has-rope .step-head::before { visibility: hidden; }
.step {
  /* Where the middle of the circle sits: on the title's first line, or, on a wide screen, halfway
     down the row. */
  --dot-y: calc(var(--step-pad) + var(--title-line) / 2);
  --rule: linear-gradient(var(--color-line), var(--color-line));
  position: relative; display: grid; gap: var(--space-3);
  padding: var(--step-pad) 0 var(--step-pad) var(--step-indent);
  background: var(--rule) right top / calc(100% - var(--step-indent)) var(--hairline) no-repeat;
}
.step:last-of-type {
  background:
    var(--rule) right top / calc(100% - var(--step-indent)) var(--hairline) no-repeat,
    var(--rule) right bottom / calc(100% - var(--step-indent)) var(--hairline) no-repeat;
}
.step::before {
  content: ""; position: absolute; left: 0; top: calc(var(--dot-y) - var(--dot) / 2);
  width: var(--dot); height: var(--dot); box-sizing: border-box;
  border: var(--pipe) solid var(--color-violet); border-radius: 50%;
}
/* The line's two halves: into the circle from above, and out of it below. */
.step:not(:first-of-type)::after, .step:not(:last-of-type) .step-head::before {
  content: ""; position: absolute; left: calc(var(--dot) / 2 - var(--pipe) / 2);
  width: var(--pipe); background: var(--color-violet);
}
.step:not(:first-of-type)::after {
  top: 0; height: calc(var(--dot-y) - var(--dot) / 2 - var(--dot-gap));
  border-radius: 0 0 var(--pipe) var(--pipe);
}
.step:not(:last-of-type) .step-head::before {
  top: calc(var(--dot-y) + var(--dot) / 2 + var(--dot-gap)); bottom: 0;
  border-radius: var(--pipe) var(--pipe) 0 0;
}
.step-head { display: flex; align-items: baseline; gap: var(--space-4); font-weight: var(--weight-regular); }
/* The number sits on the middle of the title's line. */
.step-num { align-self: center; font-family: var(--font-mono); font-size: var(--text-mono); color: var(--color-violet-bright); }
.step-name { font-family: var(--font-display); font-size: var(--text-display-xs); line-height: var(--leading-snug); }
.step-text { color: var(--color-text-muted); max-width: var(--measure); }
@media (min-width: 64rem) {
  .pipeline { --step-pad: var(--space-6); }
  .step { --dot-y: 50%; grid-template-columns: 5fr 6fr; gap: var(--space-8); align-items: center; }
}

/* Agentsy Advantage: the page opens up */
.advantage { text-align: center; }
.advantage-inner { display: grid; justify-items: center; text-align: center; }
.advantage .label { margin-inline: auto; }
.advantage-title { font-size: var(--text-display-l); line-height: var(--leading-display); letter-spacing: var(--tracking-hero); text-wrap: balance; }
.advantage-premise { margin-top: var(--space-7); color: var(--color-text-muted); font-size: var(--text-body-l); line-height: var(--leading-snug); }
.advantage-thesis {
  margin-top: var(--space-7); max-width: 28ch;
  font-family: var(--font-display); font-size: var(--text-display-s); line-height: var(--leading-display); text-wrap: balance;
}
.advantage-loop {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-5) var(--space-6);
  width: 100%; max-width: var(--measure-wide);
  font-family: var(--font-display); font-style: italic; font-size: clamp(1.25rem, 0.9rem + 1vw, 1.75rem);
}
/* Each on one line: "Operate better." broke after its first word. */
.advantage-loop li { white-space: nowrap; }
/* Like a wave, one after another, each word rises up through the line above it. Above the line it
   is purple, below it white, and it starts below, white. The line glows as the word passes through,
   then fades to the colour the word is not: white while the word is above, violet again once it is
   back below. They hold a beat, then go back down in the order they went up.
   Each word is there twice, white (shown below the line) and purple (.loop-lit, shown above it),
   each clipped at the line as they move together. Risen, a word sits as far above its line as it
   sat below it (--gap), and the list keeps as much room above a risen word as below a resting one. */
.advantage-loop { --gap: var(--space-3); --word: 1.25em; margin-top: calc(var(--space-8) + var(--gap) + var(--word)); }
.advantage-loop li { position: relative; padding-top: var(--gap); }
.advantage-loop li::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: var(--hairline);
  background: var(--color-line-strong); border-radius: 1px;
}
.loop-word { display: inline-block; line-height: 1.25; }
.loop-lit { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .has-motion .loop-lit {
    display: block; position: absolute; left: 0; right: 0; top: var(--gap); text-align: center;
    color: var(--color-highlight); clip-path: inset(-1em -1em calc(100% + var(--gap)) -1em);
  }
  /* A pseudo-element cannot go inside :is(), so the line has its own rule, on the same clock. */
  .has-motion .advantage-loop .loop-word {
    animation: loop-word-rise 8s cubic-bezier(0.45, 0, 0.35, 1) infinite;
    animation-delay: calc(var(--n) * 0.2s + 0.8s);
  }
  .has-motion .advantage-loop .loop-lit { animation-name: loop-lit-rise; }
  .has-motion .advantage-loop li::before {
    animation: loop-line 8s linear infinite;
    animation-delay: calc(var(--n) * 0.2s + 0.8s);
  }
}
/* The white word: shown only below the line, which in its own box sits a gap above it at rest and
   moves down it as it rises. Up over the first 12%, held, down from 50% to 62%. */
@keyframes loop-word-rise {
  0%, 62%, 100% { translate: 0 0; clip-path: inset(calc(-1 * var(--gap)) -1em -1em -1em); }
  12%, 50% { translate: 0 calc(-2 * var(--gap) - var(--word)); clip-path: inset(calc(var(--gap) + var(--word)) -1em -1em -1em); }
}
/* The purple word: shown only above the line. */
@keyframes loop-lit-rise {
  0%, 62%, 100% { translate: 0 0; clip-path: inset(-1em -1em calc(100% + var(--gap)) -1em); }
  12%, 50% { translate: 0 calc(-2 * var(--gap) - var(--word)); clip-path: inset(-1em -1em calc(var(--gap) * -1) -1em); }
}
/* The line: it glows while the word is passing through it (the middle of each move), then fades to
   white while the word is above, and back to violet once it is below again. */
@keyframes loop-line {
  0%, 3.5%, 66%, 100% { background: var(--color-line-strong); box-shadow: none; }
  6% { background: var(--color-highlight); box-shadow: 0 0 10px 2px rgb(224 140 255 / 0.75); }
  9% { background: #fff; box-shadow: 0 0 6px 1px rgb(255 255 255 / 0.35); }
  16%, 52.5% { background: #fff; box-shadow: none; }
  56% { background: var(--color-highlight); box-shadow: 0 0 10px 2px rgb(224 140 255 / 0.75); }
}
.advantage-loop li { border-top: var(--hairline) solid var(--color-line-strong); }
/* The sign-off sits on the light purple pill, like the other closing lines on the page. */
.advantage-sign { margin-top: var(--space-8); font-size: var(--text-body-l); line-height: var(--leading-snug); color: var(--color-text); }
@media (min-width: 56rem) { .advantage-loop { grid-template-columns: repeat(4, 1fr); } }

/* Case studies: their titles, words and links, in the rope of pills on the home page and the case
   studies page (.case-rope, below). */
.case-title { font-family: var(--font-display); font-weight: var(--weight-regular); font-size: var(--text-display-s); line-height: var(--leading-display); text-wrap: balance; }
.case-text { display: grid; gap: var(--space-4); color: var(--color-text-muted); max-width: var(--measure); }
.case-link { justify-self: start; padding-block: 0.75rem; margin-block: -0.75rem; font-family: var(--font-mono); font-size: var(--text-mono); color: var(--color-violet-bright); text-decoration: none; }
.case-link:hover { text-decoration: underline; text-underline-offset: 0.3em; }

/* Partners: a plain list */
.partner-list {
  display: grid; grid-template-columns: 1fr 1fr;
  border-top: var(--hairline) solid var(--color-line);
  font-family: var(--font-mono); font-size: var(--text-mono-l); color: var(--color-text-muted);
}
.partner-list li { padding-block: var(--space-4); border-bottom: var(--hairline) solid var(--color-line); }
.cogs-canvas { position: absolute; pointer-events: none; }
@media (min-width: 48rem) { .partner-list { grid-template-columns: repeat(4, 1fr); } }

/* Final CTA */
.final-title { font-size: var(--text-display-l); line-height: var(--leading-display); letter-spacing: var(--tracking-hero); max-width: 14ch; text-wrap: balance; }
/* What your business could become: each a pill of soft violet, like the vibe coding checks, wrapping
   in rows. */
.prompts { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-6); font-size: var(--text-body-l); line-height: var(--leading-snug); color: var(--color-text); }
.prompts li { padding: 0.4em 0.95em; border-radius: 999px; background: rgb(158 107 242 / 0.3); border: var(--hairline) solid rgb(158 107 242 / 0.55); }
/* The last screen, kept short: no full screen of
   its own, and room at its foot for the forest that grows along the footer's line (footer-forest.js
   draws it into .forest-art, whose foot is the section's bottom edge, the footer's top). */
.final.full-screen {
  --forest-height: clamp(7rem, 4.5rem + 5vw, 10rem);
  --footer-height: 23.7rem; /* the footer under it, so the two together are one screen */
  position: relative; align-content: stretch;
  min-height: calc(100svh - var(--footer-height) + 0.25rem); /* a hair over, so the divider above is just off screen */
  padding-block: clamp(var(--space-7), 9svh, var(--space-9)) calc(var(--forest-height) + var(--space-5));
}
@media (max-width: 47.99rem) { .final.full-screen { --footer-height: 47.1rem; } }
/* Title at the top, the way on at the foot, and the pills of what it could become in the middle,
   with as much room above them as below. */
.final .container { display: flex; flex-direction: column; gap: var(--space-6); }
.final .prompts { margin-block: auto; }
.forest-art { position: absolute; left: 0; bottom: 0; width: 100%; height: var(--forest-height); pointer-events: none; }
.final-head { display: grid; gap: var(--space-4); }
.final-action { position: relative; display: grid; justify-items: end; }
/* Two laser lights circling the pill (pill-lights.js): their canvas sits over it, past its edges,
   and in front of the trees' leaves where they stand on it. */
.pill-lights { position: absolute; z-index: 2; pointer-events: none; }
/* Under the pill, How We Work and Case Studies as the site's own links, in two equal halves set in
   from the big pill's ends. */
.final-more {
  --inset: clamp(var(--space-5), 6%, var(--space-8));
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3);
  padding-inline: var(--inset); margin-top: var(--space-4); justify-items: center;
}
/* The way on: a large pill, a band of light sweeping across it now and then, inside its shape. */
/* Never thinner than two finger-heights, however small its words get on a narrow phone. */
.final-pill {
  position: relative; isolation: isolate; overflow: hidden;
  min-height: calc(2 * var(--tap-target)); max-width: 100%; padding: 1em 2em; border-radius: 999px;
  font-size: clamp(1.05rem, 0.8rem + 1.2vw, 2rem); font-weight: var(--weight-medium);
}
.final-pill::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(105deg, transparent 35%, rgb(255 255 255 / 0.42) 50%, transparent 65%);
  translate: -110% 0;
}
.final-pill:focus-visible { outline: 3px solid var(--color-highlight); outline-offset: 4px; }
@media (prefers-reduced-motion: no-preference) {
  .final-pill::before { animation: pill-shimmer 4.2s cubic-bezier(0.45, 0, 0.3, 1) 1.2s infinite; }
}
@keyframes pill-shimmer { 0% { translate: -110% 0; } 45%, 100% { translate: 110% 0; } }
.build-it { font-family: var(--font-display); font-size: var(--text-display-m); line-height: var(--leading-display); }
/* Wide screens: the way on stands among the trees along the footer, its middle level with theirs,
   and the trees under it are gone. footer-forest.js grows them to --trees-tall,
   so the section keeps that much room at its foot below the words. */
@media (min-width: 640px) {
  .final.full-screen {
    --trees-tall: clamp(13rem, 6rem + 14vw, 20rem);
    padding-bottom: calc(var(--trees-tall) * 1.12 + var(--space-5));
  }
  /* The pill and the two links under it are one stack, its middle level with the trees' middle. */
  .final-action { position: absolute; right: max(var(--gutter), calc((100% - var(--container)) / 2)); bottom: calc(var(--trees-tall) / 2); translate: 0 50%; }
  /* Smaller than on a phone, so there is clear room between it and the trees. */
  .final-pill { font-size: clamp(1rem, 0.7rem + 0.9vw, 1.6rem); }
  .final-more { --inset: clamp(2.5rem, 11%, 4.5rem); margin-top: var(--space-5); justify-self: stretch; }
}

/* ---------- Sides ---------- */
/* Down the page the sections take turns: some lead from the left, some from the right, and the
   drawn screens and the Advantage sit in the middle, so the page swings from side to side as it
   goes. .is-end puts a section's heading, or a statement's, in the right-hand column on a wide
   screen. A title is always set left (or centred), never right. */
@media (min-width: 64rem) {
  .statement.is-end .statement-head { order: 2; }
  .statement.is-end .statement-body { order: 1; }
  .is-end .people-grid { grid-template-columns: 5fr 7fr; }
  .is-end .people-grid .punchline { order: -1; }
  .is-end .split { grid-template-columns: 7fr 5fr; }
  .is-end .split-head { order: 2; }
}

/* ---------- Supporting pages ---------- */
/* Each supporting page opens on its own hero: Jins' heading for the page, large, with his opening
   lines under it, sitting low on the first screen and leading from the left. */
.subpage-hero { min-height: 78svh; display: grid; align-content: end; padding-block: calc(var(--nav-height) + var(--space-8)) var(--space-8); }
.subpage-hero-body { display: grid; gap: var(--space-6); justify-items: start; }
/* Contact's ring of phones (phone-wheel.js), and Partners' cogs (partner-cogs.js): to the right of
   the title on a wide screen, above it on a phone. */
.subpage-hero:has(.hero-phones, .hero-cogs) { position: relative; }
/* About's wall going up (builders-frame.js): beside the words on a wide screen, the two sharing the
   middle of the screen as Contact's do; above them on a phone. */
.subpage-hero:has(.hero-frame) { position: relative; }
.hero-frame { position: absolute; pointer-events: none; aspect-ratio: 1.65; }
.hero-frame canvas { display: block; width: 100%; height: 100%; }
.subpage-hero:has(.hero-frame) .subpage-hero-body { position: relative; z-index: 1; }
@media (min-width: 64rem) {
  .subpage-hero.subpage-hero:has(.hero-frame) { min-height: calc(100svh - var(--nav-height)); align-content: center; padding-block: 0 var(--nav-height); }
  .hero-frame { right: max(var(--gutter), calc((100% - var(--container)) / 2)); top: calc(50% - var(--nav-height) / 2); translate: 0 -50%; width: min(46vw, 46rem); }
}
@media (max-width: 63.99rem) {
  .subpage-hero:has(.hero-frame) { min-height: 100svh; align-content: center; }
  .hero-frame { position: relative; justify-self: center; width: min(100vw - var(--gutter), 34rem); margin-bottom: var(--space-4); }
}
/* What We Do's neural etching (implementation-network.js), behind the words: a section of the How We Work page,
   tall enough for the etching to have room above the words, which sit at its foot. */
.what-we-do-intro { display: grid; align-content: end; min-height: 72svh; }
[data-network-hero] { position: relative; }
[data-network-hero] .subpage-hero-body { position: relative; z-index: 1; }
.hero-network-art { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; }
.hero-phones, .hero-cogs { position: absolute; pointer-events: none; aspect-ratio: 1; }
.hero-phones canvas { display: block; width: 100%; height: 100%; }
@media (min-width: 64rem) {
  .hero-phones, .hero-cogs { right: max(var(--gutter), calc((100% - var(--container)) / 2)); top: 50%; translate: 0 -46%; width: min(44vw, 38rem); }
  /* The ring's outer edge, not its box's, sits on the margin: as far in from the right as the title
     is from the left (phone-wheel.js measures the gap). */
  .hero-phones { translate: var(--ring-spare, 0px) -46%; }
  /* Contact: the words and the ring share the middle of the screen. The hero
     fills the screen under the header, with the header's height left empty at its foot too, so its
     middle is the screen's; the ring is centred on that middle. (Doubled to outrank the rule that
     gives a hero a divided section's room below.) */
  .subpage-hero.subpage-hero:has(.hero-phones) { min-height: calc(100svh - var(--nav-height)); align-content: center; padding-block: 0 var(--nav-height); }
  .subpage-hero:has(.hero-phones) .hero-phones { top: calc(50% - var(--nav-height) / 2); translate: var(--ring-spare, 0px) -50%; }
  /* The cogs have the whole opening to wrap round the words in (partner-cogs.js). */
  .hero-cogs { inset: 0; width: auto; translate: none; aspect-ratio: auto; }
}
@media (max-width: 63.99rem) {
  .subpage-hero:has(.hero-phones, .hero-cogs) { min-height: 100svh; }
  .hero-phones, .hero-cogs { left: 50%; translate: -50% 0; top: calc(var(--nav-height) + env(safe-area-inset-top)); width: min(90vw, 28rem); }
  /* Contact: the ring sits above the words, centred, clear of the header above it, the screen's
     sides and the title below. --ring-seen is the ring as drawn,
     phone tip to phone tip; its canvas is wider, the phones reaching 0.824 of it (ringFor in
     phone-wheel.js), so the canvas runs past the screen's sides, where the page clips it (html).
     The hero must not clip it as well: a clip of its own cut the top phone off flat at its top. */
  /* The header is sticky, above the hero, and its logo sits in its middle: the gap above the ring
     is measured from the logo's foot (the logo is 0.216 as tall as it is wide), but the ring never
     starts above the hero itself. */
  /* Twice the page's margin above and below it, the ring made smaller by that much so the opening
     keeps its height. */
  .subpage-hero:has(.hero-phones) {
    --ring-gap: calc(2 * var(--gutter));
    --ring-seen: calc(min(100vw - 2 * var(--gutter), 24rem) - 2 * var(--gutter));
    --ring-box: calc(var(--ring-seen) / 0.824);
    --ring-top: max(0px, var(--ring-gap) - (var(--nav-height) - var(--logo-width) * 0.216) / 2);
    min-height: 0;
    padding-top: calc(var(--ring-top) + var(--ring-seen) + var(--ring-gap));
  }
  .subpage-hero .hero-phones {
    width: var(--ring-box);
    top: calc(var(--ring-top) - (var(--ring-box) - var(--ring-seen)) / 2);
  }
  /* The cogs span the content's width exactly, inside the page's margins. */
  .hero-cogs { width: min(100% - 2 * var(--gutter), 28rem); }
}
/* How We Work's title plays. "Imagine" has a soft rainbow running slowly through it, left to right.
   "Vibe" and "code" rock from one foot to the other, in step and mirrored: when one leans out, so
   does the other, and when they lean in, never far enough to touch. The o's of "operational" are
   cogs drawn in their place (title-cogs.js). */
.rainbow-word {
  background: linear-gradient(90deg, #ff9fae, #ffc58a, #ffe69a, #a6f0c0, #94d4ff, #bba6ff, #f0a6ff, #ff9fae) 0 0 / 7em 100% repeat-x;
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
/* "Code" in How We Work's title: its letters hop up one at a time, at random, like keys being typed
   (script.js; the designer, 2026-10-13). */
.type-hop, .type-hop .key { display: inline-block; }
.type-hop { position: relative; }
.type-hop .key-echo { position: absolute; pointer-events: none; opacity: 0; }
/* The lines of a title with a typed word sit a little further apart, so each letter's echo has room
   to slide up and fade before it reaches the line above: the d of "Code" sat 1px under the g of
   "Imagine". */
.subpage-title:has([data-type-hop]) .line + .line { margin-top: 0.16em; }
/* A word in the site's green, set bold: "operational" in How We Work's title. */
.green-key { color: var(--color-green); font-weight: var(--weight-semibold); }
/* The real o is hidden from the first paint, not once the script runs: the script waits for the
   fonts, and until then the o showed through behind its cog. With scripts off,
   the page's noscript style shows it again. */
.cog-o { position: relative; color: transparent; --cog-colour: var(--color-green-deep); }
.cog-o canvas { position: absolute; pointer-events: none; }
@media (prefers-reduced-motion: no-preference) {
  .rainbow-word { animation: rainbow-run 12s linear infinite; }
}
@keyframes rainbow-run { to { background-position: 7em 0; } }
.subpage-title {
  font-family: var(--font-display); font-weight: var(--weight-regular);
  font-size: var(--text-display-l); line-height: var(--leading-display);
  letter-spacing: var(--tracking-hero); text-wrap: balance; max-width: 17ch;
}
.subpage-lede { display: grid; gap: var(--space-2); max-width: 36ch; font-size: var(--text-body-l); line-height: var(--leading-snug); color: var(--color-text-muted); }
.subpage-lede > :first-child { color: var(--color-text); }
/* A lede of equals, like Contact's four "Maybe…" lines: all the same white, none set above the rest. */
.lede-equal > * { color: var(--color-text); }

/* A list of services, steps or the like: each in a deep purple box, its name and line on one side
   and its detail on the other, the sides swapping from one box to the next. */
.service-list { display: grid; gap: var(--space-5); margin-top: var(--space-8); }
.service { --service-pad: var(--space-6); display: grid; gap: var(--space-6); padding: var(--service-pad); background: var(--color-deep); border-radius: var(--radius-l); overflow: hidden; }
.service-head { display: grid; gap: var(--space-3); align-content: start; }
/* A pink pill that runs in from the nearest edge, of its box or of the page (--edge, how far that
   edge is): square where it meets the edge, round at its words' end, which start where the words
   below them do. A service's number, and a case study's tag. */
:is(.service-num, .case-tag) {
  justify-self: start; width: fit-content; margin-left: calc(-1 * var(--edge));
  padding: 0.2em 0.85em 0.2em var(--edge); border-radius: 0 999px 999px 0;
  background: var(--color-highlight); color: var(--color-on-violet);
  font-family: var(--font-mono); font-size: calc(var(--text-display-xs) * 0.75); line-height: 1.2; font-weight: var(--weight-semibold);
}
.service { --edge: var(--service-pad); }
.subpage-hero { --edge: max(var(--gutter), (100vw - var(--container)) / 2); }
.subpage-hero .case-tag { margin-bottom: var(--space-5); }
/* The case studies list, like the home page's steps: a rope down the left joins a ball on each row,
   and each ball is the filled left end of its study's pill, the pill running on from it with the
   study's tag, so a ripple down the rope carries the whole pill. The title sits under the pill, the words beside; each row's line starts past the balls
   (pipeline-rope.js draws the rope moving; this is it at rest). */
.case-rope {
  --pipe: 3px; --dot-gap: 0.2rem; --rope-colour: var(--color-highlight);
  --tag-size: calc(var(--text-display-xs) * 0.75); --ball: calc(var(--tag-size) * 1.6); --row-pad: var(--space-7);
  position: relative;
}
/* Under a section title, as on the home page, the rope keeps the room the other lists keep. */
.h2 + .case-rope { margin-top: var(--space-8); }
.case-row {
  --rule: linear-gradient(var(--color-line), var(--color-line));
  position: relative; display: grid; gap: var(--space-5) var(--space-8); align-items: start; padding-block: var(--row-pad);
  background: var(--rule) right top / calc(100% - var(--ball) - var(--space-4)) var(--hairline) no-repeat;
}
.case-row:last-child {
  background:
    var(--rule) right top / calc(100% - var(--ball) - var(--space-4)) var(--hairline) no-repeat,
    var(--rule) right bottom / calc(100% - var(--ball) - var(--space-4)) var(--hairline) no-repeat;
}
.case-head { display: grid; gap: var(--space-4); justify-items: start; }
.case-head .case-title { margin-left: var(--ball); }
.case-row .case-text { margin-left: var(--ball); }
.case-tag.case-tag-ball {
  display: flex; align-items: center; width: fit-content; margin: 0; padding: 0; border-radius: 0; background: none;
  font-size: var(--tag-size);
}
.case-ball { flex: none; width: 1.6em; height: 1.6em; border-radius: 50%; background: var(--color-highlight); }
.case-tag-text { margin-left: -0.8em; padding: 0.2em 0.85em 0.2em 1.1em; border-radius: 0 999px 999px 0; background: var(--color-highlight); }
/* The rope at rest: down from the row's top to just short of its ball, and on from just past it. */
.case-row:not(:first-child)::before, .case-row:not(:last-child)::after {
  content: ""; position: absolute; left: calc(var(--ball) / 2 - var(--pipe) / 2); width: var(--pipe); background: var(--rope-colour);
}
.case-row:not(:first-child)::before { top: 0; height: calc(var(--row-pad) - var(--dot-gap)); border-radius: 0 0 var(--pipe) var(--pipe); }
.case-row:not(:last-child)::after { top: calc(var(--row-pad) + var(--ball) + var(--dot-gap)); bottom: 0; border-radius: var(--pipe) var(--pipe) 0 0; }
.has-rope .case-row::before, .has-rope .case-row::after { visibility: hidden; }
@media (max-width: 639px) { .case-rope { --tag-size: 0.95rem; } }
@media (min-width: 64rem) {
  .case-row { grid-template-columns: 5fr 6fr; }
  .case-row .case-text { margin-left: 0; }
}
.service-name { font-family: var(--font-display); font-weight: var(--weight-semibold); font-size: var(--text-display-xs); line-height: var(--leading-snug); color: var(--color-highlight); }
.service-tag { display: grid; font-family: var(--font-display); font-size: var(--text-display-s); line-height: var(--leading-display); text-wrap: balance; }
.service-body { display: grid; gap: var(--space-3); align-content: start; line-height: var(--leading-body); }
.service-body .dash-list { color: var(--color-text); }
.service-body .places { justify-content: flex-start; margin-block: var(--space-2); }
@media (min-width: 64rem) {
  .service { --service-pad: var(--space-7); grid-template-columns: 5fr 7fr; gap: var(--space-8); }
  /* Every head on the left, its number with it, row after row: not back and forth. The words beside it stack toward the box's right edge, a little in from it, still
     reading left to right. Every stack in a list is as wide as the widest, so they all start on one
     line (script.js sets --stack-width). */
  .service .service-body {
    justify-self: end; width: var(--stack-width, fit-content); max-width: 100%; margin-right: var(--space-7);
  }
}

/* A line between a page's opening and the section after it has the same space on each side: the
   opening keeps a section's space below its words. A closing screen with a line above it starts its
   words a section's space below the line, as any section does, not in the middle of the screen. */
.subpage-hero:has(+ .is-divided) { padding-bottom: var(--space-section); }
.subpage-cta.full-screen.is-divided { min-height: 0; align-content: start; padding-block: var(--space-section); }

/* The Partners page's platforms: four small cards side by side, each its group's name in the
   highlight and its platforms as a short list. */
.platforms { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); margin-top: var(--space-8); }
.platform-group { display: grid; gap: var(--space-4); align-content: start; padding: var(--space-6); background: var(--color-deep); border-radius: var(--radius-l); }
.platform-group-name { font-family: var(--font-mono); font-size: var(--text-mono-l); font-weight: var(--weight-semibold); letter-spacing: var(--tracking-mono); color: var(--color-highlight); }
.platform-names { display: grid; gap: var(--space-2); font-family: var(--font-display); font-size: var(--text-display-xs); line-height: var(--leading-snug); }
@media (min-width: 64rem) { .platforms { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* A supporting page's close: Jins' closing lines in the middle of a screen, and the way to talk. */
.subpage-cta .container { display: grid; justify-items: center; gap: var(--space-5); text-align: center; }
.subpage-cta-title { display: grid; font-family: var(--font-display); font-weight: var(--weight-regular); font-size: var(--text-display-l); line-height: var(--leading-display); letter-spacing: var(--tracking-hero); text-wrap: balance; }
.subpage-cta-sub { font-family: var(--font-display); font-style: italic; font-size: var(--text-display-xs); line-height: var(--leading-snug); color: var(--color-text-muted); }
.subpage-cta .button { margin-top: var(--space-4); }
/* A case study's close: "The Agentsy Advantage" as a label, then its two sentences as a setup and a
   punch, the punch the size of a heading and the setup a step smaller and quieter, so a long
   sentence never fills the screen at hero size. */
.subpage-cta-label { margin-inline: auto; margin-bottom: 0; font-size: var(--text-body); }
.subpage-cta-title.is-split { gap: var(--space-4); justify-items: center; }
.cta-setup { font-size: var(--text-display-s); line-height: var(--leading-snug); color: var(--color-text-muted); max-width: 26ch; text-wrap: balance; }
.cta-punch { font-size: var(--text-display-m); line-height: var(--leading-display); max-width: 22ch; text-wrap: balance; }
.subpage-cta-title.is-split + .button { margin-top: var(--space-6); }

/* ---------- Team page ---------- */
.team-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-4); }
@media (min-width: 48rem) { .team-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-6); } }
/* Three people: two across with the third centred under them, then all three across on wide screens. */
@media (min-width: 48rem) and (max-width: 71.99rem) { .team-grid .person:nth-child(odd):last-child { grid-column: 1 / -1; justify-self: center; width: calc((100% - var(--space-6)) / 2); } }
@media (min-width: 72rem) { .team-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.person { display: grid; gap: var(--space-4); align-content: start; padding: var(--space-6); background: var(--color-deep); border-radius: var(--radius-l); color: var(--color-text); }
.person-photo { width: 10rem; height: 10rem; max-width: 100%; border-radius: 50%; object-fit: cover; background: rgb(158 107 242 / 0.3); }
.person-caption { margin: 0; font-size: var(--text-body-s); font-style: italic; color: var(--color-text-quiet); }
.person-name { font-family: var(--font-display); font-weight: var(--weight-regular); font-size: var(--text-display-s); line-height: var(--leading-display); }
.person .label { margin-bottom: 0; }
.person-bio { display: grid; gap: var(--space-3); color: var(--color-text-muted); font-size: var(--text-body-l); line-height: var(--leading-snug); }
.person .text-link { justify-self: start; }

/* ---------- Contact form ---------- */
/* The contact page's form: Jins' four fields and his button. Loaded after styles.css on
   contact.html only, and made only from its tokens, so it can fold into styles.css as it is. */

/* The form takes the place of a statement's lines, so it resets their larger, quieter type. */
.contact-form { gap: var(--space-5); font-size: var(--text-body); line-height: var(--leading-body); color: var(--color-text); }
.field { display: grid; gap: var(--space-2); }
.field-label { font-weight: var(--weight-medium); }

/* Each field is a deep purple box, like the boxes on the other pages, with white type. Body size
   keeps Safari on a phone from zooming in when a field is tapped. */
.field-input {
  display: block; width: 100%; min-height: var(--button-height);
  padding: var(--space-3) var(--space-4);
  background: var(--color-deep); color: var(--color-text);
  border: var(--hairline) solid transparent; border-radius: var(--radius-m);
  font: inherit;
}
textarea.field-input { resize: vertical; }
.field-input::placeholder { color: var(--color-text-quiet); opacity: 1; }
.field-input:hover { border-color: var(--color-line-strong); }
/* The site's focus ring, kept to the field's own corners. */
.field-input:focus-visible { border-color: var(--color-line-strong); border-radius: var(--radius-m); }

/* The button is the site's large button; a <button> also needs its own border and cursor cleared. */
.contact-form .button { justify-self: start; margin-top: var(--space-2); border: 0; cursor: pointer; }
.contact-form .button:disabled { opacity: 0.7; cursor: progress; }
.form-status { font-family: var(--font-display); font-size: var(--text-display-xs); line-height: var(--leading-snug); }
.contact-form.is-sent .form-status { color: var(--color-highlight); }

/* The fallback form is a grid (.statement-body), which beats the hidden attribute: say it again. */
.contact-form[hidden], .hs-form-html[hidden] { display: none; }
.contact-embed { max-width: var(--measure); min-width: 0; }

/* ---------- HubSpot form ---------- */
/* HubSpot's developer embed draws plain HTML into .hs-form-html, no iframe, with its own styles
   added to the head after ours (every rule of theirs starts [data-hsfc-id=Renderer], two classes
   deep). So each rule here starts .hs-form-html .hsfc-Renderer, three deep, to win without !important.
   Class names found by dumping the drawn page (2026-10-14): Renderer > FormWrapper > Form > Step >
   Step__Content > Row > {TextField, EmailField, PhoneField, TextareaField, DataPrivacyField}, each a
   FieldLabel (+ __RequiredIndicator) over a TextInput or TextareaInput, then ErrorAlert under an input
   marked aria-invalid="true"; last a NavigationRow with its Button. The look matches the fallback form
   above: .field-label, .field-input, .button-large and .form-status. */
.hs-form-html .hsfc-Renderer {
  --hs-gap: var(--space-5);
  /* HubSpot's own switches: the one button sits at the start, as ours does. */
  --hsf-default-navigationrow-buttons-single__justify-content: flex-start;
  --hsf-default-navigationrow-buttons__justify-content: flex-start;
  font-family: var(--font-body); font-size: var(--text-body); line-height: var(--leading-body); color: var(--color-text);
}
.hs-form-html .hsfc-Renderer .hsfc-Row { display: grid; grid-template-columns: 1fr; gap: var(--hs-gap); margin: 0 0 var(--hs-gap); }
.hs-form-html .hsfc-Renderer .hsfc-Step__Content { padding: 0; }
.hs-form-html .hsfc-Renderer :is(.hsfc-TextField, .hsfc-EmailField, .hsfc-PhoneField, .hsfc-TextareaField, .hsfc-DropdownField, .hsfc-NumberField, .hsfc-DateField, .hsfc-URLField) { display: grid; gap: var(--space-2); align-content: start; }
.hs-form-html .hsfc-Renderer :is(.hsfc-RichText, .hsfc-RichText p) { font-family: var(--font-body); font-size: var(--text-body); color: var(--color-text-muted); }
.hs-form-html .hsfc-Renderer .hsfc-RichText p { margin: 0; }
.hs-form-html .hsfc-Renderer .hsfc-RichText br { display: none; }
.hs-form-html .hsfc-Renderer .hsfc-DataPrivacyField .hsfc-RichText { font-size: var(--text-body-s); color: var(--color-text-quiet); }
.hs-form-html .hsfc-Renderer .hsfc-RichText a { color: var(--color-highlight); }

/* Labels: like .field-label. */
.hs-form-html .hsfc-Renderer .hsfc-FieldLabel {
  font-family: var(--font-body); font-size: var(--text-body); font-weight: var(--weight-medium); color: var(--color-text);
}
.hs-form-html .hsfc-Renderer .hsfc-FieldLabel__RequiredIndicator { margin-left: 0.2em; color: var(--color-highlight); }
/* A field's help line, set in HubSpot: quiet like the placeholder, not HubSpot's grey-blue. */
.hs-form-html .hsfc-Renderer .hsfc-FieldDescription { font-family: var(--font-body); font-size: var(--text-body-s); color: var(--color-text-quiet); }

/* Fields: like .field-input, a deep purple box with white type. */
.hs-form-html .hsfc-Renderer :is(.hsfc-TextInput, .hsfc-TextareaInput, .hsfc-DropdownInput) {
  display: block; width: 100%; min-height: var(--button-height); margin: 0; box-sizing: border-box;
  padding: var(--space-3) var(--space-4);
  background: var(--color-deep); color: var(--color-text);
  border: var(--hairline) solid transparent; border-radius: var(--radius-m);
  box-shadow: none; font: inherit; font-family: var(--font-body);
}
.hs-form-html .hsfc-Renderer .hsfc-TextareaInput { min-height: 9rem; resize: vertical; }
.hs-form-html .hsfc-Renderer :is(.hsfc-TextInput, .hsfc-TextareaInput)::placeholder { color: var(--color-text-quiet); opacity: 1; }
.hs-form-html .hsfc-Renderer :is(.hsfc-TextInput, .hsfc-TextareaInput, .hsfc-DropdownInput):hover { border-color: var(--color-line-strong); box-shadow: none; }
.hs-form-html .hsfc-Renderer :is(.hsfc-TextInput, .hsfc-TextareaInput, .hsfc-DropdownInput):focus,
.hs-form-html .hsfc-Renderer :is(.hsfc-TextInput, .hsfc-TextareaInput, .hsfc-DropdownInput):focus-visible { border-color: var(--color-line-strong); box-shadow: none; }
/* Wrong: the red the app uses for what is wrong. */
.hs-form-html .hsfc-Renderer :is(.hsfc-TextInput, .hsfc-TextareaInput)[aria-invalid="true"] { border-color: var(--color-red); }

/* Phone: the flag-and-caret button sits as a box of the same kind beside its number. */
.hs-form-html .hsfc-Renderer .hsfc-PhoneInput { display: flex; align-items: stretch; gap: var(--space-2); position: relative; }
.hs-form-html .hsfc-Renderer .hsfc-PhoneInput > .hsfc-TextInput { flex: 1 1 auto; width: auto; }
.hs-form-html .hsfc-Renderer .hsfc-PhoneInput__FlagAndCaret {
  box-sizing: border-box; padding: var(--space-3) var(--space-4); background: var(--color-deep); color: var(--color-text);
  border: var(--hairline) solid transparent; border-radius: var(--radius-m);
}
.hs-form-html .hsfc-Renderer .hsfc-PhoneInput__FlagAndCaret:hover { border-color: var(--color-line-strong); }
.hs-form-html .hsfc-Renderer .hsfc-PhoneInput__FlagAndCaret__Caret { border-top-color: var(--color-text); }
/* The country list opens over the page, so it needs a ground of its own. */
.hs-form-html .hsfc-Renderer .hsfc-DropdownOptions {
  background: var(--color-deep); color: var(--color-text); border: var(--hairline) solid var(--color-line-strong);
  border-radius: var(--radius-m); box-shadow: none; font-family: var(--font-body); font-size: var(--text-body-s);
}
.hs-form-html .hsfc-Renderer .hsfc-DropdownOptions .hsfc-TextInput { background: var(--color-ground); }
.hs-form-html .hsfc-Renderer .hsfc-DropdownOptions__List__ListItem { color: var(--color-text); background: transparent; }
.hs-form-html .hsfc-Renderer :is(.hsfc-DropdownOptions__List__ListItem:hover, .hsfc-DropdownOptions__List__ListItem:focus, .hsfc-DropdownOptions__List__ListItem--selected) { background: var(--color-ground-raised); color: var(--color-text); }

/* Checkboxes (the consent lines). */
.hs-form-html .hsfc-Renderer .hsfc-CheckboxField .hsfc-FieldLabel { display: flex; align-items: flex-start; gap: var(--space-3); font-weight: var(--weight-regular); font-size: var(--text-body-s); color: var(--color-text-muted); }
.hs-form-html .hsfc-Renderer .hsfc-CheckboxInput { flex: none; margin: 0.2em 0 0; accent-color: var(--color-violet); }

/* Errors and the sent message: like .form-status, the display serif. */
.hs-form-html .hsfc-Renderer :is(.hsfc-ErrorAlert, .hsfc-InfoAlert) {
  font-family: var(--font-body); font-size: var(--text-body-s); line-height: var(--leading-snug); color: var(--color-red);
}
.hs-form-html .hsfc-Renderer .hsfc-InfoAlert { color: var(--color-highlight); }
.hs-form-html .hsfc-Renderer .hsfc-PostSubmit {
  font-family: var(--font-display); font-size: var(--text-display-xs); line-height: var(--leading-snug); color: var(--color-highlight);
}
.hs-form-html .hsfc-Renderer .hsfc-PostSubmit * { font-family: inherit; color: inherit; }

/* One step only: the progress bar says nothing. */
.hs-form-html .hsfc-Renderer .hsfc-Row:has(> .hsfc-ProgressBar) { display: none; }
.hs-form-html .hsfc-Renderer .hsfc-NavigationRow { margin-top: 0; }
.hs-form-html .hsfc-Renderer .hsfc-NavigationRow__Buttons { flex-direction: row; }

/* Submit: the site's large button. */
.hs-form-html .hsfc-Renderer .hsfc-Button {
  display: inline-flex; align-items: center; justify-content: center; width: auto; min-height: var(--button-height);
  padding: 0 var(--space-5); margin: var(--space-2) 0 0;
  background: var(--color-violet); color: var(--color-on-violet);
  font-family: var(--font-body); font-size: var(--text-body); font-weight: var(--weight-medium); line-height: 1;
  border: 0; border-radius: var(--radius-s); box-shadow: none; cursor: pointer;
}
.hs-form-html .hsfc-Renderer .hsfc-Button:not([disabled]):hover,
.hs-form-html .hsfc-Renderer .hsfc-Button:not([disabled]):focus { background: var(--color-violet-bright); color: var(--color-on-violet); transform: none; }
.hs-form-html .hsfc-Renderer .hsfc-Button[disabled] { opacity: 0.7; cursor: progress; filter: none; }
/* The captcha's badge is Google's own; only its grey shadow goes. */
.hs-form-html .hsfc-Renderer .grecaptcha-badge { box-shadow: none !important; }
/* Google lets the badge go if its notice is shown instead (see .recaptcha-note under the form). Hidden,
   not removed: display: none can stop reCAPTCHA working. The row that held it keeps no height. */
.hs-form-html .hsfc-Renderer :is(.grecaptcha-badge, .hsfc-ReCaptchaV3__Badge__Container) { visibility: hidden; }
.hs-form-html .hsfc-Renderer .hsfc-ReCaptchaV3__Badge__Container { height: 0; overflow: hidden; }
.recaptcha-note { margin-top: var(--space-4); font-size: var(--text-body-s); color: var(--color-text-quiet); }
.recaptcha-note a { color: var(--color-highlight); }

@media (prefers-reduced-motion: no-preference) {
  .field-input, .hs-form-html .hsfc-Renderer :is(.hsfc-TextInput, .hsfc-TextareaInput) { transition: border-color var(--dur-fast); }
}

/* ---------- Footer ---------- */
/* The logo and where we are, then three short columns of links, each under a small heading.
   Two across on a phone, four across from 48rem. */
.site-footer { border-top: var(--hairline) solid var(--color-line); padding-block: var(--space-6); }
.footer-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-6) var(--space-4); align-items: start; }
.footer-brand { display: grid; gap: var(--space-3); grid-column: 1 / -1; }
.footer-grid > .footer-copy { grid-column: 1 / -1; grid-row: auto; padding-top: var(--space-4); border-top: var(--hairline) solid var(--color-line); }
.footer-place, .footer-copy { font-family: var(--font-mono); font-size: var(--text-mono); color: var(--color-text-quiet); }
.footer-email { display: inline-block; padding-block: 0.25rem; color: inherit; text-decoration: none; }
.footer-email:hover { color: var(--color-text); }
.footer-abn { white-space: nowrap; }
.footer-head { margin-bottom: var(--space-2); font-family: var(--font-mono); font-size: var(--text-mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-text-quiet); }
.footer-links a { display: inline-block; padding-block: 0.4rem; font-weight: var(--weight-semibold); }
@media (max-width: 47.99rem) {
  .footer-grid > .footer-col:nth-of-type(2) { grid-column: 2; grid-row: 2 / span 2; }
  .footer-grid > .footer-col:nth-of-type(3) { grid-column: 1; grid-row: 3; }
  .footer-grid > .footer-copy { grid-row: 4; }
}
@media (min-width: 48rem) {
  .footer-grid { grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: var(--space-8); }
  .footer-brand { grid-column: auto; }
}

/* ---------- Motion (only where it has a reason) ---------- */
@media (prefers-reduced-motion: no-preference) {
  .button, .text-link, .menu-links a, .footer-links a {
    transition: background-color var(--dur-fast), color var(--dur-fast), text-decoration-color var(--dur-fast);
  }


  /* Hidden only until script.js types it; shown on a timer if the script never runs. */
  .is-typing [data-type]:not(.is-ready),
  .is-typing .hero-title:not(.is-ready) .prompt-chevron,
  .is-typing .hero-title > .cursor { visibility: hidden; animation: type-fallback 0s var(--type-fallback) forwards; }

}
@keyframes type-fallback { to { visibility: visible; } }

/* The mission line is drawn in the first time the drawing above is finished (hero-graphic.js
   adds .is-drawn): a soft sweep from left to right with a white-hot edge that cools to its own
   colour. After that it stays. Without script or with Reduce Motion it is simply there. */
@property --mission-reveal { syntax: "<percentage>"; inherits: true; initial-value: 0%; }
.hero-mission-text { display: block; }
.hero-mission-heat { display: none; }
@media (prefers-reduced-motion: no-preference) {
  /* Hidden until .is-drawn. The fallback, if the drawing never finishes, is a 12 second timer in
     hero-graphic.js: a delayed CSS animation of --mission-reveal made the browser redo the page's
     style every frame while it waited, which cost a quarter of the frame rate. */
  .has-motion .hero-mission { --mission-reveal: 0%; }
  .has-motion .hero-mission.is-drawn { animation: mission-wipe var(--dur-mission) cubic-bezier(0.45, 0, 0.35, 1) forwards; }
  .has-motion .hero-mission-text {
    -webkit-mask-image: linear-gradient(90deg, #000 calc(var(--mission-reveal) - 8%), transparent var(--mission-reveal));
    mask-image: linear-gradient(90deg, #000 calc(var(--mission-reveal) - 8%), transparent var(--mission-reveal));
  }
  .has-motion .hero-mission-heat {
    display: block; position: absolute; inset: 0; color: #fff; pointer-events: none;
    text-shadow: 0 0 0.6em rgb(255 255 255 / 0.8);
    -webkit-mask-image: linear-gradient(90deg, transparent calc(var(--mission-reveal) - 16%), #000 calc(var(--mission-reveal) - 4%), transparent var(--mission-reveal));
    mask-image: linear-gradient(90deg, transparent calc(var(--mission-reveal) - 16%), #000 calc(var(--mission-reveal) - 4%), transparent var(--mission-reveal));
  }
  .has-motion .hero-mission-heat .hero-mission-key { color: inherit; }
}
@keyframes mission-wipe { to { --mission-reveal: 120%; } }

/* ---------- Phone ---------- */
@media (max-width: 639px) {
  /* The staircase stays on screen: its widest step is just inside the page's margin. */
  :root { --stair: calc((var(--gutter) - 0.25rem) / 3); }
  /* A supporting page's close is a section like any other, not a whole screen: on a phone the
     screen-high version left most of a screen empty above its words. */
  .subpage-cta.full-screen { min-height: 0; padding-block: var(--space-section); }
  /* The way on is the full width of the page and centred, with three trees growing on top of it
     (footer-forest.js), so it gets their room above it, and clear room over the treetops. No trees
     grow under it, so the section needs no room for them at its foot. */
  .final.full-screen { padding-bottom: var(--space-8); }
  .final-action { justify-items: stretch; padding-top: 10rem; }
  /* Its words keep well clear of its ends: on a narrow phone they get smaller rather than closer. */
  .final-pill { width: 100%; padding-inline: 1.75rem; font-size: min(1.15rem, (100vw - 2 * var(--gutter) - 3.5rem) / var(--final-pill-ems, 19)); }
  /* The ring's two links came out 43px tall, a pixel short of a finger. */
  .text-link { min-height: var(--tap-target); }
  /* Partners' two-up boxes: "Infrastructure" ran past its box's padding, and a name that wraps
     pushed its list below its neighbour's. Less padding and the smaller mono size keep every name
     inside, and the subgrid starts both lists in a row on one line. */
  .platform-group { padding: var(--space-5); grid-row: span 2; grid-template-rows: subgrid; }
  .platform-group-name { font-size: var(--text-mono); }
  /* The vibe coding sum-up's pill wraps taller on a phone (160px, not the 112px the hold allows
     for), so it sat 32px above the next section's line with 80px below it. Half its real height
     puts the line midway again. */
}

/* Looping animations stop while their section is off screen (toggled in script.js). Scroll-driven ones are left running: pausing them would offset them from the scroll. */
[data-paused] :is(.scary-word, .model-ring-turn, .rainbow-word, .loop-word, .loop-lit, .advantage-loop li, .final-pill),
[data-paused] :is(.advantage-loop li, .final-pill)::before { animation-play-state: paused !important; }

/* What We Do, once a page of its own, lands clear of the header when linked to. */
#what-we-do { scroll-margin-top: var(--nav-height); }

/* ---------- Questions and answers (How We Work) ---------- */
/* Each question is a native details box in the deep purple, the answer opening under it. The question
   is the box's whole top, so the tap target is its full width; a plus turns to a minus when open. */
.faq-list { display: grid; gap: var(--space-3); margin-top: var(--space-8); max-width: var(--measure-wide); }
.faq-item { background: var(--color-deep); border-radius: var(--radius-l); }
.faq-q {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
  min-height: var(--tap-target); padding: var(--space-5) var(--space-6); cursor: pointer; list-style: none;
  font-family: var(--font-display); font-size: var(--text-display-xs); line-height: var(--leading-snug); text-wrap: balance;
}
.faq-q::-webkit-details-marker { display: none; }
.faq-q::after { content: "+"; content: "+" / ""; flex: none; font-family: var(--font-mono); color: var(--color-highlight); }
.faq-item[open] > .faq-q::after { content: "\2212"; content: "\2212" / ""; }
.faq-a { padding: 0 var(--space-6) var(--space-5); color: var(--color-text-muted); line-height: var(--leading-body); max-width: var(--measure-wide); }

/* ---------- Insights (articles and their list) ---------- */
/* The list: one deep box per article, built from the FAQ's box. */
.insight-list { display: grid; gap: var(--space-4); max-width: var(--measure-wide); }
.insight-card { display: grid; gap: var(--space-3); padding: var(--space-6); background: var(--color-deep); border-radius: var(--radius-l); }
.insight-title { font-family: var(--font-display); font-weight: var(--weight-regular); font-size: var(--text-display-s); line-height: var(--leading-display); text-wrap: balance; }
.insight-title a { color: inherit; text-decoration: none; }
.insight-title a:hover { color: var(--color-violet-bright); }
.insight-summary { color: var(--color-text-muted); line-height: var(--leading-body); }
.insight-meta { color: var(--color-text-quiet); font-family: var(--font-mono); font-size: var(--text-mono); }

/* An article's top: a shorter hero than a page's, with a smaller title for a longer line. */
.article-hero { min-height: 0; }
.article-hero .subpage-title { font-size: var(--text-display-m); max-width: 24ch; }
.breadcrumb { font-family: var(--font-mono); font-size: var(--text-mono); color: var(--color-text-quiet); }
.breadcrumb ol { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-2); }
.breadcrumb li + li::before { content: "\203A"; content: "\203A" / ""; margin-right: var(--space-2); }
.breadcrumb a { color: var(--color-text-muted); text-decoration: none; padding-block: 0.5rem; display: inline-block; margin-block: -0.5rem; }
.breadcrumb a:hover { color: var(--color-violet-bright); }
.byline { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-3) var(--space-4); color: var(--color-text-muted); font-size: var(--text-body-s); }
.byline-photo { width: 3rem; height: 3rem; border-radius: 50%; object-fit: cover; background: rgb(158 107 242 / 0.3); }
.byline a { color: var(--color-text); text-decoration-color: var(--color-line-strong); text-underline-offset: 0.25em; }
.byline a:hover { text-decoration-color: var(--color-violet); }

/* The answer up top, boxed, so a reader and a search engine both find it first. */
.quick-answer { display: grid; gap: var(--space-2); max-width: var(--measure-wide); padding: var(--space-5) var(--space-6); background: var(--color-deep); border-radius: var(--radius-l); border-left: 3px solid var(--color-highlight); }
.quick-answer .label { margin-bottom: 0; }
.quick-answer p:last-child { font-size: var(--text-body-l); line-height: var(--leading-snug); }

/* The article's words: about 68 characters a line. */
.prose { max-width: 68ch; line-height: var(--leading-body); color: var(--color-text-muted); }
.prose > * + * { margin-top: var(--space-4); }
.prose h2 { margin-top: var(--space-8); font-family: var(--font-display); font-weight: var(--weight-regular); font-size: var(--text-display-s); line-height: var(--leading-display); text-wrap: balance; color: var(--color-text); scroll-margin-top: calc(var(--nav-height) + var(--space-5)); }
.prose h3 { margin-top: var(--space-6); font-family: var(--font-display); font-weight: var(--weight-regular); font-size: var(--text-display-xs); line-height: var(--leading-snug); color: var(--color-text); }
.prose :is(ul, ol) { padding-left: 1.4em; display: grid; gap: var(--space-2); }
.prose ul { list-style: disc; }
.prose ol { list-style: decimal; }
.prose li::marker { color: var(--color-violet-bright); }
.prose strong { color: var(--color-text); font-weight: var(--weight-semibold); }
.prose a { color: var(--color-violet-bright); text-underline-offset: 0.25em; }
.prose blockquote { padding-left: var(--space-5); border-left: 3px solid var(--color-line-strong); font-family: var(--font-display); font-size: var(--text-display-xs); line-height: var(--leading-snug); color: var(--color-text); }
.prose .table-wrap { overflow-x: auto; }
.prose table { width: 100%; border-collapse: collapse; font-size: var(--text-body-s); }
.prose :is(th, td) { padding: var(--space-3) var(--space-4); text-align: left; vertical-align: top; border-bottom: var(--hairline) solid var(--color-line); }
.prose th { color: var(--color-text); font-weight: var(--weight-medium); }
.related-list { display: grid; gap: var(--space-3); max-width: var(--measure-wide); }
.related-list a { display: inline-block; padding-block: 0.5rem; color: var(--color-violet-bright); text-underline-offset: 0.25em; }
.quick-answer + .prose { margin-top: var(--space-6); }
