/* ==========================================================================
   site.css — jamesbarber.me
   Everything except the showcase (`.demo-*` lives in demo.css, owned by
   Agent B). Loads after tokens.css. Consumes tokens only, never redefines
   them. No selector in this file starts with `.demo-`.
   ========================================================================== */

/* ---- Reset / base ---- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink-2);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: var(--fw-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
img, svg { display: block; max-width: 100%; }
/* The `hidden` attribute must always win. Without this, any rule that sets `display` on a class
   (e.g. `.embed-placeholder { display:flex }`) silently un-hides a hidden element. */
[hidden] { display: none !important; }
a { color: inherit; }

/* The dashed full-bleed dividers use 100vw pseudo-elements; this wrapper
   keeps that from ever producing a real horizontal scrollbar. Kept off
   body itself so the sticky header is never at risk. */
.page-shell { overflow-x: clip; }

/* ---- Type ---- */
h1, h2 {
  font-family: var(--font-sans);
  font-weight: var(--fw-display);
  letter-spacing: var(--ls-display);
  line-height: var(--lh-display);
  color: var(--ink-strong);
  margin: 0 0 20px;
  text-wrap: balance;
}
h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 {
  font-size: var(--fs-h3);
  font-weight: var(--fw-regular);
  line-height: 1.3;
  color: var(--ink-strong);
  margin: 0 0 6px;
}
p {
  margin: 0 0 16px;
  max-width: 60ch;
  text-wrap: pretty;
}
p:last-child { margin-bottom: 0; }
p a:not(.text-link):not(.btn) {
  color: var(--accent-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}
/* Bracket labels ("[ Backed by Y Combinator ]" on emdash.com): sans, medium, mixed case,
   accent colour. The brackets are drawn by CSS so the HTML text stays clean for machines and
   screen readers (the "/ ''" alt text hides them from assistive tech; the line before is a
   fallback for browsers that don't support alt text in `content`). */
.kicker,
.mono-label,
.wordmark__role,
.visual-label,
.stat-figure__source,
.bk-label {
  font-family: var(--font-sans);
  font-size: var(--fs-kicker);
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: var(--ls-kicker);
  text-transform: none;
  color: var(--accent-ink);
}
.kicker::before, .mono-label::before, .wordmark__role::before, .visual-label::before,
.stat-figure__source::before, .bk-label::before { content: "[\00a0"; content: "[\00a0" / ""; }
.kicker::after, .mono-label::after, .wordmark__role::after, .visual-label::after,
.stat-figure__source::after, .bk-label::after { content: "\00a0]"; content: "\00a0]" / ""; }
.kicker { margin: 0 0 22px; }
.num {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--accent-ink);
}
.mono-label {
  display: block;
  margin: 0 0 10px;
}
.mono-figure { font-family: var(--font-mono); font-size: 11px; color: var(--ink-subtle); }

/* ---- Accessibility utilities ---- */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.skip-link {
  position: absolute;
  top: -60px;
  left: 12px;
  z-index: 100;
  background: var(--btn-dark);
  color: var(--btn-dark-ink);
  padding: 12px 20px;
  border-radius: 0;
  text-decoration: none;
  font-size: var(--fs-small);
  transition: top var(--dur-fast) var(--ease-out);
}
.skip-link:focus {
  top: 12px;
}
:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }

/* ---- The frame: rails + hairlines ----
   A wide centred column with 1px rails: the viewport minus 24px each side, capped at
   --rail-max (1392px at 1440, after emdash.com). Below 768px the rails sit 16px in from
   the viewport edge so the frame stays visible on phones. */
.rail {
  /* The rail's own width, for padding maths (a padding % would be of the page, not the rail). */
  --rail-w: calc(100vw - 32px);
  position: relative;
  width: auto;
  margin-inline: 16px;
  border-left: 1px solid var(--line);
  border-right: 1px solid var(--line);
  box-sizing: border-box;
}
@media (min-width: 768px) {
  .rail { --rail-w: min(100% - 48px, var(--rail-max)); width: var(--rail-w); margin-inline: auto; }
}
/* Full-bleed dashed seams.
   Every horizontal line that runs rail to rail is drawn as a 100vw dashed pseudo-element
   instead of a rail-width hairline, so it reaches both edges of the browser. Anchored on an
   already-centred rail element: left:50% + a 100vw box shifted back by half its own width
   always lands on the viewport edges, whatever the host's own (narrower) width. The host keeps
   its 1px border as a TRANSPARENT row (layout unchanged) and the line sits exactly in that row.
   .page-shell clips the overflow so this never makes a horizontal scrollbar; the lines are
   pointer-events:none and sit in a row that holds no content, so they never cross text.
     top seams    -> ::before, in the host's transparent border-top row
     bottom seams -> ::after,  in the host's transparent border-bottom row (or, for .demo,
                     the first row of the section below) */
#approach, #know-how, #ownership, #security, #book, .site-footer,
.insight-cta, .insight-back {
  border-top-color: transparent;
}
.site-header, .insights-head, .insight-head {
  border-bottom: 1px solid transparent;
}
#approach::before, #know-how::before, #ownership::before, #security::before, #book::before,
.site-footer::before, .insight-cta::before, .insight-back::before, .demo::before,
.site-header::after, .demo::after, .insights-head::after, .insight-head::after,
.demo-tabs::after {
  content: "";
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: 100vw;
  height: 0;
  border-top: 1px dashed var(--line-dashed);
  pointer-events: none;
}
#approach::before, #know-how::before, #ownership::before, #security::before, #book::before,
.site-footer::before, .insight-cta::before, .insight-back::before, .demo::before { top: -1px; }
.site-header::after, .demo::after, .insights-head::after, .insight-head::after,
.demo-tabs::after { bottom: -1px; }

/* Seam dots: a 4px square where a dashed seam crosses a vertical line, after emdash.com.
   Placed by site.js (initSeamDots); decorative only. <main> is positioned so the dots on the
   footer's seam can live there (the footer clips its own children). */
.seam-dot {
  position: absolute;
  width: 4px;
  height: 4px;
  background: var(--seam-dot, #cbd4db);
  pointer-events: none;
  z-index: 3;
}
main { position: relative; }

/* Section rhythm: generous whitespace, hairlines between sections except
   the two dashed seams (header→hero, showcase→problem) handled above.
   .split-section and .approach-section are deliberately NOT here — they are
   edge-to-edge grids (see "Split blocks" and "Approach" below) whose OWN
   columns carry the padding, not the section itself. */
.knowhow {
  padding-block: var(--block-pad-y);
  /* padding is worked out from the rail's own width (--rail-w), so the text sits in a centred --content-max
     column. Not from 100%: a padding % is of the PARENT's width (the whole page), which grew with the window. */
  padding-inline: max(clamp(24px, 5vw, 64px), calc((var(--rail-w) - var(--content-max)) / 2));
}
#approach, #know-how, #ownership, #security, #book, .site-footer {
  border-top: 1px solid transparent;   /* the dashed seam above draws in this row */
}

/* ---- Buttons ---- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 44px;
  padding: 0 18px;
  border-radius: 0;   /* square, like emdash.com */
  font-family: var(--font-sans);
  font-size: 16px;
  font-weight: var(--fw-medium);
  text-decoration: none;
  white-space: nowrap;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}
.btn--primary { background: var(--btn-dark); color: var(--btn-dark-ink); }
.btn--primary:hover { background: var(--btn-dark-hover); }
.btn--primary:active { transform: translateY(1px); }
.btn--primary:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; box-shadow: var(--focus-ring); }

.btn--ghost { background: var(--surface-1); border-color: var(--line-pill); color: var(--ink); }
.btn--ghost:hover { border-color: var(--ink-subtle); background: var(--paper-2); }
.btn--ghost:active { transform: translateY(1px); }
.btn--ghost:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; box-shadow: var(--focus-ring); }

.btn--sm {
  height: 40px;
  font-size: 15px;
  position: relative;
}
.btn--sm::before { content: ""; position: absolute; inset: -2px; } /* expands touch target to ~44px without changing visual size */

.text-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--ink);
  font-weight: var(--fw-medium);
  text-decoration: none;
  border-bottom: 1px solid var(--ink-faint);
  padding-bottom: 2px;
  width: fit-content;
}
.text-link:hover { border-bottom-color: var(--ink); }
.text-link:hover .text-link__arrow { transform: translateX(2px); }
.text-link:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 4px; }
.text-link__arrow { transition: transform var(--dur-fast) var(--ease-out); }

/* ---- Header ---- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  /* White, and full-bleed: the 100vmax shadow paints the same white out to both browser edges (the
     clip-path stops it spilling above/below), so page lines scrolling underneath never show beside
     the bar. The header's own 1px rails still draw on top of the white. */
  background: var(--surface);
  box-shadow: 0 0 0 100vmax var(--surface);
  clip-path: inset(0 -100vmax);
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-inline: var(--gutter);
}
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--ink-strong);
  text-decoration: none;
  border-radius: 4px;
}
.wordmark__mark { color: var(--ink-strong); flex-shrink: 0; }
.wordmark__text { display: flex; flex-direction: column; line-height: 1; }
.wordmark__name { font-size: 16px; font-weight: var(--fw-medium); color: var(--ink-strong); letter-spacing: -0.01em; }
.wordmark__role {
  font-size: 11.5px;   /* bracket style comes from the shared label rule above */
  line-height: 1;
  margin-top: 5px;
  white-space: nowrap;
}

/* Main navigation: one link beside the Book button (14px, medium, like emdash.com). */
.site-nav { margin-left: auto; margin-right: clamp(16px, 2.5vw, 28px); display: flex; align-items: center; }
.site-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  color: var(--ink-strong);
  text-decoration: none;
  border-radius: 2px;
}
.site-nav a:hover { color: var(--accent-ink); }
.site-nav a[aria-current="page"] { text-decoration: underline; text-decoration-color: var(--accent); text-underline-offset: 6px; text-decoration-thickness: 1.5px; }

/* Header button: a shorter label swaps in on narrow phones so it never
   collides with the (now two-line) wordmark beside it. */
.btn__short { display: none; }

@media (max-width: 479.98px) {
  .site-header { padding-inline: 16px; }
  .wordmark { gap: 6px; }
  .wordmark__name { font-size: 14px; }
  .wordmark__role { font-size: 10.5px; letter-spacing: 0.03em; }
  .site-nav { margin-right: 12px; }
  .site-nav a { font-size: 13px; }
  .btn--sm { padding: 0 12px; font-size: 13px; gap: 5px; }
  .btn__long { display: none; }
  .btn__short { display: inline; }
}
/* Very narrow phones: tighten the header so wordmark, Insights and Book never touch. */
@media (max-width: 399.98px) {
  .site-header { padding-inline: 12px; }
  .wordmark__role { font-size: 10px; letter-spacing: 0; }
  .wordmark__role::before, .wordmark__role::after { content: "["; content: "[" / ""; }
  .wordmark__role::after { content: "]"; content: "]" / ""; }
  .site-nav { margin-right: 8px; }
  .btn--sm { padding: 0 10px; }
}

/* ---- Hero ---- */
.hero {
  min-height: clamp(360px, 52vh, 560px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  padding-block: var(--block-pad-y);
  padding-inline: max(clamp(24px, 5vw, 64px), calc((var(--rail-w) - var(--content-max)) / 2));
}
/* align-items defaults to stretch, so children take the full (and
   unambiguous) cross-size of the flex container; text-align:center then
   centres the text within it. (Deliberately not align-items:center — that
   switches children to content-based shrink-to-fit sizing, which measured
   unreliably here and let long lines overflow the container at narrow
   widths instead of wrapping.) */
.hero > * { max-width: 100%; }

/* ---- Hero: animated perspective grid ----
   A "ceiling" and a "floor" of square cells receding to a horizon behind the
   headline, drifting slowly towards the viewer. Purely decorative (the markup
   is aria-hidden): --canvas (#F7FBFC) squares outlined in a softened version of
   the site's orange accent, so it reads as texture, never content.

   The squares take the canvas fill (#F7FBFC). The outlines are
   orange because a light outline (the first version used white) is invisible
   against it: 1.04:1. --grid-line-strength softens the orange by mixing
   it with transparent, which keeps it a background rather than a feature.

   How it works: each plane is attached to the top or bottom edge of the hero
   and swung back to lie exactly flat (90deg), so it recedes AWAY from the
   viewer and converges on the vanishing point at the hero's centre. It must
   be exactly 90deg: any less and each plane's horizon overshoots the centre by
   perspective x cot(angle), so the floor and ceiling cross in the middle. Inside each plane, a grid layer slides exactly one cell and loops,
   so the motion is seamless. Only `transform` animates, so it runs on the
   GPU compositor rather than repainting every frame.

   Tuning: every knob is a custom property on .hero-grid. */
.hero { isolation: isolate; }
.hero > :not(.hero-grid) { position: relative; z-index: 1; }
.hero-grid {
  --grid-fill: var(--canvas);  /* the squares: the page canvas (#F7FBFC) */
  --grid-line: var(--accent);  /* their outlines: the site's orange */
  --grid-line-strength: 70%;   /* how much of that orange shows: 100% = full */
  --grid-line-v: 1px;          /* outlines running towards the horizon */
  --grid-line-h: 1.5px;        /* outlines running across: heavier, because
                                  lying flat foreshortens them */
  --grid-line-color: color-mix(in srgb, var(--grid-line) var(--grid-line-strength), transparent);
  --grid-cell: 64px;           /* cell size at the near edge */
  --grid-depth: 340px;         /* perspective distance: smaller = more dramatic */
  --grid-speed: 7s;            /* time to travel one cell */

  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  perspective: var(--grid-depth);
  perspective-origin: 50% 50%;
  /* Fade the grid out across the middle band, so it frames the headline
     rather than sitting behind it. (Black here is the mask's opacity, not a
     colour.) */
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, rgba(0, 0, 0, 0) 34%, rgba(0, 0, 0, 0) 66%, #000 100%);
          mask-image: linear-gradient(to bottom, #000 0%, rgba(0, 0, 0, 0) 34%, rgba(0, 0, 0, 0) 66%, #000 100%);
}
.hero-grid__plane {
  position: absolute;
  left: -50%;
  width: 200%;
  height: 300%;   /* how far back the grid runs; the mask hides the far end */
}
.hero-grid__plane--ceiling {
  top: 0;
  transform-origin: 50% 0;
  transform: rotateX(-90deg);
}
.hero-grid__plane--floor {
  bottom: 0;
  transform-origin: 50% 100%;
  transform: rotateX(90deg);
}
.hero-grid__cells {
  position: absolute;
  inset: calc(-1 * var(--grid-cell)) 0;  /* one spare cell each end, so the loop never shows a gap */
  /* Two layers, each repeating along ONE axis only (the other is 100%): a
     background tiled in both directions leaves hairline seams between tiles
     once it is transformed in 3D, which breaks the lines into dashes. */
  background-color: var(--grid-fill);
  background-image:
    linear-gradient(to right, var(--grid-line-color) var(--grid-line-v), transparent var(--grid-line-v)),
    linear-gradient(to bottom, var(--grid-line-color) var(--grid-line-h), transparent var(--grid-line-h));
  background-size: var(--grid-cell) 100%, 100% var(--grid-cell);
  background-position: center;
  will-change: transform;
  animation: hero-grid-toward-bottom var(--grid-speed) linear infinite;
}
/* "Towards the viewer" is towards each plane's attached edge: down for the
   floor, up for the ceiling. */
.hero-grid__plane--ceiling .hero-grid__cells { animation-name: hero-grid-toward-top; }
@keyframes hero-grid-toward-bottom { to { transform: translate3d(0, var(--grid-cell), 0); } }
@keyframes hero-grid-toward-top    { to { transform: translate3d(0, calc(-1 * var(--grid-cell)), 0); } }
/* Paused while the hero is scrolled out of view (site.js), to save battery. */
.hero--offscreen .hero-grid__cells { animation-play-state: paused; }
/* The kicker is small orange text sitting where the grid still shows (on
   phones especially), so a canvas-coloured halo stops the orange outlines just short of
   its letters instead of running through them. */
.hero .kicker {
  text-shadow: 0 0 2px var(--canvas), 0 0 3px var(--canvas), 0 0 5px var(--canvas), 0 0 8px var(--canvas);
}
.hero .lead {
  max-width: 640px;
  font-size: var(--fs-lead);
  color: var(--ink-2);
  margin-inline: auto;
}
.btn-row {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 14px;
}
.br-desk { display: none; }
@media (min-width: 760px) { .br-desk { display: inline; } }
.br-mob { display: none; }
@media (max-width: 479.98px) {
  /* Phones: "The AI / operating system, / built around / your business." — keeping the comma
     break as well lets text-wrap:balance split the last phrase evenly instead of orphaning "business." */
  .br-mob, .br-desk { display: inline; }
  .hero h1 { font-size: 2.125rem; }
}

/* ---- Showcase host section (bare `.demo`; `.demo-*` is Agent B's) ---- */
.demo { border-top: 1px solid transparent; }   /* the dashed seam above draws in this row */

/* ---- Split blocks (problem / ownership / security / book) ----
   The section carries NO padding of its own — .split is an edge-to-edge
   grid filling the full rail width, and each column supplies its own
   inset, so dividers and row hairlines can run flush to the rails and to
   each other. Columns stretch to the section's full height (grid default). */
.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr); /* minmax(0,…): a bare 1fr track grows to its content's min-width (e.g. a scrolling strip) and overflows the page */
}
.split__col--copy {
  padding-block: var(--block-pad-y);
  padding-inline: clamp(24px, 5vw, 64px);
}
.split__col--list,
.split__col--grid,
.split__col--embed {
  /* Stacked (<1000px): a full-width top hairline, rail to rail, is the only
     separator — the panel itself stays edge-to-edge (no side padding here;
     rows/cells below carry their own). */
  border-top: 1px solid var(--line);
}
.split__col--embed {
  background: var(--paper);
  padding: clamp(20px, 3vw, 40px);
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
@media (min-width: 1000px) {
  .split { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .split__col--list,
  .split__col--grid,
  .split__col--embed {
    border-top: none;
    border-left: 1px solid var(--line); /* the column divider, touching the section's top and bottom borders */
  }
}
/* Mirrored split (Security): copy on the RIGHT, list on the LEFT from 1000px up, with the column
   divider still between them. Stacked (phones), the copy stays first: the HTML order is untouched. */
@media (min-width: 1000px) {
  .split--flip .split__col--list { grid-column: 1; grid-row: 1; border-left: none; }
  .split--flip .split__col--copy { grid-column: 2; grid-row: 1; border-left: 1px solid var(--line); }
}
.ink-strong-p { color: var(--ink-strong); font-weight: var(--fw-regular); }

/* ---- Numbered list (problem + security right columns) ----
   Fills the whole column, edge to edge and top to bottom; each row is an
   equal third, its own padding creating the inset, its bottom hairline
   running the full column width (divider to rail). */
.numbered-list {
  list-style: none;
  margin: 0;
  padding: 0;
  height: 100%;
  display: grid;
  grid-template-rows: repeat(3, 1fr);
}
.numbered-list li {
  display: grid;
  grid-template-columns: 42px 1fr;
  align-items: start;      /* numeral lines up with the title's first line… */
  align-content: center;   /* …while the row's content stays vertically centred */
  padding: 36px clamp(24px, 4vw, 56px);
  border-bottom: 1px solid var(--line);
}
.numbered-list li:last-child { border-bottom: none; }
.numbered-list .num { padding-top: 6px; } /* optical baseline match with the 18px title */
.numbered-list h3 { color: var(--ink-strong); }
.numbered-list p { color: var(--ink-2); font-size: var(--fs-small); max-width: 42ch; }

/* ---- Problem: MIT stat ---- */
.stat-figure {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 24px;
  margin: 32px 0;
}
.stat-figure__num {
  font-size: clamp(72px, 9vw, 128px);
  font-weight: 300;
  letter-spacing: -0.05em;
  color: var(--ink-strong);
  line-height: 1;
  margin: 0;
  flex-shrink: 0;
}
.stat-figure__pct { color: var(--accent-ink); }
.stat-figure__text { max-width: 320px; }
.stat-figure__caption { color: var(--ink-2); font-size: var(--fs-small); margin: 0 0 10px; max-width: none; }
.stat-figure__source { margin: 0; max-width: none; }

/* ---- Approach ----
   `.steps` IS the edge-to-edge grid (no wrapping section padding): the
   intro block and the five step buttons share column 1, stacked top to
   bottom; every panel occupies column 2, spanning the full grid height,
   and only the active one is shown. Below 1000px this is plain block flow
   — which is exactly the accordion — so no separate mobile logic is
   needed for the button/panel relationship itself. Row placement uses
   [data-step] rather than :nth-of-type so the intro (also a <div>, like
   the panels) can't shift the count. */
.approach-intro {
  max-width: 640px;
  padding: var(--block-pad-y) clamp(24px, 5vw, 64px) 40px;
}

.steps { display: block; }
.steps-tab {
  display: grid;
  grid-template-columns: 30px 1fr;
  gap: 4px;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-top: 1px solid var(--line);
  padding-block: 22px;
  padding-inline: clamp(24px, 5vw, 64px);
  cursor: pointer;
  font: inherit;
  font-family: var(--font-sans);
  color: inherit;
  position: relative;
}
/* No bottom line on the last tab: the section's own dashed seam (#know-how::before) closes the list. */
.steps-tab .num { padding-top: 2px; }
.steps-tab__text { display: flex; flex-direction: column; gap: 4px; }
.steps-tab__title {
  font-size: 18px;
  font-weight: var(--fw-regular);
  color: var(--ink-soft);
  transition: color var(--dur-fast) var(--ease-out);
}
.steps-tab__summary { font-size: var(--fs-small); color: var(--ink-soft); }
.steps-tab::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  background: transparent;
}
.steps-tab:hover { background: var(--surface-hover); }
.steps-tab[aria-selected="true"] { background: var(--surface-active); }
.steps-tab[aria-selected="true"]::before { background: var(--accent); }
.steps-tab[aria-selected="true"] .steps-tab__title { color: var(--ink-strong); }
.steps-tab[aria-selected="true"] .num { color: var(--accent-ink); }
.steps-tab:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; }

.steps-panel {
  background: var(--paper);
  border-top: 1px solid var(--line);
  padding: clamp(32px, 5vw, 72px);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
/* `display:flex` above has the same specificity as the UA stylesheet's
   `[hidden]{display:none}` and loads after it, so without this the hidden
   (inactive) panels would render anyway. Needed at every width, not just
   the ≥1000px tab layout — this is what keeps the <1000px accordion to
   exactly one open panel. */
.steps-panel[hidden] { display: none; }
.step-visual {
  width: min(440px, 100%);
  min-height: 300px;
  margin: 0 auto 28px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  padding: 28px;
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.visual-label {
  position: absolute;
  top: 14px; left: 16px; right: 16px;
  font-size: 11.5px;
  margin: 0;
  max-width: none;
}
.step-desc { max-width: 46ch; font-size: 15px; color: var(--ink-2); margin: 0 auto; text-align: left; }

@media (min-width: 1000px) {
  .steps {
    /* Right column geometry, shared by the ticker and the step window so they can never collide:
       the window is pinned at a fixed distance below the top, whatever the step's text length. */
    --panel-pad: clamp(32px, 5vw, 72px);
    --panel-top: clamp(56px, 11vw, 160px);
    --ticker-h: 78px;
    --ticker-gap: 36px;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); /* same split as .split so the column divider lines up down the whole page */
    grid-template-rows: auto repeat(5, auto);
  }
  /* The ticker: right column, centred over the step window (same width as .step-visual), above it. */
  .steps > .ticker {
    grid-column: 2;
    grid-row: 1 / span 6;
    align-self: start;
    justify-self: center;
    position: relative;
    z-index: 1;
    width: min(440px, calc(100% - 2 * var(--panel-pad)));
    max-width: none;
    margin: var(--panel-top) 0 0;
  }
  .approach-intro { grid-column: 1; grid-row: 1; padding-bottom: 40px; }
  .steps-tab { grid-column: 1; }
  .steps-tab[data-step="1"] { grid-row: 2; }
  .steps-tab[data-step="2"] { grid-row: 3; }
  .steps-tab[data-step="3"] { grid-row: 4; }
  .steps-tab[data-step="4"] { grid-row: 5; }
  .steps-tab[data-step="5"] { grid-row: 6; }
  .steps-tab:not(:last-of-type) { border-bottom: none; }
  .steps-panel {
    grid-column: 2;
    grid-row: 1 / span 6;
    border-top: none;
    border-left: 1px solid var(--line);
    /* Top-anchored so the window sits at the same height for all five steps, under the ticker. */
    justify-content: flex-start;
    padding-top: calc(var(--panel-top) + var(--ticker-h) + var(--ticker-gap));
  }
}

/* -- Visual 1: Shadow — stacked bar + legend -- */
.stackbar { display: flex; height: 16px; border-radius: 8px; overflow: hidden; margin-bottom: 22px; }
.stackbar__seg { height: 100%; transform: scaleX(0); transform-origin: left; }
.stackbar__seg--a { width: 40%; background: var(--accent); }
.stackbar__seg--b { width: 22%; background: var(--accent-soft); }
.stackbar__seg--c { width: 38%; background: var(--line); }
.step-visual.is-active .stackbar__seg--a { animation: seg-grow var(--dur-slow) var(--ease-out) 100ms forwards; }
.step-visual.is-active .stackbar__seg--b { animation: seg-grow var(--dur-slow) var(--ease-out) 320ms forwards; }
.step-visual.is-active .stackbar__seg--c { animation: seg-grow var(--dur-slow) var(--ease-out) 540ms forwards; }
@keyframes seg-grow { to { transform: scaleX(1); } }

.visual-legend { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.visual-legend li {
  display: flex; align-items: center; gap: 10px;
  font-size: 14px; color: var(--ink-soft);
  opacity: 0; transform: translateY(6px);
  max-width: none;
}
.visual-legend__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.visual-legend .mono-figure { margin-left: auto; flex-shrink: 0; }
.swatch { width: 10px; height: 10px; border-radius: 3px; flex-shrink: 0; }
.swatch--a { background: var(--accent); }
.swatch--b { background: var(--accent-soft); }
.swatch--c { background: var(--line); }
.step-visual.is-active .visual-legend li:nth-child(1) { animation: legend-in var(--dur) var(--ease-out) 780ms forwards; }
.step-visual.is-active .visual-legend li:nth-child(2) { animation: legend-in var(--dur) var(--ease-out) 940ms forwards; }
.step-visual.is-active .visual-legend li:nth-child(3) { animation: legend-in var(--dur) var(--ease-out) 1100ms forwards; }
@keyframes legend-in { to { opacity: 1; transform: none; } }

/* -- Visual 2: Map — node/connector flow -- */
.flow {
  display: grid;
  grid-template-columns: auto minmax(10px, 1fr) auto minmax(10px, 1fr) auto minmax(10px, 1fr) auto;
  align-items: center;
}
.flow__node {
  border: 1px solid var(--line);
  background: var(--surface);
  border-radius: var(--radius-chip);
  padding: 10px 12px;
  font-size: 14px;
  color: var(--ink-strong);
  white-space: nowrap;
  text-align: center;
}
.flow__link {
  position: relative;
  margin: 0 2px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.flow__line { width: 100%; height: 1px; background: var(--line); transform: scaleX(0); transform-origin: left; }
.step-visual.is-active .flow__line { animation: line-grow var(--dur-slow) var(--ease-out) forwards; }
@keyframes line-grow { to { transform: scaleX(1); } }
.flow__link--hot .flow__line, .flow__link--tag .flow__line { background: var(--accent-ink); }
.flow__tag {
  position: absolute;
  top: -22px; left: 50%; transform: translateX(-50%);
  font-family: var(--font-sans);
  font-size: 10.5px;
  letter-spacing: 0.02em;
  color: var(--accent-ink);
  background: var(--accent-wash);
  padding: 2px 6px;
  border-radius: 4px;
  white-space: nowrap;
  opacity: 0;
}
.step-visual.is-active .flow__tag { animation: legend-in var(--dur) var(--ease-out) 500ms forwards; }
.flow__pulse {
  position: absolute;
  top: 50%; left: 50%;
  width: 10px; height: 10px;
  margin: -5px 0 0 -5px;
  border-radius: 50%;
  background: var(--accent);
  opacity: 0;
}
.step-visual.is-active .flow__pulse { animation: pulse-ring 1.8s var(--ease-out) 900ms infinite; }
@keyframes pulse-ring {
  0% { transform: scale(0.6); opacity: 0.55; }
  100% { transform: scale(2.6); opacity: 0; }
}
.flow__caption { text-align: center; font-size: 13px; color: var(--ink-soft); margin: 20px 0 0; }
@media (max-width: 479px) {
  /* Wrap to 2x2 node cards; connectors (and their "typed by hand" tags) step
     aside in favour of the caption below, which still carries the point. */
  .flow { grid-template-columns: 1fr 1fr; grid-template-rows: repeat(4, auto); gap: 10px; }
  .flow__link { display: none; }
}

/* -- Visual 3: Build — module grid -- */
.module-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 18px; }
.module-grid__tile {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 60px;
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--surface);
  font-size: 14px;
  color: var(--ink-strong);
  opacity: 0;
  transform: translateY(8px);
  text-align: center;
  padding: 4px;
}
.module-grid__tile--add { border-style: dashed; border-color: var(--line-dashed); color: var(--ink-soft); }
.step-visual.is-active .module-grid__tile { animation: tile-in var(--dur) var(--ease-out) forwards; }
.step-visual.is-active .module-grid__tile:nth-child(1) { animation-delay: 60ms; }
.step-visual.is-active .module-grid__tile:nth-child(2) { animation-delay: 160ms; }
.step-visual.is-active .module-grid__tile:nth-child(3) { animation-delay: 260ms; }
.step-visual.is-active .module-grid__tile:nth-child(4) { animation-delay: 360ms; }
.step-visual.is-active .module-grid__tile:nth-child(5) { animation-delay: 460ms; }
.step-visual.is-active .module-grid__tile:nth-child(6) { animation-delay: 560ms; }
@keyframes tile-in { to { opacity: 1; transform: none; } }
.module-caption { font-size: 14px; color: var(--ink-soft); text-align: center; margin: 0; max-width: none; }

/* -- Visual 4: Prove — score meters -- */
.meter-row { display: grid; grid-template-columns: 74px 1fr 56px; align-items: center; gap: 12px; margin-bottom: 14px; }
.meter-row__label { font-size: 14px; color: var(--ink-soft); }
.meter { display: block; height: 8px; border-radius: 4px; background: var(--line); overflow: hidden; }
.meter__fill { display: block; height: 100%; width: 0; background: var(--accent); border-radius: 4px; }
.meter-row .mono-figure { text-align: right; }
.step-visual.is-active .meter-row:nth-of-type(1) .meter__fill { animation: meter-fill var(--dur-slow) var(--ease-out) 100ms forwards; }
.step-visual.is-active .meter-row:nth-of-type(2) .meter__fill { animation: meter-fill var(--dur-slow) var(--ease-out) 500ms forwards; }
.step-visual.is-active .meter-row:nth-of-type(3) .meter__fill { animation: meter-fill var(--dur-slow) var(--ease-out) 900ms forwards; }
@keyframes meter-fill { to { width: var(--pct); } }
.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: var(--fw-medium);
  padding: 6px 12px;
  border-radius: var(--radius-pill);
  margin: 8px 0 0;
  width: fit-content;      /* stay pill-sized even inside a stretching flex/grid parent */
  align-self: flex-start;
  opacity: 0;
}
.pill--ok { background: var(--ok-wash); color: var(--ok-ink); }
.step-visual.is-active .pill { animation: legend-in var(--dur) var(--ease-out) 1500ms forwards; }

/* -- Visual 5: Hand over — checklist -- */
.checklist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 16px; }
.checklist__row { display: flex; align-items: center; gap: 12px; font-size: 14px; color: var(--ink-2); max-width: none; }
.checklist__dot { width: 20px; height: 20px; border-radius: 50%; border: 1.5px solid var(--line-pill); flex-shrink: 0; position: relative; }
.checklist__dot::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: var(--ok); opacity: 0; transform: scale(0.5);
}
.checklist__dot::before {
  content: ""; position: absolute; left: 6px; top: 3px;
  width: 5px; height: 9px;
  border-right: 1.5px solid #fff; border-bottom: 1.5px solid #fff;
  transform: rotate(45deg) scale(0);
  z-index: 1;
}
.step-visual.is-active .checklist__row:nth-child(1) .checklist__dot::after,
.step-visual.is-active .checklist__row:nth-child(1) .checklist__dot::before { animation-delay: 100ms; }
.step-visual.is-active .checklist__row:nth-child(2) .checklist__dot::after,
.step-visual.is-active .checklist__row:nth-child(2) .checklist__dot::before { animation-delay: 450ms; }
.step-visual.is-active .checklist__row:nth-child(3) .checklist__dot::after,
.step-visual.is-active .checklist__row:nth-child(3) .checklist__dot::before { animation-delay: 800ms; }
.step-visual.is-active .checklist__row:nth-child(4) .checklist__dot::after,
.step-visual.is-active .checklist__row:nth-child(4) .checklist__dot::before { animation-delay: 1150ms; }
.step-visual.is-active .checklist__dot::after { animation: dot-fill var(--dur) var(--ease-out) forwards; }
.step-visual.is-active .checklist__dot::before { animation: tick-in var(--dur) var(--ease-out) forwards; }
@keyframes dot-fill { to { opacity: 1; transform: scale(1); } }
@keyframes tick-in { to { transform: rotate(45deg) scale(1); } }

/* ---- Know-how (copy + gadget preview). The ticker now lives in the Approach section (see .steps). ---- */
.knowhow { text-align: center; display: flex; flex-direction: column; align-items: center; justify-content: center; }
.knowhow__lead { max-width: 720px; margin-inline: auto; }
.ticker {
  height: 78px;
  overflow: hidden;
  width: auto;
  max-width: 420px;
  /* Phones / tablets (<1000px): sits under the Approach intro, above the first step, lined up with
     the intro text's own left padding. */
  margin: 0 clamp(24px, 5vw, 64px) 32px;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 20%, #000 80%, transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 20%, #000 80%, transparent);
}
.ticker__track { display: flex; flex-direction: column; animation: ticker-scroll 10s linear infinite; will-change: transform; }
.ticker__item { height: 26px; display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-soft); white-space: nowrap; }
.ticker__item span { overflow: hidden; text-overflow: ellipsis; }
.ticker__icon { color: var(--ink-faint); flex-shrink: 0; }
.ticker__chevron { color: var(--ink-faint); flex-shrink: 0; margin-left: auto; }
@keyframes ticker-scroll {
  from { transform: translateY(0); }
  to { transform: translateY(-130px); }
}

/* ---- Ownership tool grid ----
   Fills the whole right column, edge to edge and top to bottom; the four
   rows share the column's height equally. Stays 2 columns even on phones —
   a single column of 8 tall cells reads far too long. */
.tool-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  height: 100%;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: repeat(4, 1fr);
}
.tool-grid > li {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  padding: 24px clamp(20px, 3vw, 40px);
  border-bottom: 1px solid var(--line);
  border-right: 1px solid var(--line);
  transition: background-color var(--dur-fast) var(--ease-out);
}
.tool-grid > li:hover { background: var(--surface-hover); }
/* The ownership tiles and the security list sit on white; the problem list above stays on canvas. */
#ownership .split__col--grid,
#security .split__col--list { background: var(--surface); }
.tool-grid > li:nth-child(2n) { border-right: none; }
.tool-grid > li:nth-last-child(-n+2) { border-bottom: none; }
.tool-grid__icon { width: 24px; height: 24px; color: var(--ink); margin-bottom: 14px; }
.tool-grid__title { font-size: 15px; font-weight: var(--fw-regular); color: var(--ink-strong); margin: 0 0 4px; }
.tool-grid__sub { font-size: 13px; color: var(--ink-soft); margin: 0; max-width: 24ch; }
@media (max-width: 479px) {
  .tool-grid > li { padding: 18px 16px; }
  .tool-grid__title { font-size: 14px; }
  .tool-grid__sub { font-size: 12.5px; }
}

/* ---- Book ---- */
.who-note { border-top: 1px solid var(--line); padding-top: 28px; margin-top: 28px; }
.who-note p:not(.mono-label) { font-size: 15px; color: var(--ink-2); }
.contact-list { font-style: normal; margin-top: 28px; display: flex; flex-direction: column; gap: 16px; }
.contact-list__row { display: flex; flex-direction: column; gap: 4px; }
.contact-list__row a {
  font-size: 16px;
  color: var(--ink-strong);
  text-decoration: none;
  border-bottom: 1px solid var(--ink-faint);
  width: fit-content;
}
.contact-list__row a:hover { border-bottom-color: var(--ink); }

/* ---- Embeds (booking + legal) ---- */
/* The booking widget sits in the same app window as the gadget previews (gadgets.css:
   .gx-window / .gx-titlebar), so it reads as one more thing built for the page. The window
   supplies the frame, so the embed inside drops its own border; the window's 13px text
   size is reset so the widget keeps its own type scale. */
.bk-window { width: 100%; font-size: var(--fs-body); line-height: var(--lh-body); }
.bk-window .embed { border: 0; }
.bk-window .gx-pill { background: var(--ok-wash); color: var(--ok-ink); }
.embed {
  min-width: 0;
  max-width: 100%;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 0;   /* square, like every other panel and button */
  overflow: hidden;
  display: flex;
  width: 100%;
}
/* The 620px minimum is a real-embed sizing rule (an iframe booking widget
   wants a stable height), not a mandate that the placeholder loom that tall
   on a phone — below 1000px the placeholder just sizes to its own content. */
@media (min-width: 1000px) {
  .embed { min-height: 620px; }
}
.embed > iframe { width: 100%; min-height: 620px; border: 0; display: block; }
.embed-placeholder {
  margin: auto;
  max-width: 320px;
  text-align: center;
  padding: 48px 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}
.embed-placeholder svg { color: var(--ink-soft); margin-bottom: 12px; }
.embed-placeholder h3 { margin-bottom: 8px; }
.embed-placeholder p { font-size: 14px; color: var(--ink-soft); margin-bottom: 20px; }

.embed--legal { max-width: 760px; min-height: 50vh; border: none; background: none; display: block; }
.embed--legal .embed-placeholder { display: block; padding: 0; text-align: left; } /* legal holding text reads as body copy under the H1 */
.embed--legal .embed-placeholder p { font-size: var(--fs-body); color: var(--ink-2); margin: 0; }
/* GetTerms always injects its own document-title heading as the very first
   element (confirmed live on all three documents) and it only ever repeats
   our own page <h1> above the embed — so it's hidden rather than shown as a
   second, duplicate top-level heading. Whatever immediately follows it
   (a <p> in every document checked) loses its top margin so there's no gap
   under our real H1. */
.embed--legal h1 { display: none; }
.embed--legal h1 + * { margin-top: 0; }
.embed--legal h2 { font-size: var(--fs-h3); font-weight: var(--fw-regular); margin: 32px 0 12px; }
.embed--legal h3 { margin: 24px 0 10px; }
.embed--legal h4 { font-size: var(--fs-small); font-weight: var(--fw-medium); color: var(--ink-strong); margin: 20px 0 8px; }
.embed--legal p, .embed--legal ul, .embed--legal ol { color: var(--ink-2); font-size: var(--fs-body); max-width: 72ch; }
.embed--legal ul, .embed--legal ol { padding-left: 22px; }
.embed--legal a { color: var(--accent-ink); text-decoration: underline; text-underline-offset: 3px; }
/* display:block lets a wide injected table scroll horizontally instead of
   overflowing the page on phones, without needing a wrapper element around
   third-party markup we don't control. */
.embed--legal table { display: block; overflow-x: auto; border-collapse: collapse; width: 100%; margin: 16px 0; font-size: 14px; }
.embed--legal table th, .embed--legal table td { border: 1px solid var(--line); padding: 8px 12px; text-align: left; }

/* ---- Legal pages (privacy / terms) ---- */
.legal-block { padding-block: var(--block-pad-y); padding-inline: clamp(24px, 5vw, 64px); }
.h2-size { font-size: var(--fs-h2); }

/* ---- 404 ---- */
.notfound {
  min-height: 60vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding-block: var(--block-pad-y);
  padding-inline: max(clamp(24px, 5vw, 64px), calc((var(--rail-w) - var(--content-max)) / 2));
}
.notfound h1 { margin-bottom: 28px; }

/* ---- Footer ---- */
.site-footer {
  min-height: 96px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding-block: 24px;
  padding-inline: clamp(24px, 5vw, 64px);
  font-size: 14px;
  color: var(--ink-soft);
  /* White and full-bleed, like the header. */
  background: var(--surface);
  box-shadow: 0 0 0 100vmax var(--surface);
  clip-path: inset(0 -100vmax);
}
.site-footer p { margin: 0; max-width: none; }
.site-footer nav { display: flex; flex-wrap: wrap; gap: 8px 24px; }
.site-footer nav a,
.site-footer .footer-action { color: var(--ink-soft); text-decoration: none; }
/* "Cookie preferences" performs an action rather than navigating, so it is a
   <button> — styled here to read as one more footer link. */
.site-footer .footer-action {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  line-height: inherit;
  cursor: pointer;
}
.site-footer nav a:hover,
.site-footer .footer-action:hover { color: var(--ink); }
.site-footer nav a[aria-current="page"] { color: var(--ink); }

/* ---- Scroll reveal (progressive enhancement: safe with JS off) ---- */
body.js-reveal .reveal {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--dur) var(--ease-out), transform var(--dur) var(--ease-out);
}
body.js-reveal .reveal.is-in { opacity: 1; transform: none; }

/* ---- Reduced motion: switch off every animation/transition on the page ---- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; }
  body.js-reveal .reveal { opacity: 1 !important; transform: none !important; }
  .stackbar__seg { transform: scaleX(1) !important; }
  .visual-legend li { opacity: 1 !important; transform: none !important; }
  .flow__line { transform: scaleX(1) !important; }
  .flow__tag { opacity: 1 !important; }
  .flow__pulse { opacity: 0 !important; animation: none !important; }
  .module-grid__tile { opacity: 1 !important; transform: none !important; }
  .meter__fill { width: var(--pct) !important; }
  .pill { opacity: 1 !important; }
  .checklist__dot::after { opacity: 1 !important; transform: scale(1) !important; }
  .checklist__dot::before { transform: rotate(45deg) scale(1) !important; }
  .ticker__track { animation: none !important; transform: none !important; }
  .hero-grid__cells { animation: none !important; transform: none !important; }  /* a still grid, no drift */
}

/* 404: framed block fills the viewport so the rails never stop mid-page */
.notfound { min-height: calc(100vh - var(--header-h)); min-height: calc(100svh - var(--header-h)); }
