/* ==========================================================================
   Carth marketing site, by Carthagent.
   One stylesheet, no build step, no external assets.

   Design notes for whoever edits this next:

   - The palette is lifted from the product itself (src/styles.css) so the site
     and the cockpit read as one thing: purple #6b5b95 on a warm near white.
     Every text pair below was measured, the ratio is in the comment beside it.
   - Three colours carry meaning and nothing else does. Purple is the product
     and its structure. Clay is work in progress, the crew and the building.
     Green is approval: gates, ticks, anything a person said yes to. Teal and
     blue appear only as two of the four crew characters, so the crew reads as
     four people rather than four copies of one.
   - No gradients anywhere. Solid fills only, per the brand rules.
   - The motif is the cothon, Carthage's circular harbour, which is already the
     product's logomark: a ring with exactly one opening. It is the whole
     governance argument in one shape, so it carries the hero, the section
     markers and the favicon.
   - Type is a pair with two jobs. The display face is an old style serif, the
     same family of shapes the harbour motif comes from, and it carries every
     headline and price. The text face is Inter Variable, self hosted from
     site/fonts, because it is what the product itself is set in: the site and
     the cockpit read as one thing. Nothing is fetched from a CDN, so the site
     works offline, in a container, and behind a strict CSP.
   ========================================================================== */

/* Space Grotesk Variable, latin subset, SIL OFL - the V3 display face. 13KB. */
@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fonts/space-grotesk-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+2000-206F, U+20AC, U+2122;
}

/* Inter Variable, latin subset, SIL Open Font Licence. The licence text sits
   next to the file in site/fonts/. One file, one axis, 48KB. */
@font-face {
  font-family: "Inter Variable";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/inter-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* ink and ground ------------------------------------------------------- */
  --ink: #211e1a;          /* 15.24:1 on --surface, 16.60:1 on --card */
  --muted: #4f4a42;        /*  8.07:1 on --surface, 8.78:1 on --card, 7.70:1 on --tint */
  --surface: #f7f5f1;      /* warm near white */
  --card: #ffffff;
  --line: #e8e4dd;
  --line-strong: #d8d2c7;
  --deep: #2a2622;         /* the one dark band, --surface on it is 13.79:1 */
  --deep-line: #453f38;
  --deep-muted: #cfc8bd;   /*  9.04:1 on --deep */

  /* accent --------------------------------------------------------------- */
  --accent: #6b5b95;       /*  5.42:1 on --surface, white on it is 5.91:1 */
  --accent-strong: #574a7c;/*  7.21:1 on --surface, white on it is 7.85:1 */
  --accent-soft: #f1eff6;
  --accent-line: #d9d3e6;

  /* work in progress: the crew, the building, anything still moving -------- */
  --warm: #a24b1e;         /*  5.42:1 on --surface, white on it is 5.90:1 */
  --warm-soft: #fbf1e9;    /* --ink on it is 14.91:1, --warm on it is 5.60:1 */
  --warm-line: #ecd7c4;

  /* approval: gates, ticks, anything a person said yes to ------------------ */
  --ok: #1f6b46;           /*  5.93:1 on --surface, white on it is 6.46:1 */
  --ok-soft: #ecf4ef;      /* --ink on it is 14.82:1, --ok on it is 5.77:1 */
  --ok-line: #cbe0d4;

  /* status, used sparingly and only where measured ------------------------ */
  --teal: #17636b;         /*  6.36:1 on --surface */
  --info: #1e3b90;         /*  9.26:1 on --surface */
  --hold: #b4482f;         /*  4.93:1 on --surface */

  /* the dark ground: the header and the landing view sit on it, so it is the
     first thing anybody sees. Every value below was measured against it. */
  --band: #1a1714;         /* white on it is 17.85:1 */
  --band-text: #ded7cb;    /* 12.48:1 on --band, the hero paragraph */
  --band-muted: #c4bdb2;   /*  9.58:1 on --band, captions and notes */
  --band-lav: #cbbfe4;     /* 10.29:1 on --band, eyebrows and gate bars */
  --band-warm: #f0c9a8;    /* 11.58:1 on --band, the crew and the claim */

  /* The CTA. One colour, one button: the apply button in the header, on every
     page, in both languages. It is --band-warm given a second job rather than a
     new hue, so the palette does not grow to make one control louder. */
  --cta: #f0c9a8;          /* 11.58:1 against --band as a shape */
  --cta-ink: #211e1a;      /* 10.77:1 on --cta */
  --cta-hover: #f7dcc2;    /* 13.57:1 against --band, ink on it 12.62:1 */
  --band-ok: #8fd3ae;      /* 10.28:1 on --band, approval */
  --band-line: #2a2521;    /* hairlines inside the dark */
  --band-edge: #6b645b;    /*  3.06:1 on --band, outlined control borders */

  /* the crew, lightened to live on the dark ground, one hue each */
  --crew-plan: #b9a8d8;    /*  8.21:1 on --band */
  --crew-build: #f0c9a8;   /* 11.58:1 on --band */
  --crew-review: #8ecfd7;  /* 10.25:1 on --band */
  --crew-report: #a5bdf0;  /*  9.47:1 on --band */

  /* a wash of the product's own purple, for the one band that needs to be
     quieter than white but nowhere near the manifesto */
  --tint: #f1eff6;         /* --ink 14.56:1, --muted 6.19:1, --accent-strong 6.88:1 */

  /* type ----------------------------------------------------------------- */
  /* V3 (2026-08-19): Space Grotesk replaces the serif as the display face. The token
     keeps its historical name so every page inherits the change untouched. */
  --serif: "Space Grotesk", "Inter Variable", system-ui, sans-serif;
  --sans: "Inter Variable", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;

  /* measure -------------------------------------------------------------- */
  --page: 1120px;
  --prose: 68ch;
  --radius: 12px;
  --radius-sm: 8px;
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

@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;
  }
}

img, svg { max-width: 100%; }

/* Typography ------------------------------------------------------------- */

h1, h2, h3, h4 {
  font-family: var(--serif);
  /* Space Grotesk carries weight differently from the old serif: 500 with negative
     tracking is the V3 display voice; 600 read too heavy in the prototype. */
  font-weight: 500;
  line-height: 1.12;
  letter-spacing: -0.02em;
  margin: 0;
  text-wrap: balance;
}

h1 { font-size: clamp(2.25rem, 1.5rem + 3vw, 3.5rem); letter-spacing: -0.02em; }
h2 { font-size: clamp(1.75rem, 1.3rem + 1.7vw, 2.4rem); letter-spacing: -0.012em; }
h3 { font-size: 1.2rem; line-height: 1.3; }
h4 { font-size: 1rem; line-height: 1.35; }

p { margin: 0 0 1rem; }
p:last-child { margin-bottom: 0; }

a { color: var(--accent-strong); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--ink); }

strong, b { font-weight: 650; }

/* The utility face: small uppercase labels, the same device the cockpit uses
   for its nav groups, so the site speaks the product's visual language. */
.eyebrow {
  display: block;
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-strong);
  margin: 0 0 0.75rem;
}
.eyebrow-quiet { color: var(--muted); }
.on-deep .eyebrow { color: #cbbfe4; } /* 8.05:1 on --deep */

.lede {
  font-size: clamp(1.05rem, 1rem + 0.4vw, 1.25rem);
  color: var(--muted);
  max-width: var(--prose);
}
.on-deep .lede { color: var(--deep-muted); }

.small { font-size: 0.9rem; }
.mono { font-family: var(--mono); font-size: 0.86em; letter-spacing: -0.01em; }

/* Skip link and focus ---------------------------------------------------- */

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--accent-strong);
  color: #fff;
  padding: 0.7rem 1.1rem;
  border-radius: 0 0 var(--radius-sm) 0;
  font-weight: 600;
}
.skip:focus { left: 0; color: #fff; }

:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}
.on-deep :focus-visible { outline-color: #b9a8d8; }

/* Layout ----------------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--page);
  margin: 0 auto;
  padding: 0 1.5rem;
}

/* Vertical rhythm.
   Measured at a 1440px viewport: each section carried 104px of padding top and bottom, so
   the band between the last line of one section and the first word of the next was 208px
   plus the margins inside it. That reads as a page that failed to load rather than as
   breathing room. It is 76px a side now, so 152px between sections - still generous, and
   still enough for each section to land as its own thing. */
.section { padding: clamp(3rem, 1.75rem + 4vw, 4.75rem) 0; }
.section-tight { padding: clamp(2.25rem, 1.5rem + 3vw, 3.25rem) 0; }
.section-line { border-top: 1px solid var(--line); }

.section-head { max-width: var(--prose); margin-bottom: 2.1rem; }
.section-head p { margin-top: 0.9rem; }

.section-tint { background: var(--tint); }
.on-deep { background: var(--deep); color: var(--surface); }
.on-deep h2, .on-deep h3, .on-deep h4 { color: var(--surface); }
.on-deep a { color: #cbbfe4; }
.on-deep a:hover { color: #fff; }

/* Buttons ---------------------------------------------------------------- */

.btn {
  display: inline-block;
  font-family: var(--sans);
  font-size: 0.98rem;
  font-weight: 600;
  line-height: 1.2;
  padding: 0.82rem 1.35rem;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.btn-primary { background: var(--accent); color: #fff; }          /* 5.91:1 */
.btn-primary:hover { background: var(--accent-strong); color: #fff; } /* 7.85:1 */

/* The one CTA colour. It belongs to the header apply button and to nothing
   else on the site, which is the whole reason it works: a visitor learns in one
   screenful that the warm slab in the dark bar is the thing to press. Clay,
   because green is reserved for approval and purple is already the product's
   own structure, and the light clay rather than the dark one because it sits on
   the near-black band, where a light fill is the loudest thing available and
   still takes ink text at 10.77:1. See BRAND.md section 3, "The CTA colour". */
.btn-cta { background: var(--cta); color: var(--cta-ink); border-color: var(--cta); }  /* 10.77:1 */
.btn-cta:hover { background: var(--cta-hover); color: var(--cta-ink); border-color: var(--cta-hover); } /* 12.62:1 */
.btn-secondary { background: transparent; color: var(--ink); border-color: var(--line-strong); }
.btn-secondary:hover { background: var(--card); border-color: var(--accent); color: var(--ink); }
/* The border is the only thing giving this button a shape on a dark block, so it is a
   UI component boundary and owes 3:1. #5c554c measured 2.04:1 on --deep and 2.43:1 on
   --band: a control outline nobody could quite see, on every dark section of the site.
   #7d7468 was already the hover value, so it is a palette colour rather than a new one,
   and it clears 3:1 on BOTH dark grounds (3.27 and 3.88). Hover moves up in step. */
.on-deep .btn-secondary { color: var(--surface); border-color: #7d7468; }
.on-deep .btn-secondary:hover { background: #35302b; color: #fff; border-color: #948b7e; }

.btn-row { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 1.9rem; }

/* Header ----------------------------------------------------------------- */

/* The header is dark on every page. On the home page it merges into the dark
   landing view below it and the two read as one field; on the light pages it
   is the top half of a frame the dark footer closes. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--band);
  border-bottom: 1px solid var(--band-line);
}
.site-header :focus-visible { outline-color: var(--band-lav); }
.header-inner {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  min-height: 74px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  color: #fff;                        /* 17.85:1 on --band */
  font-weight: 700;
  font-size: 1.12rem;
  letter-spacing: 0.02em;
  margin-right: auto;
}
.brand:hover { color: #fff; }
.brand .mark { color: var(--crew-plan); flex: 0 0 auto; }
.brand .brand-sub {
  font-family: var(--sans);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--band-muted);           /* 9.58:1 on --band */
  border-left: 1px solid #3a332d;
  padding-left: 0.6rem;
  margin-left: 0.15rem;
}

.nav-toggle {
  display: none;
  align-items: center;
  gap: 0.5rem;
  background: transparent;
  border: 1px solid var(--band-edge); /* 3.06:1 on --band */
  border-radius: var(--radius-sm);
  padding: 0.5rem 0.75rem;
  font: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  color: #fff;
  cursor: pointer;
}

.nav { display: flex; align-items: center; gap: 1.45rem; }
/* Between the last destination and the call to action, so the button reads as the end of
   the list rather than one more link in it. */
.nav .btn-cta { margin-left: 0.35rem; }
.nav a {
  color: var(--band-text);            /* 12.48:1 on --band */
  text-decoration: none;
  font-size: 0.95rem;
  font-weight: 500;
  padding: 0.4rem 0;
  border-bottom: 2px solid transparent;
  /* A destination is one word or it is one phrase, never a phrase broken over
     two lines. French sets these labels longer than English does, and a header
     where two items are two lines tall and four are one is the raggedest thing
     on the page. The row is allowed to run out of space, which the breakpoint
     below then answers; it is not allowed to wrap. */
  white-space: nowrap;
}
.nav a:hover { color: #fff; border-bottom-color: var(--crew-plan); }
.nav a[aria-current="page"] { color: #fff; border-bottom-color: var(--crew-plan); }
.nav .btn { padding: 0.6rem 1.05rem; font-size: 0.92rem; border-bottom: 0; }
.nav .btn:hover { border-bottom: 0; }
.nav .btn-primary:hover { color: #fff; }
/* The header CTA keeps its ink text through hover and focus. The header's own
   focus ring is --band-lav, which reads against both the band and the clay. */
.nav .btn-cta, .nav .btn-cta:hover { color: var(--cta-ink); }

/* The language switcher. Two links to the same page in the other tree, and a
   hairline between them. It sits outside the nav panel on purpose: a visitor who
   landed in the wrong language should not have to open a menu written in it, so
   this stays on the bar at every width. The language you are reading is the one
   marked, and it still links to itself so the pair never changes shape. */
/* The language switcher is a SETTING, not a destination, so it sits to the right of the
   menu with a hairline between them rather than inside the list of places to go. */
.lang {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  flex: 0 0 auto;
  margin-left: 1.4rem;
  padding-left: 1.4rem;
  border-left: 1px solid var(--band-line);
}
.lang a {
  color: var(--band-muted);           /* 9.58:1 on --band */
  text-decoration: none;
  padding: 0.4rem 0;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  /* The switcher is set smaller than the nav, so with the nav's padding it
     builds a shorter box, and two boxes of different heights centred on the
     same row put their underlines on two different lines: the marked language
     appeared to float above the nav's own current-page rule. Borrowing the
     nav's line box, not its font size, makes the two underlines land on one
     line and the two texts share a baseline, while the switcher stays the
     quieter of the two. */
  line-height: calc(0.95rem * 1.65);
}
.lang a:hover { color: #fff; border-bottom-color: var(--crew-plan); }
.lang a[aria-current] { color: #fff; border-bottom-color: var(--crew-plan); }
.lang-sep { color: var(--band-edge); }  /* 3.06:1 on --band, non-text */

/* The header carries EIGHT destinations, a button and the language switcher, and
   the breakpoint below is what decides when that row folds into a panel.

   IT WAS MEASURED FOR SIX. The note that used to sit here worked the number out
   honestly - 679px of links in English, 707px in French, folding at 1040px with
   36px of slack - and then two more destinations were added to the markup and
   nobody measured again. The row does not wrap (see .nav a), so past its limit it
   does not squeeze or fold: it runs straight through the right edge of the wrap
   and takes the whole page's horizontal scroll with it. A visitor on an ordinary
   laptop got a crowded header AND a page that slid sideways, which is the same
   defect seen twice.

   Re-measured against the values actually in this file: the eight links set
   623px, their seven gaps 162px, the call to action 130px with its margin, the
   lockup 185px, the switcher 55px, the two header gaps 48px and the wrap padding
   48px. The row needs about 1250px in English and, with the longer French
   labels, about 1310px. So it folds at 1280px, which keeps English comfortable
   and French honest, and it is re-derived here rather than nudged so the next
   person to add a destination can see what the number is made of.

   IF A NINTH DESTINATION IS ADDED, this number moves again. Eight is already
   more than a header should carry; the cheaper fix next time is to drop one. */
/* THE INTERMEDIATE BAND, where the row is tightened rather than hidden.
   MEASURED IN A BROWSER THIS TIME, which is the only reason these numbers are worth
   anything. The note above this one was arithmetic - add up the labels, the gaps, the
   lockup and the switcher - and arithmetic got it wrong by two hundred pixels: at 1440,
   the width of an ordinary laptop, the language switcher was pushed 22px past the right
   edge and clipped, which is the white gap that got reported. Rendered and measured, the
   full row needs about 1480px in English and about 1540px in French.
   Folding at 1560px would be correct and awful: every laptop made would get a hamburger.
   So between the fold and the width where everything fits comfortably, the row is made
   SMALLER instead - a tighter gap, a slightly smaller label, and the CARTHAGENT wordmark
   dropped from the lockup, which together buy about 190px and bring French down to around
   1350. The brand itself never goes; only its second half, which is the one part of the
   header that repeats what the logo beside it already says. */
@media (max-width: 1560px) and (min-width: 1281px) {
  .header-inner { gap: 1rem; }
  .nav { gap: 0.95rem; }
  .nav a { font-size: 0.9rem; }
  .nav .btn { padding: 0.55rem 0.85rem; font-size: 0.88rem; }
  .brand .brand-sub { display: none; }
}

@media (max-width: 1280px) {
  .nav-toggle { display: inline-flex; }
  .header-inner { gap: 0.85rem; }
  /* The nav goes out of flow below this width, so without explicit order the Menu button
     would jump ahead of the language switcher purely because of where the nav sits in the
     markup. Keep the reading order the same at every width. */
  .lang { font-size: 0.78rem; gap: 0.35rem; order: 2; margin-left: 0; padding-left: 0; border-left: 0; }
  .nav-toggle { order: 3; }
  .nav .btn-cta { margin-left: 0; }
  .nav {
    display: none;
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--band);
    border-bottom: 1px solid var(--band-line);
    padding: 0.5rem 1.5rem 1.25rem;
  }
  .nav.is-open { display: flex; }
  .nav a {
    padding: 0.8rem 0;
    border-bottom: 1px solid var(--band-line);
  }
  .nav a:hover { border-bottom-color: var(--band-line); }
  .nav a[aria-current="page"] { border-bottom-color: var(--band-line); }
  .nav .btn { margin-top: 0.9rem; text-align: center; }
  .header-inner { position: relative; }
}

/* Hero ------------------------------------------------------------------- */

/* The landing view is dark and it is the loudest thing on the site. Everything
   below it breathes light again, and the page closes dark at the trust strip
   and the footer, so the dark is a frame rather than a mood. */
/* The whole point of the landing view is that the headline, the slide it
   belongs to and both buttons are on screen together. That is what sets the
   headline ceiling and the padding here, not a wish for bigger type. */
.hero {
  background: var(--band);
  color: #fff;
  padding: clamp(2.5rem, 1.5rem + 3.5vw, 4.25rem) 0 clamp(3.5rem, 2.5rem + 5vw, 6rem);
}
.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
  gap: clamp(2.5rem, 1rem + 5vw, 5rem);
  /* START, not centre. The five slides have very different figure heights, so
     centring meant every slide aligned its two columns differently: the headline
     landed somewhere new each time the carousel advanced, which is what read as
     "off". Aligned to the top, the eyebrow and the diagram start on the same line
     on every slide, and the carousel stops moving underneath the reader. */
  align-items: start;
}
/* The optical nudge that makes "same line" true rather than merely equal: the
   eyebrow is small caps with its own leading, so a diagram whose first mark sits
   flush at y=0 would read as slightly high against it. */
.hero-grid > *:last-child { padding-top: 0.35rem; }

/* The diagrams are drawn on a 470x420 viewBox and stretch to whatever column they
   are given, so on a wide screen they were growing to fill it and pushing their own
   caption blocks apart. Capped and centred, every slide's figure occupies the same
   optical width and the small-caps labels underneath keep a constant rhythm. */
.hero-slide .figure { max-width: 34rem; margin-inline: auto; }
.hero-slide .figure svg { display: block; width: 100%; height: auto; }
.hero-slide .figure figcaption { margin-top: 1.5rem; max-width: 46ch; }
/* One h1 on the page, and it belongs to the first slide. The other seven
   headlines are h2s that read at exactly the same size, because they are the
   same thing in the same place: the page's opening sentence. */
.hero h1,
.hero .hero-h {
  margin-bottom: 1.1rem;
  font-family: var(--serif);
  font-weight: 600;
  color: #fff;                                        /* 17.85:1 on --band */
  font-size: clamp(2.4rem, 1.5rem + 3.1vw, 3.85rem);
  letter-spacing: -0.025em;
  line-height: 1.04;
}
.hero .eyebrow { color: var(--band-lav); }            /* 10.29:1 */
.hero .lede { font-size: clamp(1.1rem, 1rem + 0.55vw, 1.3rem); color: var(--band-text); } /* 12.48:1 */
.hero .figure figcaption { color: var(--band-muted); }/*  9.58:1 */
/* A caption may point at a page that carries the long version of what it just
   claimed. On this ground the link takes the lavender, underlined by the
   global rule, and the focus ring is the light one: the brand purple is 3.02:1
   against the band and a ring you cannot see is not a ring. */
.hero .figure figcaption a { color: var(--band-lav); }/* 10.29:1 */
.hero .figure figcaption a:hover { color: #fff; }     /* 17.85:1 */
.hero :focus-visible { outline-color: #b9a8d8; }
.hero .btn-secondary { color: #fff; border-color: var(--band-edge); }
.hero .btn-secondary:hover { background: #262019; border-color: #8b8377; color: #fff; }
/* The one warm sentence in the hero. Clay, because it is a claim about the
   work getting done rather than about the gates. 11.58:1 on --band. */
.hero-claim {
  margin-top: 1.3rem;
  font-family: var(--serif);
  font-size: clamp(1.08rem, 1rem + 0.4vw, 1.32rem);
  line-height: 1.4;
  color: var(--band-warm);
  border-left: 3px solid #8c6547;
  padding-left: 0.95rem;
  max-width: 44ch;
}

/* The line under the buttons answers "so what happens if I press that". It
   carries no marker: a coloured dot beside a sentence reads as a live status
   light, and green is reserved for things a person approved. Quiet type on its
   own measure says "a note" without pretending to be an indicator. */
.hero-note {
  margin-top: 1.6rem;
  font-size: 0.92rem;
  color: var(--band-muted);           /* 9.58:1 on --band */
  max-width: 62ch;                    /* holds it to two lines on a desktop */
}

@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; }
  /* On one column the text and the drawing are already stacked, so the slack
     in the reserved box has nowhere useful to go but the bottom. Placing it
     there keeps the first line of all eight slides on the same rule, which at
     this width is the only alignment a reader can see at all. */
  .js .hero-slide { align-content: start; }
}

/* The cothon diagram, the page's signature element ------------------------
   The harbour is drawn once and then set in motion at the bottom of this file.
   Everything here is the still frame: it has to read on its own, because that
   is exactly what somebody with reduced motion switched on will see. */

.cothon { display: block; width: 100%; height: auto; }
.cothon .ring { fill: none; stroke: var(--crew-plan); }      /*  8.21:1 on --band */
.cothon .ring-faint { fill: none; stroke: #4a433c; }
.cothon .isle { fill: var(--accent); }                       /*  3.02:1 as a shape, white on it 5.91:1 */
.cothon .gatebar { stroke: var(--band-lav); fill: none; }    /* 10.29:1 */

/* Each crew member is one group carrying its own colour in --c, so the disc,
   the face, the label, the path and the dot it sends all match without four
   near identical rule blocks. The same four faces turn up in the other hero
   drawings, so the rules that describe a crew member are shared with them and
   only the harbour's own furniture is scoped to the harbour.
   Ratios on --band: plan 8.21:1, build 11.58:1, review 10.25:1, report 9.47:1,
   all of them shapes and small labels above the 4.5:1 the labels need. */
.cothon .crew, .hero-svg .crew { --c: var(--crew-plan); }
.cothon .crew-build, .hero-svg .crew-build { --c: var(--crew-build); }
.cothon .crew-review, .hero-svg .crew-review { --c: var(--crew-review); }
.cothon .crew-report, .hero-svg .crew-report { --c: var(--crew-report); }

.cothon .disc, .hero-svg .disc { fill: #221d19; stroke: var(--c); stroke-width: 2.2; }
.cothon .halo { fill: none; stroke: var(--c); stroke-width: 1.5; opacity: 0; }
.cothon .eye, .hero-svg .eye { fill: var(--c); }
.cothon .brow, .hero-svg .brow { stroke: var(--c); stroke-width: 2.4; stroke-linecap: round; fill: none; }
.cothon .mouth, .hero-svg .mouth { stroke: var(--c); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; fill: none; }
.cothon .lane { stroke: var(--c); stroke-width: 1.5; stroke-dasharray: 3 6; fill: none; opacity: 0.45; }
.cothon .dot { fill: var(--c); }
.cothon .dot-trunk { fill: var(--band-lav); }
.cothon .trunk { stroke: #4a433c; stroke-width: 1.5; stroke-dasharray: 3 6; fill: none; }

/* Light green disc, dark check: the reverse of the light page, and 10.28:1. */
.cothon .tick circle { fill: var(--band-ok); }
.cothon .tick path { stroke: var(--band); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; fill: none; }

/* The two layers above the crew, and the one below it -----------------------
   A mission is not a flat crew of four. Carth runs many missions at once, each
   mission has a team manager, and the manager spins up the agents that brief
   needs. The stack of three chips is the mission layer: the front one is drawn
   in full and the two behind it are outlines, which is the cheapest honest way
   to say "one of several" inside a ring this size. The bracket under the front
   chip is the spawn, and the hub at the collecting point is Carth itself.

   Ratios on --band (#1a1714): --band-lav 10.29:1 as a shape and as text,
   --band-edge 3.06:1, which is what a shape carrying meaning has to clear, and
   white 17.85:1 for the manager's own name. The engine under each agent is
   --band-muted at 9.58:1: quieter than the role name above it by colour, not
   by size, so it stays inside the 9.5px floor the diagram scale sets. */
.cothon .mgr { fill: var(--band); stroke: var(--band-lav); stroke-width: 1.8; }
.cothon .mgr-back { fill: none; stroke: var(--band-edge); stroke-width: 1.5; }
.cothon .spawn { fill: none; stroke: var(--band-edge); stroke-width: 1.5; stroke-linecap: round; }
.cothon .hub { fill: var(--band); stroke: var(--band-lav); stroke-width: 1.8; }
.cothon .mark-line { stroke: var(--band-lav); fill: none; }
.cothon .mark-dot { fill: var(--band-lav); }
.cothon .mgr-name { font-family: var(--sans); font-size: 9.5px; font-weight: 700; letter-spacing: 0.06em; fill: #fff; text-transform: uppercase; }

/* The engine an agent runs on is a fact about the agent, so it is written
   under the agent's own name. It is text and never colour alone: the four crew
   hues say who, these two lines say what runs them. */
.cothon .elabel { font-family: var(--sans); font-size: 9.5px; font-weight: 700; letter-spacing: 0.06em; fill: var(--band-muted); text-transform: uppercase; }

.cothon .label { font-family: var(--sans); font-size: 11px; font-weight: 700; letter-spacing: 0.08em; fill: var(--band-muted); text-transform: uppercase; }
.cothon .label-ink { fill: #fff; }
.cothon .label-sm { font-size: 9.5px; letter-spacing: 0.07em; }
.cothon .clabel { font-family: var(--sans); font-size: 9.5px; font-weight: 700; letter-spacing: 0.07em; fill: var(--c); text-transform: uppercase; }

/* The crew's names in French, and only there ------------------------------
   PLANIFICATEUR is thirteen characters where PLANNER is seven, and the two
   discs they sit under are a fixed distance apart because the harbour is
   drawn, not laid out. In the English tree those two labels clear each other
   by 41px; in French, at the same tracking, by 2px, which the eye reads as one
   long word rather than two roles.

   Of the three ways out, this is the one that costs nothing else. Shrinking
   the type would drop it under the 9.5px floor the scale sets for diagram
   labels; moving the discs would redraw the composition and every lane and
   travelling dot that lands on it. Tracking is the one dimension here that is
   decoration rather than meaning, so the French labels give some of it back
   and stay positive, as uppercase labels on this site always are. */
[lang="fr"] .cothon .clabel,
[lang="fr"] .hero-svg .clabel { letter-spacing: 0.02em; }

/* The other seven hero drawings -------------------------------------------
   One vocabulary, seven pictures, all on --band: a chip is a named thing, a
   panel is a place, a dashed lane is work moving and a solid dot on it is the
   work itself. Nothing is coloured for effect. Purple is structure, clay is
   work in progress, green is approval, and the four crew hues belong to the
   four crew members and to nothing else.

   Ratios on --band (#1a1714): --band-text 12.48:1, --band-muted 9.58:1,
   --band-lav 10.29:1, --band-warm 11.58:1, --band-ok 10.28:1, white 17.85:1,
   white on --accent 5.91:1, and --band-edge 3.06:1, which is a shape colour
   and never carries a word.

   Chips and panels are drawn on the band itself rather than on the crew disc's
   #221d19, and that is a contrast decision rather than a taste one: the edge
   grey clears 3:1 against the band but only 2.86:1 against the lighter fill,
   and an outline is worth nothing if it is the thing you cannot see. The two
   grounds are 1.07:1 apart, so nothing is lost by dropping one of them. */

.hero-svg { display: block; width: 100%; height: auto; }

.hero-svg .label { font-family: var(--sans); font-size: 9.5px; font-weight: 700; letter-spacing: 0.08em; fill: var(--band-muted); text-transform: uppercase; }
.hero-svg .label-ink { fill: #fff; }
.hero-svg .clabel { font-family: var(--sans); font-size: 9.5px; font-weight: 700; letter-spacing: 0.07em; fill: var(--c); text-transform: uppercase; }

.hero-svg .panel { fill: var(--band); stroke: var(--band-edge); stroke-width: 1.5; }
.hero-svg .panel-lav { stroke: var(--band-lav); }
.hero-svg .chip { fill: var(--band); stroke: var(--band-edge); stroke-width: 1.5; }
.hero-svg .chip-name { font-family: var(--sans); font-size: 12.5px; font-weight: 600; fill: var(--band-text); }
.hero-svg .chip-dot { fill: var(--band-edge); }
.hero-svg .lane { stroke: var(--band-edge); stroke-width: 1.5; stroke-dasharray: 3 6; fill: none; }
.hero-svg .hflow { fill: var(--band-lav); }
.hero-svg .node { fill: var(--band); stroke: var(--band-lav); stroke-width: 1.8; }  /* 10.29:1 as a shape */
/* A row is a line of something written: a line of a file in the update, a line
   of a ticket on the board. It is never a word, so it is drawn in the edge
   grey, which is 3.06:1 on the band and reads as texture rather than text. */
.hero-svg .row { stroke: var(--band-edge); stroke-width: 3; stroke-linecap: round; fill: none; }

/* The gate is drawn the same way it is drawn in the harbour, because it is the
   same gate: two bars, a purple island, and your name on it. And a tick is a
   light green disc with a dark mark cut out of it, everywhere it appears. */
.hero-svg .gatebar { stroke: var(--band-lav); fill: none; }
.hero-svg .isle { fill: var(--accent); }
.hero-svg .isle-name { font-family: var(--sans); font-size: 12px; font-weight: 700; letter-spacing: 0.06em; fill: #ffffff; }
.hero-svg .tick circle { fill: var(--band-ok); }     /* 10.28:1 */
.hero-svg .tick path { stroke: var(--band); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; fill: none; }

/* 2. The keys. Eight providers as eight identical chips, four on each side of
   the cockpit, and the equality is deliberate: with your key every provider in
   this list can run the reviewing, advising and analysis work, so nothing in
   the geometry may say that one of them counts for more. Every chip is the
   base .hero-svg .chip, the same shape the repo chips and the tool chips use:
   the band's own ground inside a --band-edge outline at 3.06:1 as a shape,
   with the name in --band-text at 12.48:1. Same size, same spacing, same lane
   into the core, no fill against an outline and no dashes.

   The one asymmetry that is true, that missions build and ship on Claude and
   Codex, is written in words under the stack instead. A fill, a bigger box or
   a column of its own would encode importance, and importance is not what the
   difference is.

   Ratios on --band: chip outline --band-edge 3.06:1 as a shape, chip name and
   provider mark --band-text 12.48:1, labels --band-muted 9.58:1, the core
   outline and its mark --band-lav 10.29:1, and the travelling feed dots
   --band-lav 10.29:1 as shapes. */
/* Provider marks, inlined path data tinted with the chip's own text colour
   (BRAND section 6, provider surfaces exception). A mark is a meaningful shape
   and must clear 3:1 against the chip ground; at --band-text it clears the
   same 12.48:1 the name beside it does. All eight are the same colour, because
   all eight chips are. */
.hprov .pmark { fill: var(--band-text); }        /* 12.48:1 on --band */
.hprov .core { fill: var(--band); stroke: var(--band-lav); stroke-width: 2; }
.hprov .core-name { font-family: var(--sans); font-size: 13px; font-weight: 700; letter-spacing: 0.1em; fill: var(--band-lav); }
.hprov .mark-line { stroke: var(--band-lav); fill: none; }
.hprov .mark-dot { fill: var(--band-lav); }
.hprov .feed { fill: var(--band-lav); }          /* 10.29:1 as a shape */

/* 3. The cost of asking twice, and the shape that removes it. One drawing in
   two halves with a rule between them, because the claim is a comparison.

   The left half carries no colour at all, and that is the argument rather than
   a shortage of ideas. Everything there is --band-edge, 3.06:1 on the band and
   a shape colour, under labels in --band-muted at 9.58:1: the same four
   bubbles, the same loop, and tokens falling out of the bottom of the picture.

   The right half is the product's own furniture, so it takes the structure
   colour, --band-lav at 10.29:1: the plan panel, the lanes, the engine dots and
   the gate. The engine dots are one big and two small and size is the only
   thing telling them apart, because size is the only thing being said. The
   isle is the brand purple with white on it at 5.91:1, exactly as it is in the
   harbour, and the one green is the tick past the gate at 10.28:1.

   Labels here are 10.5px where the other drawings use 9.5px. This is the only
   hero drawing built as two columns, so its longest label has half the frame
   to live in, and the scale allows anything from 9.5px to 11px. */
.honce .label { font-size: 10.5px; }
/* The one divider. It groups, so it is held to the 3:1 a meaningful shape has
   to clear rather than to the hairline used for furniture inside the dark. */
.honce .rule { stroke: var(--band-edge); stroke-width: 1; fill: none; }   /* 3.06:1 */
.honce .loop-ring,
.honce .loop-head {
  stroke: var(--band-edge); stroke-width: 1.8; fill: none;                /* 3.06:1 */
  stroke-linecap: round; stroke-linejoin: round;
}
/* A bubble is a chip that says nothing: the band's own ground, the same 3.06:1
   outline every chip carries, and three dots where a sentence would be. All
   four are identical, because they are the same prompt. */
.honce .bub-box { fill: var(--band); stroke: var(--band-edge); stroke-width: 1.5; stroke-linejoin: round; }
.honce .bub-dot { fill: var(--band-edge); }
.honce .drip,
.honce .tok { fill: var(--band-edge); }
.honce .eng { fill: var(--band-lav); }                                    /* 10.29:1 as a shape */

/* 4. The code map. Six communities, six hues, and the hue is the only thing
   telling them apart, so each one is a colour the page already uses for a
   member of the crew or for the product itself. Links inside a community take
   its colour; the few that cross take the neutral edge, which is what makes
   the crossings legible as crossings. */
.cgraph .cl { --c: var(--crew-plan); }   /* c1 takes this one and needs no rule */
.cgraph .c2 { --c: var(--crew-build); }
.cgraph .c3 { --c: var(--crew-review); }
.cgraph .c4 { --c: var(--crew-report); }
.cgraph .c5 { --c: var(--band-ok); }
.cgraph .c6 { --c: var(--band-lav); }
.cgraph .cl circle { fill: var(--c); }
.cgraph .link { stroke: var(--c); stroke-width: 0.7; fill: none; }
.cgraph .link-far { stroke: var(--band-edge); stroke-width: 0.7; fill: none; }

/* 5. The update, on any repository. Five text chips carry the breadth of the
   claim and nothing else in the picture changes: it is one worktree, one file
   changed, one shield and one gate. The worktree is marked with four corner
   brackets in the same lavender as the harbour wall, because it is the same
   wall seen closer up. */
.hcms .bracket { stroke: var(--crew-plan); stroke-width: 2; fill: none; stroke-linecap: round; }
.hcms .row-change { stroke: var(--band-warm); }      /* 11.58:1, the one change */
.hcms .row-dot { fill: var(--band-edge); }
.hcms .row-mark { fill: var(--band-warm); }
.hcms .shield-body { stroke: var(--band-ok); stroke-width: 2; fill: none; stroke-linejoin: round; }
.hcms .shield-tick { stroke: var(--band-ok); stroke-width: 2.6; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.hcms .chip-out { stroke: var(--band-ok); }          /* what left through the gate */

/* 6. The board and the tools beside it. A card is a chip by another name, so
   it is drawn the same way: the band's own ground inside a 3.06:1 outline,
   nested inside the column it sits in, exactly as the repo chips nest inside
   their panel one slide earlier.

   The colour argument is the whole slide. Clay marks the ticket the crew
   drafted, because that is work in progress. Green appears once, on the tick
   in the done column, because approval is the only thing green ever means.
   Lavender is structure, so it carries the lanes, the stage nodes and the one
   chip that is a door rather than a product: any MCP server you allow. */
.hjira .card { fill: var(--band); stroke: var(--band-edge); stroke-width: 1.5; }  /* 3.06:1 as a shape */
.hjira .tag { fill: none; stroke: var(--band-warm); stroke-width: 1.2; }          /* 11.58:1 */
.hjira .tag-name {
  font-family: var(--sans); font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.07em; fill: var(--band-warm); text-transform: uppercase;      /* 11.58:1 */
}
/* A tie is solid and a lane is dashed, and the difference carries meaning: a
   lane is work moving, a tie only says "this is that". The board hangs off the
   chip that names it, and nothing is flowing down that line. */
.hjira .tie { stroke: var(--band-edge); stroke-width: 1.5; fill: none; }  /* 3.06:1 */
.hjira .chip-open { stroke: var(--band-lav); }       /* the open door, not a product */
.hjira .chip-dot-open { fill: var(--band-lav); }
/* The one divider in the drawing. It groups, so it is held to the 3:1 that a
   meaningful shape has to clear rather than to the hairline value used for
   furniture inside the dark, which would be 1.18:1 here and invisible. */
.hjira .rule { stroke: var(--band-edge); stroke-width: 1; fill: none; }  /* 3.06:1 */

/* 7. The question. The guard is lavender and not green: nobody approved
   anything here, the database is simply refusing to be written to. */
.hdata .ask { font-family: var(--sans); font-size: 14px; fill: var(--band-text); }
.hdata .lock rect, .hdata .lock path { fill: none; stroke: var(--band-lav); stroke-width: 2; }
.hdata .strip { fill: #221d19; stroke: var(--band-line); stroke-width: 1; }  /* --band-text on it 11.68:1 */
.hdata .sql { font-family: var(--mono); font-size: 11px; fill: var(--band-text); } /* 12.48:1 on --band */
.hdata .bars rect { fill: var(--crew-report); }      /* the analyst's own hue */
.hdata .axis { stroke: var(--band-edge); stroke-width: 1.5; fill: none; }

/* 8. The architecture, adapted from the isolation diagram on the trust page
   and moved onto the dark ground.

   Three colour decisions, all of them arguments rather than taste.

   There is no green in this drawing. Green means a person approved something,
   everywhere else on this site, and nobody approved anything here: the kernel
   keeps these containers apart whether or not anybody is watching. A padlock
   in the approval colour would be a decoration wearing the meaning of a gate,
   so the lock work is lavender, which is what structure is drawn in. It is the
   same reasoning that keeps the read only guard on the data slide lavender.

   Your container carries the lavender outline and the other carries the plain
   3.06:1 edge, which is the only difference between them. Everything inside is
   drawn identically, because that is the claim: the next company holds the
   same three things and reaches none of yours.

   The empty third column is dashed in the edge grey, which is how this page
   draws a thing that is real in principle and not running yet.

   Ratios on --band: white 17.85:1, --band-muted 9.58:1, --band-lav 10.29:1 and
   --band-edge 3.06:1 as a shape. The crew dots are the four crew hues at
   8.21:1, 11.58:1, 10.25:1 and 9.47:1. */
.hiso .co-name { font-family: var(--sans); font-size: 13px; font-weight: 700; fill: #fff; }  /* 17.85:1 */
.hiso .wall { stroke: var(--band-lav); stroke-width: 3; stroke-linecap: round; fill: none; } /* 10.29:1 as a shape */
.hiso .mark-line { stroke: var(--band-lav); fill: none; }
.hiso .mark-dot { fill: var(--band-lav); }
/* Four dots, one hue each, which is the shorthand the whole page uses for the
   crew. They sit under the cockpit's own mark, so the row reads as one thing
   the container holds rather than as four passengers. */
.hiso .cd-plan { fill: var(--crew-plan); }      /*  8.21:1 */
.hiso .cd-build { fill: var(--crew-build); }    /* 11.58:1 */
.hiso .cd-review { fill: var(--crew-review); }  /* 10.25:1 */
.hiso .cd-report { fill: var(--crew-report); }  /*  9.47:1 */
.hiso .vol ellipse, .hiso .vol path { fill: none; stroke: var(--band-lav); stroke-width: 1.8; }
/* The seam across the middle of the volume is texture, never a word, so it
   takes the edge grey the same way a row of a file does. */
.hiso .vol .vol-line { stroke: var(--band-edge); stroke-width: 1.4; }   /* 3.06:1 */
.hiso .key circle, .hiso .key path { fill: none; stroke: var(--band-lav); stroke-width: 2; stroke-linecap: round; }
.hiso .next-box { fill: none; stroke: var(--band-edge); stroke-width: 1.5; stroke-dasharray: 5 4; }  /* 3.06:1 */
.hiso .next-plus { stroke: var(--band-edge); stroke-width: 2.5; stroke-linecap: round; fill: none; }

/* The manifesto band ------------------------------------------------------
   The one place on the site where type is the entire design. The landing view
   holds the dark, so this is its inverse: a white slab in the middle of the
   page, cut from the warm sections around it by two hairlines, arriving right
   after the six steps as the eight word version of them.

   Two nouns are coloured, and only those two, because the page has already
   taught what the colours mean. Clay is the crew and the work. Green is the
   gate and the approval. The sentence is the colour key. */

.manifesto {
  background: var(--card);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: clamp(4rem, 2.5rem + 7vw, 8rem) 0;
}

.manifesto-h {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(2.3rem, 0.9rem + 6.6vw, 4.65rem);
  font-weight: 600;
  line-height: 1.06;
  letter-spacing: -0.025em;
  color: var(--ink);        /* 16.60:1 on --card */
}

/* Each sentence is its own line box. The padding is what keeps the descenders
   in the p and the g alive once the line is clipped for the reveal. */
.mline { display: block; padding-bottom: 0.16em; }
.mline > span { display: block; text-wrap: balance; }
.mline + .mline { margin-top: 0.04em; }

.m-crew { color: var(--warm); }       /* 5.90:1 on --card */
.m-gate { color: var(--ok); }         /* 6.46:1 on --card */

.manifesto-sub {
  margin: clamp(1.6rem, 1rem + 1.8vw, 2.5rem) 0 0;
  font-size: clamp(0.95rem, 0.9rem + 0.3vw, 1.08rem);
  color: var(--muted);                /* 8.78:1 on --card */
  max-width: 48ch;
}

/* The hero slider ----------------------------------------------------------
   Eight slides, and a slide is one piece: the headline, its sentence and its
   drawing arrive and leave together. There is no second thing moving at the
   same time, which is why the rotating line that used to sit under the
   headline is gone.

   Three decisions carry the whole feature.

   One, the slides are stacked in a single grid cell. The box is therefore
   always as tall as the tallest slide and the page cannot move when a slide
   changes: there is no reserved height to guess at per breakpoint and nothing
   to keep in step with the copy, because the browser measures it.

   Two, the stack only exists when something can run it. Without scripting the
   eight slides are ordinary blocks down the page, all readable and all in the
   document, which is also what a crawler sees. The .js class is set in the
   head before the body renders, so there is no flash of eight stacked slides.

   Three, inside that fixed box the two columns are aligned differently on
   purpose. The box is as tall as the tallest slide, so every shorter slide has
   slack to place, and centring the whole slide spent that slack at the top:
   the text columns are all different heights, so centred columns started on
   different lines. Measured at 1280 on the six slides this had before the
   architecture one arrived: 98, 153, 136, 136, 185 and 185 pixels down. The
   eyebrow moved 87 pixels between slides and floated in the middle of nowhere
   on the opening one.

   So the text column is anchored to the top of the box and every eyebrow,
   headline and sentence lands on the same line on all eight slides, while the
   drawing keeps align-items: center and sits in the middle of the frame. The
   slack collects at the bottom, beside a picture, where it reads as air rather
   than as a gap. Nothing about the reserved height changes, so the buttons and
   the dots underneath still never move.

   The hidden slides are hidden with visibility, not display, so every word
   stays in the layout and the box keeps its measured height. */

.hero-slides { display: grid; gap: clamp(2.5rem, 1rem + 4vw, 4rem); }

.js .hero-slides { gap: 0; }
.js .hero-slide {
  grid-area: 1 / 1;
  display: grid;
  opacity: 0;
  visibility: hidden;
}
.js .hero-slide.is-on { opacity: 1; visibility: visible; }

/* The words are anchored, the picture is centred. On one column this rule is
   inert, because there the two are stacked and nothing has room to slide.
   Scoped to the hero on purpose: .hero-grid is borrowed further down the page
   by the daily view, which has no reserved height, no slack to place and
   therefore nothing to anchor against. */
.hero .hero-grid > *:first-child { align-self: start; }

/* The controls carry no content and do nothing without scripting, so they are
   only shown once there is something to control. Unlike the stepper further
   down the page they survive reduced motion: nothing advances on its own
   there, but the eight slides are still yours to move through. */
.hero-dots {
  display: none;
  gap: 0.4rem;
  margin-top: clamp(1.4rem, 1rem + 1.2vw, 2rem);
}
.js .hero-dots { display: flex; }

.herodot {
  width: 2rem;
  height: 2rem;
  display: grid;
  place-items: center;
  padding: 0;
  font-family: var(--mono);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--band-muted);           /*  9.58:1 on --band */
  background: transparent;
  border: 1px solid var(--band-edge); /*  3.06:1, a shape */
  border-radius: 50%;
  cursor: pointer;
}
.herodot:hover { color: #fff; border-color: var(--band-lav); }
.herodot[aria-current="true"] {
  color: #fff;                        /*  5.91:1 on --accent */
  background: var(--accent);
  border-color: var(--accent);
}
/* The page's focus ring is the brand purple, which is too dark to see against
   the band. On this ground the ring is the light lavender instead. */
.herodot:focus-visible { outline: 3px solid #b9a8d8; outline-offset: 2px; }

/* Plain explanatory diagrams (the isolation drawing on the trust page). */
/* Capped near its drawn size: stretched to the full page width the labels blow
   up to headline scale and the drawing shouts over the prose. */
.diagram { display: block; width: 100%; max-width: 700px; height: auto; margin: 0 auto; }
.diagram .box { fill: var(--card); stroke: var(--line-strong); stroke-width: 1.5; }
.diagram .box-accent { fill: var(--accent-soft); stroke: var(--accent-line); stroke-width: 1.5; }
.diagram .host { fill: var(--surface); stroke: var(--line-strong); stroke-width: 1.5; }
.diagram .wall { stroke: var(--accent); stroke-width: 3; stroke-linecap: round; }
.diagram .mark-fill { fill: var(--accent); }
.diagram .label {
  font-family: var(--sans); font-size: 10px; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; fill: var(--muted);
}
.diagram .name { font-family: var(--sans); font-size: 12.5px; font-weight: 600; fill: var(--ink); }

/* The provider orchestration diagram --------------------------------------
   Same drawn language as the harbour, on the light ground: one chip per
   provider with its mark beside its name, one Carth node in the middle, and
   the crew on the way out. */

.orch { display: block; width: 100%; height: auto; max-width: 760px; margin: 0 auto; }
.orch .chip { fill: var(--card); stroke: var(--line-strong); stroke-width: 1.5; }
.orch .chip-name { font-family: var(--sans); font-size: 13px; font-weight: 600; fill: var(--ink); }
.orch .chip-dot { fill: var(--muted); }

/* One kind of provider chip, the same reasoning as .hprov on the band. Every
   provider chip carries the same outline, the same size, the same spacing and
   the same lane into the cockpit, because on the customer's own key every one
   of them runs the reviewing, advising and analysis roles. The earlier version
   split them into a live chip and a dashed quiet chip, which drew a ranking the
   product does not have. The one true asymmetry, that the building and shipping
   roles run on Claude or Codex, is written in the drawing's own words instead.

   The chip ground is --card inside an --accent outline: 5.42:1 against the
   --surface page ground and 5.91:1 against the white it encloses, so the chip
   edge reads as a shape from either side. --line-strong would have been 1.50:1
   on --card, under the 3:1 a shape needs, which is why the outline every chip
   now shares is the accent one rather than the hairline. */
.orch .chip-prov { fill: var(--card); stroke: var(--accent); }
/* Provider marks in the providers diagram, same rule as .hprov: inlined path
   data in the chip's own text colour, and a mark is a meaningful shape that
   must clear 3:1 against its chip ground. All eight are one colour, because
   all eight chips are. */
.orch .pmark { fill: var(--ink); }         /* 16.60:1 on --card */
.orch .core { fill: var(--card); stroke: var(--accent); stroke-width: 2; }
.orch .core-name { font-family: var(--sans); font-size: 13px; font-weight: 700; letter-spacing: 0.1em; fill: var(--accent-strong); }
.orch .mark-line { stroke: var(--accent); fill: none; }
.orch .mark-dot { fill: var(--accent); }
.orch .lane { stroke: var(--line-strong); stroke-width: 1.5; stroke-dasharray: 3 6; fill: none; }
.orch .feed { fill: var(--accent-strong); }
.orch .out { fill: var(--accent-soft); stroke: var(--accent-line); stroke-width: 1.5; }
.orch .out-name { font-family: var(--sans); font-size: 13px; font-weight: 600; fill: var(--ink); }
.orch .label { font-family: var(--sans); font-size: 9.5px; font-weight: 700; letter-spacing: 0.08em; fill: var(--muted); text-transform: uppercase; }

.orch .role { --c: var(--accent); }
.orch .role-build { --c: var(--warm); }
.orch .role-review { --c: var(--teal); }
.orch .role-report { --c: var(--info); }
.orch .role .chip { stroke: var(--c); }
.orch .role .chip-name { fill: var(--c); }
.orch .role .chip-dot { fill: var(--c); }
.orch .relay { fill: var(--c); }

/* Cards and grids -------------------------------------------------------- */

.grid { display: grid; gap: 1.25rem; }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

@media (max-width: 980px) {
  .grid-3, .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: minmax(0, 1fr); }
}

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.5rem;
}
/* The lift itself lives in the motion section. What is left here is the part
   that still helps somebody with motion switched off: the border answers. */
.card:hover { border-color: var(--accent-line); }
.on-deep .card:hover { border-color: #5c554c; }
.card h3 { margin-bottom: 0.55rem; }
.card p { color: var(--muted); font-size: 0.97rem; }
.on-deep .card { background: #332e29; border-color: var(--deep-line); }
.on-deep .card p { color: var(--deep-muted); }

/* Capability cards ------------------------------------------------------- */
/* One drawn glyph, one honest sentence, and where it matters the sentence
   about what the connection cannot do. The note is pushed to the bottom of
   the card so the notes line up across a row and the eye can read down them
   as a column of guarantees rather than hunting for them inside prose. */

.cap { display: flex; flex-direction: column; }

.cap-glyph {
  display: block;
  margin-bottom: 1.05rem;
  color: var(--accent);               /* 5.91:1 on --card, shapes need 3:1 */
}
/* The two second colours obey the palette: clay is work in progress, green is
   the thing a person approved. Nothing else in a glyph is coloured. */
.cap-glyph .g-fill { fill: var(--accent); stroke: none; }
.cap-glyph .g-work { fill: var(--warm); stroke: none; }        /* 5.90:1 on --card */
.cap-glyph .g-gate { stroke: var(--ok); }                      /* 6.46:1 on --card */
/* A node sitting on top of its own edges: filled with the card so the line
   stops at the circle instead of running through it. */
.cap-glyph .g-knock { fill: var(--card); }

.cap h3 { margin-bottom: 0.5rem; }
.cap p { margin-bottom: 1.15rem; }

.cap .cap-note {
  margin: auto 0 0;                   /* auto top: it sits on the card floor */
  padding-top: 0.9rem;
  border-top: 1px solid var(--line);
  display: flex;
  gap: 0.55rem;
  font-size: 0.88rem;
  line-height: 1.55;
  color: var(--muted);                /* 8.78:1 on --card */
}
.cap-note .dot {
  width: 7px;
  height: 7px;
  margin-top: 0.52em;
  border-radius: 50%;
  background: var(--accent);          /* structure, not approval */
  flex: 0 0 auto;
}

/* The trademark line under the grid, same register as a figure caption. */
.grid-note {
  max-width: var(--prose);
  margin: 1.6rem 0 0;
  font-size: 0.88rem;
  color: var(--muted);                /* 8.07:1 on --surface */
}

/* Step list, numbered because the order is real: a mission runs this way
   and the sequence is the reader's mental model. */
.steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1.1rem;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  counter-reset: step;
}
@media (max-width: 980px) { .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px) { .steps { grid-template-columns: minmax(0, 1fr); } }

.steps li {
  counter-increment: step;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.4rem 1.4rem 1.5rem;
  position: relative;
}
.steps li::before {
  content: "0" counter(step);
  display: block;
  font-family: var(--mono);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--accent-strong);
  margin-bottom: 0.7rem;
}
/* The two steps a person owns are green, the colour this site uses for
   approval and nothing else. The four the crew owns stay neutral. */
.steps li.is-gate { border-color: var(--ok-line); background: var(--ok-soft); }
.steps li.is-gate::before { color: var(--ok); }
.steps li.is-crew::before { color: var(--warm); }
.steps h3 { font-size: 1.08rem; margin-bottom: 0.4rem; }
.steps p { color: var(--muted); font-size: 0.95rem; margin: 0; }
.step-tag {
  display: inline-block;
  margin-top: 0.9rem;
  font-family: var(--sans);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ok);
  background: var(--card);
  border: 1px solid var(--ok-line);
  border-radius: 999px;
  padding: 0.2rem 0.6rem;
}
.step-who {
  display: inline-block;
  margin-top: 0.9rem;
  font-family: var(--sans);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--warm);
  background: var(--warm-soft);
  border: 1px solid var(--warm-line);
  border-radius: 999px;
  padding: 0.2rem 0.6rem;
}

/* The step glyphs. Small, drawn, one per step, in the colour that step already
   owns: green for the two a person holds, clay for the four the crew holds. */
.step-glyph { display: block; margin-bottom: 0.8rem; color: var(--accent-strong); }  /* 7.85:1 on --card */
.steps li.is-crew .step-glyph { color: var(--warm); }                                /* 5.90:1 on --card */
.steps li.is-gate .step-glyph { color: var(--ok); }                                  /* 6.46:1 on --ok-soft */

/* The stepper --------------------------------------------------------------
   Six steps that are all on the page, all readable, all in order. The stepper
   only ever POINTS at one of them. It never hides the other five, so a crawler,
   a printer and a visitor who asked for less motion all get the whole thing.
   The spotlight is a ring and a lift rather than dimming the rest, because
   dimming five cards to make one stand out would put five cards under AA. */
.stepper-wrap { margin-top: 0; }
.stepper li.is-on {
  box-shadow: 0 0 0 2px var(--accent), 0 8px 22px rgba(33, 30, 26, 0.08);
}

/* The controls carry no content, so they are hidden until there is something
   to control: see the motion block, which is the only place they are shown. */
.stepper-bar { display: none; margin-top: 1.5rem; align-items: center; gap: 0.8rem; }
.stepdots { display: flex; gap: 0.4rem; }
.stepdot {
  width: 2rem;
  height: 2rem;
  display: grid;
  place-items: center;
  padding: 0;
  font-family: var(--mono);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--muted);                /* 8.78:1 on --card */
  background: var(--card);
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  cursor: pointer;
}
.stepdot:hover { border-color: var(--accent-line); }
.stepdot[aria-current="step"] {
  color: var(--card);                 /* white on --accent, 5.91:1 */
  background: var(--accent);
  border-color: var(--accent);
}
.stepdot:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The clock, drawn. It fills over one step's worth of time, and reaching the
   end is what moves the spotlight on. */
.steprail {
  flex: 1;
  height: 3px;
  border-radius: 999px;
  background: var(--line);
  overflow: hidden;
}
.steprail-fill {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--accent);          /* 4.66:1 on --line */
  transform: scaleX(0);
  transform-origin: left center;
}

/* Read more. Collapsed by default, and the words stay in the document either
   way: this is a disclosure, not a lazy load. */
.more { margin-top: 1.1rem; }
.more > summary {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  cursor: pointer;
  list-style: none;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--accent-strong);        /* 7.21:1 on --surface */
}
.more > summary::-webkit-details-marker { display: none; }
.more > summary::after {
  content: "";
  width: 6px;
  height: 6px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
}
.more[open] > summary::after { transform: translateY(1px) rotate(-135deg); }
.more > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 3px; }
.more > p {
  margin: 0.75rem 0 0;
  max-width: var(--prose);
  font-size: 0.95rem;
  color: var(--muted);                /* 8.07:1 on --surface */
}

/* Feature rows with the ring marker -------------------------------------- */

.ruleset { display: grid; gap: 1.6rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 820px) { .ruleset { grid-template-columns: minmax(0, 1fr); } }

.rule { display: flex; gap: 1rem; align-items: flex-start; }
.rule .ring-mark { flex: 0 0 auto; margin-top: 3px; color: var(--accent); } /* 5.18:1 on --tint */
.rule h3 { font-size: 1.12rem; margin-bottom: 0.45rem; }
.rule p { margin: 0; }

/* Product illustrations: simplified drawings of the cockpit, not screenshots.
   They are deliberately flatter and quieter than the real UI. */

.figure { margin: 0; }
.figure figcaption {
  margin-top: 0.85rem;
  font-size: 0.85rem;
  color: var(--muted);
  max-width: 60ch;
}
.on-deep .figure figcaption { color: var(--deep-muted); }

.mock {
  background: var(--card);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  padding: 1.1rem;
  color: var(--ink);
  font-size: 0.9rem;
}
.mock-bar {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding-bottom: 0.85rem;
  margin-bottom: 0.95rem;
  border-bottom: 1px solid var(--line);
}
.mock-bar .mark { color: var(--accent); flex: 0 0 auto; }
.mock-title { font-weight: 700; font-size: 0.92rem; letter-spacing: 0.01em; }
.mock-role {
  margin-left: auto;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-strong);
  background: var(--accent-soft);
  border-radius: 999px;
  padding: 0.15rem 0.6rem;
}
.mock h4 {
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.7rem;
}

.queue { list-style: none; margin: 0 0 0.2rem; padding: 0; display: grid; gap: 0.5rem; }
.queue li {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.65rem 0.8rem;
  background: var(--surface);
}
.queue .pip { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; background: var(--ok); }
.queue .pip-hold { background: var(--hold); }
.queue .pip-run { background: var(--warm); }
.queue .qtitle { font-weight: 600; font-size: 0.88rem; min-width: 0; }
.queue .qmeta { margin-left: auto; font-family: var(--mono); font-size: 0.74rem; color: var(--muted); white-space: nowrap; }
.queue .qwait {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ok);
  white-space: nowrap;
}

.mock-foot {
  margin-top: 0.9rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--line);
  display: flex;
  gap: 1.4rem;
  flex-wrap: wrap;
  font-size: 0.78rem;
  color: var(--muted);
}
.mock-foot b { color: var(--ink); font-family: var(--mono); font-size: 0.82rem; font-weight: 600; }

/* Evidence strip illustration */
.evidence { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.6rem; }
@media (max-width: 520px) { .evidence { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.evidence figure { margin: 0; }
.evidence svg {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.evidence figcaption {
  margin-top: 0.35rem;
  font-size: 0.7rem;
  color: var(--muted);
  line-height: 1.35;
}
.thumb .frame { fill: var(--card); }
.thumb .bar { fill: var(--accent); }
.thumb .bar-soft { fill: var(--accent-line); }
.thumb .rule-line { stroke: var(--line-strong); }
.thumb .ink-line { stroke: var(--muted); }
.thumb .ok { fill: var(--ok); }

.gatebox {
  margin-top: 1rem;
  border: 1px solid var(--ok-line);
  background: var(--ok-soft);
  border-radius: var(--radius-sm);
  padding: 0.85rem 0.95rem;
  display: flex;
  align-items: center;
  gap: 0.8rem;
  flex-wrap: wrap;
}
.gatebox .gate-q { font-weight: 600; font-size: 0.9rem; }
.gatebox .fake-btn {
  font-size: 0.78rem;
  font-weight: 700;
  border-radius: 6px;
  padding: 0.35rem 0.75rem;
  border: 1px solid var(--ok);
  color: #fff;              /* 6.46:1 on --ok */
  background: var(--ok);
}
.gatebox .fake-btn-quiet { background: var(--card); color: var(--ink); border-color: var(--line-strong); }
.gatebox .gate-who { margin-left: auto; font-size: 0.76rem; color: var(--muted); }

/* Tables ----------------------------------------------------------------- */

.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

table.matrix {
  width: 100%;
  min-width: 620px;
  border-collapse: collapse;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-size: 0.94rem;
}
table.matrix caption {
  caption-side: bottom;
  text-align: left;
  padding-top: 0.85rem;
  font-size: 0.85rem;
  color: var(--muted);
}
table.matrix th, table.matrix td {
  text-align: left;
  padding: 0.8rem 1rem;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}
table.matrix thead th {
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--surface);
}
table.matrix tbody th { font-weight: 650; font-size: 0.97rem; }
table.matrix tbody tr:last-child th,
table.matrix tbody tr:last-child td { border-bottom: 0; }
table.matrix .role-note { display: block; font-weight: 400; font-size: 0.82rem; color: var(--muted); }

.flag {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border-radius: 999px;
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--line-strong);
  color: var(--muted);
  background: var(--surface);
}
.flag-yes { color: var(--accent-strong); background: var(--accent-soft); border-color: var(--accent-line); }
.flag-own { color: var(--info); background: #eef1f9; border-color: #cfd7ea; }
.flag-no { color: var(--muted); }

/* Pricing ---------------------------------------------------------------- */

/* The trial sits above the paid tiers as one wide card, because it is the real
   entry point: every plan begins with the same application. */
.tier-lead {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr) auto;
  gap: 1.5rem;
  align-items: center;
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  border-radius: var(--radius);
  padding: 1.5rem;
  margin-bottom: 1.1rem;
}
.tier-lead .tier-price { margin-top: 0.4rem; }
.tier-lead p { font-size: 0.95rem; color: var(--muted); margin: 0; }
.tier-lead .btn { white-space: nowrap; }
@media (max-width: 860px) {
  .tier-lead { grid-template-columns: minmax(0, 1fr); gap: 1rem; }
  .tier-lead .btn { justify-self: start; }
}

.tiers {
  display: grid;
  gap: 1.1rem;
  /* Three plans since Solo was withdrawn (2026-08-31): Team, Business, Enterprise. The
     count is deliberate and must match the number of cards: it once said repeat(4) with
     three cards and left an empty fourth column, which read as a row missing something,
     because it was. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: stretch;
}
/* Three cards go straight from three columns to one. The old intermediate two column
   step existed for four plans, where it made a tidy 2x2; with three it would strand the
   last card alone beside a gap, which is the same "row missing something" this grid is
   careful to avoid. Three columns hold their width down to here because there is one
   fewer card sharing the row than there used to be. */
@media (max-width: 900px) { .tiers { grid-template-columns: minmax(0, 1fr); } }

.tier {
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.5rem 1.4rem;
}
.tier-featured { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.tier-name { font-family: var(--serif); font-size: 1.25rem; font-weight: 600; }
.tier-flag {
  display: inline-block;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-strong);
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  border-radius: 999px;
  padding: 0.15rem 0.55rem;
  margin-left: 0.5rem;
  vertical-align: 2px;
}
.tier-price {
  font-family: var(--serif);
  font-size: 2rem;
  font-weight: 600;
  line-height: 1.1;
  margin: 0.7rem 0 0.15rem;
  letter-spacing: -0.015em;
}
.tier-price .per { font-family: var(--sans); font-size: 0.85rem; font-weight: 500; color: var(--muted); letter-spacing: 0; }
.tier-line { font-size: 0.9rem; color: var(--muted); margin-bottom: 1.1rem; }
/* What happens to the price after the founding batch. It sits under the number rather
   than beside it, because a price and a condition on that price must never be read as
   one phrase. */
.tier-after { font-size: 0.82rem; color: var(--accent-strong); margin: 0 0 0.5rem; } /* 7.85:1 on --card */
.tier ul { list-style: none; margin: 0 0 1.5rem; padding: 0; display: grid; gap: 0.55rem; font-size: 0.92rem; }
.tier ul li { display: flex; gap: 0.55rem; align-items: flex-start; }
.tier ul li::before {
  content: "";
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  margin-top: 0.55em;
  border-radius: 50%;
  border: 1.5px solid var(--accent);
}
.tier .btn { margin-top: auto; text-align: center; }

.pricing-note {
  margin-top: 1.5rem;
  font-size: 0.9rem;
  color: var(--muted);
  max-width: var(--prose);
}

/* Trust strip ------------------------------------------------------------ */

.trust-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.9rem 2rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 720px) { .trust-list { grid-template-columns: minmax(0, 1fr); } }
.trust-list li { display: flex; gap: 0.7rem; align-items: flex-start; font-size: 0.98rem; }
.trust-list .ring-mark { flex: 0 0 auto; margin-top: 4px; color: #cbbfe4; }

/* Forms ------------------------------------------------------------------ */

/* Forms. Every field has a visible label above it, every optional field says
   so, and the hint that explains a field sits under the label rather than
   inside the box, so it is still there while somebody is typing. */

.form { max-width: 720px; }

/* A form that stands on its own, away from a page of prose. */
.form-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(1.4rem, 1rem + 1.4vw, 2rem);
  max-width: none;
}

.field { margin-bottom: 1.7rem; }
/* The one field that is a decision rather than an answer. It reads as a sentence with a
   box in front of it, never as a styled button, because it has to be obvious that
   ticking it is an act. Unticked in the markup, and there is no CSS that could tick it. */
.field-consent { margin-bottom: 1.4rem; }
/* NOT .consent. That name was already taken, further down this file, by the cookie
   consent MODAL, which is a dark band on a dim overlay. Reusing it here painted this
   label in the modal's colours: near-black on near-black, with the sentence a person is
   being asked to agree to effectively invisible. A class name is a namespace, and this
   file has one namespace.

   WRITTEN AS `.field label.terms-accept`, and it has to be. `.field label` below is a
   class AND an element, so it outranks a lone class however far down the file it sits:
   order does not save you from specificity. A bare `.terms-accept` lost `display` and
   `font-weight` to it and the checkbox dropped onto its own line, bold and adrift.
   The checkbox rule fights `.field input`, which dresses every control in the form with
   a border, a background and 0.75rem of padding. A checkbox is not a text box, so those
   are all named and undone rather than left to chance. */
.field label.terms-accept {
  display: flex;
  gap: 0.6rem;
  align-items: flex-start;
  font-weight: 400;
  font-size: 0.95rem;
  line-height: 1.5;
  margin-bottom: 0;
  cursor: pointer;
}
.field label.terms-accept input[type="checkbox"] {
  flex: 0 0 auto;
  width: 1.05rem;
  height: 1.05rem;
  margin: 0.22rem 0 0;
  padding: 0;
  border-radius: 4px;
  accent-color: var(--accent);
}
.field-consent .hint { display: block; margin-top: 0.5rem; }
.field label {
  display: block;
  font-weight: 600;
  font-size: 0.97rem;
  color: var(--ink);
  margin-bottom: 0.45rem;
}
.field .hint {
  display: block;
  font-weight: 400;
  font-size: 0.87rem;
  color: var(--muted);              /* 8.07:1 on --surface, 8.78:1 on --card */
  margin-top: 0.2rem;
}
.field label .hint { margin: 0.25rem 0 0; }
.field input, .field select, .field textarea {
  width: 100%;
  font: inherit;
  font-size: 1rem;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: 0.75rem 0.85rem;
}
.field textarea { min-height: 150px; resize: vertical; line-height: 1.55; }
.field select { appearance: none; background-image: none; padding-right: 0.85rem; }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--accent); }
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--accent);
  outline: 3px solid var(--accent);
  outline-offset: 1px;
}
.field-row { display: grid; gap: 0 1.35rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 620px) { .field-row { grid-template-columns: minmax(0, 1fr); } }

/* Required is marked in words as well as in colour, because a red asterisk on
   its own is not a message. */
.req {
  color: var(--hold);
  font-weight: 700;
  margin-left: 0.1rem;
}
.opt {
  font-weight: 500;
  font-size: 0.84rem;
  color: var(--muted);
  margin-left: 0.35rem;
}
.form-legend {
  font-size: 0.87rem;
  color: var(--muted);
  margin: 0 0 1.5rem;
}
.form-legend .req { margin-right: 0.15rem; }

.btn-lg { padding: 1rem 1.7rem; font-size: 1.03rem; }

/* What happens next, in the colour this site uses for a decision going well. */
.form-status {
  margin-top: 1.4rem;
  border: 1px solid var(--ok-line);
  background: var(--ok-soft);
  border-radius: var(--radius-sm);
  padding: 1.1rem 1.2rem;
  font-size: 0.94rem;
}
.form-status h3 {
  font-family: var(--sans);
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--ok);                 /* 5.77:1 on --ok-soft */
  margin-bottom: 0.5rem;
}
.form-status[hidden] { display: none; }

/* The copy out fallback on the application form, for anyone whose machine has
   no mail client wired up. Nothing is hidden from them. */
.compose { margin-top: 1rem; }
.compose summary { cursor: pointer; font-weight: 600; font-size: 0.92rem; }
.compose summary:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.compose textarea {
  display: block;
  width: 100%;
  min-height: 200px;
  margin-top: 0.75rem;
  font-family: var(--mono);
  font-size: 0.85rem;
  line-height: 1.55;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: 0.7rem 0.8rem;
  resize: vertical;
}

.callout {
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  background: var(--card);
  border-radius: var(--radius-sm);
  padding: 1.1rem 1.25rem;
  margin: 1.75rem 0;
}
.callout p { font-size: 0.96rem; }

/* Legal and long-form pages ---------------------------------------------- */

.page-head { padding: clamp(2.5rem, 1.5rem + 4vw, 4rem) 0 1.5rem; }
.page-head .lede { margin-top: 1rem; }
.page-head h1 { max-width: 900px; }
.draft-line {
  font-family: var(--sans);
  font-size: 0.82rem;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.25rem 0.8rem;
  display: inline-block;
  margin-bottom: 1.25rem;
}

.doc { max-width: var(--prose); padding-bottom: 4rem; }
.doc h2 {
  font-size: 1.45rem;
  margin: 2.75rem 0 0.9rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}
.doc h2:first-of-type { margin-top: 1.5rem; }
.doc h3 { font-size: 1.08rem; margin: 1.75rem 0 0.6rem; }
.doc p, .doc li { font-size: 1rem; }
.doc ul, .doc ol { margin: 0 0 1rem; padding-left: 1.3rem; }
.doc li { margin-bottom: 0.45rem; }
.doc .toc { list-style: none; padding: 0; margin: 0; columns: 2; column-gap: 2rem; }
@media (max-width: 620px) { .doc .toc { columns: 1; } }
.doc .toc li { margin-bottom: 0.35rem; font-size: 0.94rem; }
.doc table {
  width: 100%;
  min-width: 480px;
  border-collapse: collapse;
  font-size: 0.93rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  margin-bottom: 1.25rem;
}
.doc table th, .doc table td { text-align: left; padding: 0.7rem 0.9rem; border-bottom: 1px solid var(--line); }
.doc table thead th {
  font-family: var(--sans);
  font-size: 0.72rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--surface);
}
.doc table tbody tr:last-child td { border-bottom: 0; }

/* Footer ----------------------------------------------------------------- */

.site-footer { background: var(--deep); color: var(--surface); padding: 3.5rem 0 2.5rem; }
.footer-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) repeat(3, minmax(0, 1fr));
  gap: 2rem;
  padding-bottom: 2.25rem;
  border-bottom: 1px solid var(--deep-line);
}
@media (max-width: 860px) { .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .footer-grid { grid-template-columns: minmax(0, 1fr); } }

.footer-grid .brand { color: var(--surface); margin-right: 0; }
.footer-grid .brand .mark { color: #b9a8d8; }
.footer-grid .brand .brand-sub { color: var(--deep-muted); border-left-color: var(--deep-line); }
.footer-about { margin-top: 0.9rem; font-size: 0.92rem; color: var(--deep-muted); max-width: 34ch; }

.footer-grid h2 {
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--deep-muted);
  margin-bottom: 0.85rem;
}
.footer-links { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.55rem; }
.footer-links a { color: var(--surface); text-decoration: none; font-size: 0.94rem; }
.footer-links a:hover { color: #cbbfe4; text-decoration: underline; }

.footer-base {
  padding-top: 1.75rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
  align-items: baseline;
  font-size: 0.86rem;
  color: var(--deep-muted);
}
.footer-base a { color: var(--deep-muted); }
.footer-base a:hover { color: #fff; }
.footer-base .spacer { margin-left: auto; }

/* ==========================================================================
   Motion

   Every animation on this site is declared inside this one block, and the
   block only exists when the visitor has not asked for reduced motion. That
   is deliberate: switch reduced motion on and these rules are not overridden,
   they are never parsed, so the page has no running animations at all rather
   than animations racing to finish in a millisecond. The still frame under
   every animation is the real design, and the motion is added on top.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {

  /* The page arriving. One short sequence, top left to bottom right. ------ */
  .reveal { animation: rise 0.6s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
  .reveal-1 { animation-delay: 0.05s; }
  .reveal-2 { animation-delay: 0.16s; }
  .reveal-3 { animation-delay: 0.27s; }
  .reveal-4 { animation-delay: 0.38s; }

  @keyframes rise {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: none; }
  }

  /* Sequential reveal on scroll. The hidden state is scoped to .js so that a
     visitor with scripting off is never left with an empty section: site.js
     sets that class on the html element before the body renders. */
  .js .seq > * {
    opacity: 0;
    transform: translateY(14px);
    transition:
      opacity 0.5s ease,
      transform 0.5s cubic-bezier(0.2, 0.7, 0.3, 1);
    transition-delay: calc(var(--i, 0) * 70ms);
  }
  .js .seq > .is-in { opacity: 1; transform: none; }

  /* The manifesto reveals differently: the lines are not faded in, they rise
     out from behind their own edge, one after the other. It is the only place
     on the site that does this, which is the point. */
  .js .seq > .mline { opacity: 1; transform: none; overflow: hidden; }
  .js .seq > .mline > span {
    transform: translateY(105%);
    transition: transform 0.75s cubic-bezier(0.16, 0.84, 0.31, 1);
    transition-delay: calc(var(--i, 0) * 130ms);
  }
  .js .seq > .mline.is-in > span { transform: none; }

  /* The hero slider ------------------------------------------------------
     The whole slide crossfades as one piece. The one leaving goes first and
     the one arriving follows it in, because two stacked paragraphs at half
     opacity are unreadable: 0.45s out, then 0.55s in, so a change takes the
     one second the eye expects and never shows two headlines at once. The
     visibility switch is delayed to the end of the fade out so the slide that
     is leaving stays on screen while it leaves.

     None of this is declared under reduced motion, so there the slides swap
     the instant a dot is pressed and nothing advances on its own. The pause on
     hover and on focus lives in site.js, because the clock is a timer there
     rather than an animation here. */
  .js .hero-slide { transition: opacity 0.45s ease, visibility 0s linear 0.45s; }
  .js .hero-slide.is-on { transition: opacity 0.55s ease 0.45s, visibility 0s; }

  /* A drawing that is not on screen is not running. The harbour is the reason
     this rule exists: it is an eleven second loop and it has no business
     ticking away behind seven other slides. */
  .js .hero-slide:not(.is-on) * { animation-play-state: paused; }

  /* Work moving through the other six drawings, on the same seven seconds a
     slide is held for, so one journey is completed per slide. The dots reuse
     the harbour's keyframes: each one carries its own destination in --dx and
     --dy, measured along the lane drawn under it. */
  .hero-svg .hflow, .hero-svg .feed { animation: crewDot 7s linear infinite; }
  /* d1 and f1 leave first and so carry no delay of their own. The eight feed
     dots on the keys drawing are staggered evenly across the seven seconds, in
     equal steps, so no chip's dot arrives sooner or more often than another's:
     the timing is as equal as the chips are. */
  .hero-svg .d2 { animation-delay: 2.3s; }
  .hero-svg .d3 { animation-delay: 4.6s; }
  .hprov .f2 { animation-delay: -0.875s; }
  .hprov .f3 { animation-delay: -1.75s; }
  .hprov .f4 { animation-delay: -2.625s; }
  .hprov .f5 { animation-delay: -3.5s; }
  .hprov .f6 { animation-delay: -4.375s; }
  .hprov .f7 { animation-delay: -5.25s; }
  .hprov .f8 { animation-delay: -6.125s; }

  /* Slide three, where the two halves have to move differently or the drawing
     says nothing.

     On the left, one token rides the ring for fourteen seconds, the slowest
     loop on the site, passing behind each bubble and coming out the other
     side, and three more fall out of the bottom of the picture and fade. The
     first version of this dimmed the four bubbles in sequence instead, and it
     was measured out: --band-edge is 3.06:1 on the band, which is a shape
     colour sitting exactly on its floor, so any amount of fading takes the
     outlines under 3:1 for part of every cycle. Turning something at full
     contrast says the same thing and stays measured at every frame.

     The falling tokens do fade, because disappearing is what they mean, and
     the two words underneath them never move: the label carries the meaning
     at 9.58:1 whatever the dots are doing.

     On the right the same seven seconds are spent going somewhere. The three
     lane dots are the ones every other hero drawing uses, on the same delays,
     and the tick lands once near the end of the cycle. Nothing on that side
     starts a journey it has already made. */
  .honce .turn {
    transform-origin: 108px 174px;   /* the centre the ring is drawn around */
    animation: loopTurn 14s linear infinite;
  }

  @keyframes loopTurn {
    to { transform: rotate(360deg); }
  }

  .honce .drip { animation: dripAway 7s ease-in infinite; }
  .honce .k2 { animation-delay: -2.4s; }
  .honce .k3 { animation-delay: -4.6s; }

  @keyframes dripAway {
    0% { opacity: 1; transform: translateY(0); }
    70%, 100% { opacity: 0; transform: translateY(22px); }
  }

  .honce .tick {
    transform-box: fill-box;
    transform-origin: center;
    animation: onceTick 7s ease-out infinite;
  }

  @keyframes onceTick {
    0%, 58% { opacity: 0; transform: scale(0.4); }
    68%, 92% { opacity: 1; transform: scale(1); }
    100% { opacity: 0; transform: scale(0.9); }
  }

  /* The architecture drawing has exactly one moving part, and the restraint is
     the point: nothing crosses a wall, so nothing travels between containers.
     What does happen over time is another company arriving beside you, so the
     empty outline and its plus fade up once per slide, on the same seven
     seconds everything else in the hero runs on.

     Only the outline moves. The two words under it are outside this group and
     never fade, so the meaning is legible at every frame of the loop and at
     full contrast in the still frame a reduced motion visitor sees. */
  .hiso .next-shape { animation: nextUp 7s ease-in-out infinite; }

  @keyframes nextUp {
    0%, 6% { opacity: 0.35; }
    30%, 88% { opacity: 1; }
    100% { opacity: 0.35; }
  }

  /* The code map breathes rather than animates: seven of the hundred and five
     nodes drift two pixels and come back over a quarter of a minute, roughly
     one per community. At any moment almost nothing is moving, which is the
     intent. The counting is per group, so the step is larger than the biggest
     community to keep it to one node each. */
  .cgraph circle:nth-of-type(29n + 13) { animation: nodeDrift 15s ease-in-out infinite; }
  .cgraph circle:nth-of-type(43n + 24) { animation: nodeDrift 19s ease-in-out infinite -6s; }

  @keyframes nodeDrift {
    0%, 100% { transform: none; }
    50% { transform: translate(2px, -2px); }
  }

  /* The stepper, alive. --------------------------------------------------
     The rail under the dots fills over four seconds and the END OF THAT
     ANIMATION is what advances the spotlight, so the picture and the clock are
     one object. Two things follow for free: hovering or tabbing into the
     stepper pauses the fill and therefore pauses the advance, and under
     reduced motion the animation is never declared, so nothing ever advances
     and the controls below are never shown. Six steps, still all on the page. */
  .js .stepper-bar { display: flex; }
  .stepper li { transition: box-shadow 0.35s ease; }
  .steprail-fill { animation: stepRail 4s linear; }
  .stepper-wrap:hover .steprail-fill,
  .stepper-wrap:focus-within .steprail-fill { animation-play-state: paused; }

  @keyframes stepRail {
    from { transform: scaleX(0); }
    to { transform: scaleX(1); }
  }

  /* Cards answer the pointer. Two pixels, not a jump. -------------------- */
  .card, .tier {
    transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
  }
  .card:hover, .tier:hover {
    transform: translateY(-3px);
    box-shadow: 0 6px 18px rgba(33, 30, 26, 0.07);
  }
  .on-deep .card:hover { box-shadow: 0 6px 18px rgba(0, 0, 0, 0.22); }

  /* ---------------------------------------------------------------------
     The harbour, alive.

     One eleven second cycle. The crew send work to the collecting point on a
     half length cycle, so two rounds of work arrive for every gate opening.
     The trunk dot carries the reviewed mission to the gate, the gate parts,
     the tick appears, and the work leaves through the mouth. Nothing bounces
     and nothing is faster than a breath.
     --------------------------------------------------------------------- */

  .cothon .halo {
    transform-box: fill-box;
    transform-origin: center;
    animation: haloPulse 5.5s ease-out infinite;
  }
  .cothon .crew-plan .halo { animation-delay: 0s; }
  .cothon .crew-build .halo { animation-delay: 1.1s; }
  .cothon .crew-review .halo { animation-delay: 2.2s; }
  .cothon .crew-report .halo { animation-delay: 3.3s; }

  @keyframes haloPulse {
    0% { opacity: 0.55; transform: scale(1); }
    70% { opacity: 0; transform: scale(1.32); }
    100% { opacity: 0; transform: scale(1.32); }
  }

  /* Each dot carries its own destination in --dx and --dy, measured along the
     lane drawn under it, so one set of keyframes moves all four. */
  .cothon .dot { animation: crewDot 5.5s linear infinite; }
  .cothon .crew-plan .dot { animation-delay: -0.5s; }
  .cothon .crew-build .dot { animation-delay: -1.4s; }
  .cothon .crew-review .dot { animation-delay: -2.3s; }
  .cothon .crew-report .dot { animation-delay: -3.2s; }

  @keyframes crewDot {
    0% { opacity: 0; transform: translate(0, 0); }
    6% { opacity: 1; }
    62% { opacity: 1; transform: translate(calc(var(--dx) * 1px), calc(var(--dy) * 1px)); }
    70%, 100% { opacity: 0; transform: translate(calc(var(--dx) * 1px), calc(var(--dy) * 1px)); }
  }

  .cothon .dot-trunk { animation: trunkDot 11s linear infinite; }

  @keyframes trunkDot {
    0%, 24% { opacity: 0; transform: translateX(0); }
    28% { opacity: 1; transform: translateX(5px); }
    44%, 54% { opacity: 1; transform: translateX(47px); }
    72% { opacity: 1; transform: translateX(193px); }
    78%, 100% { opacity: 0; transform: translateX(193px); }
  }

  .cothon .gate-top { animation: gateTop 11s ease-in-out infinite; }
  .cothon .gate-bottom { animation: gateBottom 11s ease-in-out infinite; }

  @keyframes gateTop {
    0%, 44% { transform: translateY(0); }
    52%, 70% { transform: translateY(-16px); }
    82%, 100% { transform: translateY(0); }
  }
  @keyframes gateBottom {
    0%, 44% { transform: translateY(0); }
    52%, 70% { transform: translateY(16px); }
    82%, 100% { transform: translateY(0); }
  }

  .cothon .tick {
    transform-box: fill-box;
    transform-origin: center;
    animation: tickIn 11s ease-out infinite;
  }

  @keyframes tickIn {
    0%, 48% { opacity: 0; transform: scale(0.4); }
    57%, 72% { opacity: 1; transform: scale(1); }
    80%, 100% { opacity: 0; transform: scale(0.9); }
  }

  /* The provider graph. Work arrives from every provider account and leaves
     through the crew on its way to the product. Eight dots on one seven second
     loop, staggered in equal steps like the keys slide, so no chip's dot
     arrives sooner or more often than another's: the timing is as equal as the
     chips are. */
  .orch .feed { animation: feedDot 7s linear infinite; }
  .orch .feed.f2 { animation-delay: -0.875s; }
  .orch .feed.f3 { animation-delay: -1.75s; }
  .orch .feed.f4 { animation-delay: -2.625s; }
  .orch .feed.f5 { animation-delay: -3.5s; }
  .orch .feed.f6 { animation-delay: -4.375s; }
  .orch .feed.f7 { animation-delay: -5.25s; }
  .orch .feed.f8 { animation-delay: -6.125s; }

  @keyframes feedDot {
    0% { opacity: 0; transform: translate(0, 0); }
    8% { opacity: 1; }
    64% { opacity: 1; transform: translate(calc(var(--dx) * 1px), calc(var(--dy) * 1px)); }
    72%, 100% { opacity: 0; transform: translate(calc(var(--dx) * 1px), calc(var(--dy) * 1px)); }
  }

  /* One dot per row, three stops: out of Carth, into the agent, on to the
     product. It goes invisible while it crosses the chip so it reads as
     passing through the agent rather than over the top of its name. */
  .orch .relay { animation: relayDot 9s ease-in-out infinite; }
  .orch .relay.d2 { animation-delay: -2.25s; }
  .orch .relay.d3 { animation-delay: -4.5s; }
  .orch .relay.d4 { animation-delay: -6.75s; }

  @keyframes relayDot {
    0% { opacity: 0; transform: translate(0, 0); }
    6% { opacity: 1; transform: translate(0, 0); }
    34% { opacity: 1; transform: translate(calc(var(--x1) * 1px), calc(var(--y1) * 1px)); }
    39% { opacity: 0; transform: translate(calc(var(--x1) * 1px), calc(var(--y1) * 1px)); }
    50% { opacity: 0; transform: translate(calc(var(--x2) * 1px), calc(var(--y2) * 1px)); }
    55% { opacity: 1; transform: translate(calc(var(--x2) * 1px), calc(var(--y2) * 1px)); }
    84% { opacity: 1; transform: translate(calc(var(--x3) * 1px), calc(var(--y3) * 1px)); }
    90%, 100% { opacity: 0; transform: translate(calc(var(--x3) * 1px), calc(var(--y3) * 1px)); }
  }

  /* The review gate drawing: evidence lands, then the decision lights up. */
  .mock-live .evidence figure { animation: thumbPop 9s ease-in-out infinite; }
  .mock-live .evidence figure:nth-child(2) { animation-delay: 0.3s; }
  .mock-live .evidence figure:nth-child(3) { animation-delay: 0.6s; }
  .mock-live .evidence figure:nth-child(4) { animation-delay: 0.9s; }

  @keyframes thumbPop {
    0% { opacity: 0.4; transform: scale(0.965); }
    8%, 76% { opacity: 1; transform: scale(1); }
    88%, 100% { opacity: 0.4; transform: scale(0.965); }
  }

  .mock-live .gatebox .fake-btn:not(.fake-btn-quiet) {
    animation: gateRing 9s ease-in-out infinite;
  }

  @keyframes gateRing {
    0%, 52% { box-shadow: 0 0 0 0 rgba(31, 107, 70, 0); }
    62%, 78% { box-shadow: 0 0 0 4px rgba(31, 107, 70, 0.32); }
    90%, 100% { box-shadow: 0 0 0 0 rgba(31, 107, 70, 0); }
  }
}

/* ---- Where it runs: the three harbours, and the zone list ------------------
   The marks are the cothon at three scales. They are decorative in the sense
   that the heading says the same thing, so each carries its own aria-label and
   nothing depends on telling the hues apart. */
.harbours { margin-top: 2rem; }
.harbour { display: flex; flex-direction: column; }
.harbour-mark { width: 96px; height: 64px; margin-bottom: 0.9rem; }
.harbour h3 { margin: 0 0 0.3rem; }
.harbour-line { font-size: 0.9rem; color: var(--muted); margin: 0 0 0.8rem; }
.harbour p { margin: 0 0 0.8rem; }
/* Licence cards ---------------------------------------------------------- */
/* THE SECTION SAID THE STRONGEST THING ON THE PAGE AND DREW NOTHING. "Checked on your
   machine, never ours" is the differentiator the whole licensing model rests on, and it
   was three white cards of prose with no mark of any kind, directly under a section that
   draws its harbours and next to one that draws its capabilities. The claim reads as
   boilerplate when it is set as boilerplate.
   These follow the harbour marks exactly rather than inventing a second idiom: same 96x64
   plate, same stroke weights, same ring-and-dot vocabulary as the brand mark, and the hue
   comes from --sec so the three glyphs belong to the green licensing section rather than
   to the page at large. Each one draws the sentence its card makes: the check happening
   inside your own machine, the call that only ever goes outward, and the half of the key
   we do not hold. */
.licences { margin-top: 2rem; }
.licence-card { display: flex; flex-direction: column; }
.licence-mark { width: 112px; height: 74px; margin-bottom: 1rem; }
.licence-card h3 { margin: 0 0 0.55rem; }

.harbour-meta {
  margin-top: auto; padding-top: 0.9rem; border-top: 1px solid var(--line);
  font-size: 0.78rem; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted);
}

.zones { margin-top: 2.6rem; padding-top: 2rem; border-top: 1px solid var(--line); }
.zones-title { font-family: var(--serif); font-size: 1.3rem; font-weight: 600; margin: 0 0 0.4rem; }
.zones-lede { color: var(--muted); max-width: var(--prose); margin: 0 0 1.4rem; }
.zone-list {
  list-style: none; margin: 0 0 1.2rem; padding: 0;
  display: grid; gap: 0.75rem; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
.zone-list li {
  display: flex; align-items: center; gap: 0.85rem;
  padding: 0.85rem 1rem; border: 1px solid var(--line); border-radius: 8px;
  background: var(--card);
}
/* The flags are drawn inline, not emoji, so they render the same on every
   platform; a hairline keeps the white stripes from melting into the card. */
.zone-list .flag { width: 30px; height: 21px; flex-shrink: 0; border-radius: 4px; overflow: hidden; box-shadow: inset 0 0 0 1px rgba(33, 30, 26, 0.14); }
.zone-list .zl { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; }
.zone-list b { font-size: 0.98rem; }
.zone-list span { font-size: 0.85rem; color: var(--muted); }

/* ---- Pricing: the concurrency limit, and the add-on table ---------------- */
/* The two explain-the-limit panels: how many agents run at once, and what the licence
   token does and does not carry.

   THEY WERE THE PALEST THING ON THE PAGE. Both are four dense paragraphs of prose in a
   white card with a hairline round it, no mark of any kind, sitting under sections that
   have eyebrows, numbers and diagrams. They read as the small print, which is exactly
   backwards: these two answer the question a buyer actually stalls on, which is why they
   were written long in the first place. Nothing here changes a word of the copy - what
   changes is that the block announces itself and that the eye can find its way down it.

   Three moves, and no gradients: a tinted header strip with an icon chip so the panel has
   a face; a hanging accent marker on the paragraphs that already open with a bold lead, so
   the four points scan as four points; and the body left on --card so --muted keeps 8.78:1
   rather than the 6.19:1 it would fall to on --tint. */
.limits {
  margin-top: 2.4rem;
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: 10px; background: var(--card);
  overflow: hidden;                    /* the header tint follows the rounded corners */
}
.limits-title {
  display: flex; align-items: center; gap: 0.75rem;
  font-family: var(--serif); font-size: 1.25rem; font-weight: 600;
  margin: 0; padding: 1.1rem 1.8rem;
  background: var(--tint);             /* --ink on it is 14.56:1 */
  border-bottom: 1px solid var(--accent-line);
}
/* The icon chip. A solid tile, never a gradient, and the glyph carries the accent at its
   strong value so it holds up against the tint behind it. */
.limits-ico {
  flex: 0 0 auto; width: 34px; height: 34px; padding: 7px;
  border-radius: 8px; background: var(--card); border: 1px solid var(--accent-line);
  color: var(--accent-strong);         /* 6.88:1 on --tint, and it is a glyph, not text */
}
.limits-body { padding: 1.5rem 1.8rem; display: grid; grid-template-columns: minmax(0, var(--prose)) minmax(240px, 1fr); gap: 2rem; align-items: start; }
/* The prose keeps its reading width; the rest of the card, which used to sit empty,
   carries the same facts as a scannable list so a reader who will not read four
   paragraphs still leaves with the numbers. Single column once the card is narrow. */
.limits-text { min-width: 0; }
.limits-aside { background: var(--tint); border: 1px solid var(--accent-line); border-radius: 10px; padding: 1rem 1.1rem; display: flex; flex-direction: column; gap: 0.6rem; }
.limits-aside-title { font-size: 10.5px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent-strong); margin-bottom: 0.2rem; } /* 6.88:1 on --tint, label only */
.limits-aside .v3kv { border-color: var(--accent-line); }
.limits-aside .v3kv .no { font-size: 11px; font-weight: 700; letter-spacing: 0.06em; color: var(--hold); }
@media (max-width: 900px) { .limits-body { grid-template-columns: 1fr; } }
.limits-body p { margin: 0 0 0.9rem; }
.limits-body p:last-child { margin-bottom: 0; }
/* A PARAGRAPH THAT OPENS WITH ITS POINT gets a marker, so the panel can be skimmed by its
   points before it is read by its sentences. Selected on the shape the copy already has
   rather than on a class, so the French tree gets it without being touched and a new
   paragraph written the same way is picked up for free. */
.limits-body p:has(> b:first-child) {
  position: relative; padding-left: 1.15rem;
}
.limits-body p:has(> b:first-child)::before {
  content: ""; position: absolute; left: 0; top: 0.55em;
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent);
}
.limits-body p > b:first-child { color: var(--accent-strong); }  /* 7.85:1 on --card */
.limits-foot { font-size: 0.9rem; color: var(--muted); }         /* 8.78:1 on --card */
/* The foot is the aside at the end, so it is fenced off from the points above it. */
.limits-body .limits-foot { padding-top: 0.9rem; border-top: 1px solid var(--line); }
.limits-text p:last-child { margin-bottom: 0; }

@media (max-width: 620px) {
  .limits-title { padding: 0.95rem 1.15rem; font-size: 1.12rem; gap: 0.6rem; }
  .limits-body { padding: 1.15rem; }
}

.addons-title { font-family: var(--serif); font-size: 1.3rem; font-weight: 600; margin: 0 0 0.6rem; }

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

/* ---- Section identity ------------------------------------------------------
   The page was a long run of identically framed sections separated by hairlines,
   so nothing told the eye where it had got to, and three new sections made that
   worse rather than better.

   Each section now carries ONE hue from the measured palette, spent in exactly
   three places: a short rule above the eyebrow, the eyebrow itself, and the edge
   a card takes on hover. One hue, three touches, no gradients. Grounds alternate
   underneath so neighbouring sections differ in tone as well as colour.

   Every value below is already measured in this file against --surface, --card
   and --tint, and the eyebrow is the only text that takes the hue. */
.sec-plum  { --sec: var(--accent); }   /* 5.42 on surface, 5.18 on tint */
.sec-teal  { --sec: var(--teal);   }   /* 6.36 on surface, 6.07 on tint */
.sec-navy  { --sec: var(--info);   }   /* 9.26 on surface, 8.84 on tint */
.sec-clay  { --sec: var(--warm);   }   /* 5.42 on surface */
.sec-green { --sec: var(--ok);     }   /* 5.93 on surface, 5.67 on tint */

/* The rule is short and sits directly above the eyebrow, so it reads as the
   start of a section rather than as a divider between two. */
.section[class*="sec-"] .section-head .eyebrow { color: var(--sec); }
.section[class*="sec-"] .section-head .eyebrow::before {
  content: "";
  display: block;
  width: 2.25rem;
  height: 3px;
  margin-bottom: 0.85rem;
  background: var(--sec);
  border-radius: 2px;
}
/* Cards pick the section's hue up on hover instead of the generic accent line,
   so the colour is a property of where you are, not of the component. */
.section[class*="sec-"] .card:hover { border-color: var(--sec); }
.section[class*="sec-"] .card:focus-within { border-color: var(--sec); }

/* ---- Capabilities ----------------------------------------------------------
   Six cards that are a SET, not a sequence, so they get no numbers: numbering
   would assert an order the content does not have. What they get instead is a
   quiet rule down the leading edge, which groups them without ranking them.
   The last card is the gate, which is the argument the other five depend on, so
   it is the one allowed to look different. */
.caps .card {
  /* The edge carries the section's hue at rest rather than a near-invisible grey.
     A 3px bar at 1.38:1 is decoration nobody can see, which is not restraint, it
     is waste. In the section's own colour it does the grouping job it was added
     for, and at 6.36:1 it is unambiguously there. */
  border-left: 3px solid var(--sec);
  transition: border-color 0.18s ease;
}
.caps .card h3 { font-family: var(--serif); font-weight: 600; font-size: 1.16rem; }
.caps .card-gate {
  border-left-color: var(--sec);
  background: var(--tint);
}
.caps .card-gate h3 { color: var(--sec); }

/* ---- Diagram labels always win against the lines behind them ---------------
   The hero diagrams route dashed lanes and animated dots between the agents,
   and the role labels sit on those same coordinates. So a lane ran through the
   middle of BUILDER, and a travelling dot parked on the R of REVIEWER.

   Rather than move the labels (which would only relocate the collision, and
   would break again the moment a lane is re-routed), each label paints a halo
   of the ground colour UNDERNEATH its own glyphs. paint-order draws the stroke
   first and the fill on top, so the text knocks a clean gap out of whatever is
   behind it, wherever it happens to be.

   The stroke is the band, never a hue, so this changes nothing about contrast:
   the glyph keeps its measured colour against the same ground it already had. */
.cothon .clabel, .hero-svg .clabel,
.cothon .elabel, .hero-svg .elabel,
.cothon .label,  .hero-svg .label {
  paint-order: stroke fill;
  stroke: var(--band);
  stroke-width: 2.6px;
  stroke-linejoin: round;
  stroke-linecap: round;
}
/* The dark-on-light variant used inside filled shapes carries its own ground. */
.cothon .label-ink, .hero-svg .label-ink { stroke: var(--band); }


/* ---- What a plan gets you, at a glance ------------------------------------
   Every line in a tier now carries a mark for the KIND of thing it is: people,
   parallelism, hardware, disk, support. Colour is never the carrier, since the
   marks sit beside the same words they always did, so nothing is lost to anyone
   who cannot separate them. */
.tier ul li { align-items: flex-start; gap: 0.65rem; }
.tier ul li .tico {
  flex: 0 0 auto;
  width: 17px;
  height: 17px;
  margin-top: 0.12em;
  color: var(--accent);
  stroke: currentColor;
  fill: none;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* The line each plan is really sold on stays bold and takes the strong accent. */
.tier ul li b .tico, .tier ul li:has(b) .tico { color: var(--accent-strong, var(--accent)); }
.tier ul li:has(.tico)::before { display: none; }

/* ---- Consent dialog -------------------------------------------------------
   A centred dialog over a dimmed page, not a strip along the bottom. A bottom
   bar reads as a nag and gets swatted away unread, which defeats the point: the
   whole value of a consent prompt is that the answer was given deliberately.

   Refuse and Accept are the same size, weight and prominence, and Refuse comes
   first in the DOM. A dialog where refusing is a faint link is a dark pattern
   with a legal opinion attached. */
.consent-overlay {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  place-items: center;
  padding: 1.25rem;
  background: rgb(12 10 9 / 0.66);
  animation: consentIn 0.16s ease-out;
}
.consent {
  width: 100%;
  max-width: 32rem;
  padding: 1.6rem 1.7rem;
  background: var(--band);
  color: var(--band-text);            /* 12.48:1 on --band */
  border: 1px solid var(--band-edge); /*  3.06:1, a real edge */
  border-radius: 14px;
  box-shadow: 0 18px 50px rgb(0 0 0 / 0.45);
  display: grid;
  gap: 0.9rem;
}
.consent-title {
  margin: 0;
  font-family: var(--serif);
  font-size: 1.3rem;
  font-weight: 600;
  color: #fff;                        /* 17.85:1 on --band */
  letter-spacing: -0.01em;
}
.consent-text { margin: 0; font-size: 0.95rem; line-height: 1.55; }
.consent-text a { color: var(--band-lav); }   /* 10.29:1 on --band */
.consent-actions { display: flex; gap: 0.65rem; margin-top: 0.25rem; }
.consent-btn { flex: 1 1 0; text-align: center; }
/* The page behind must not scroll while a modal is open, or a phone drags the
   dialog around under the thumb. */
html.consent-open, html.consent-open body { overflow: hidden; }

@keyframes consentIn { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .consent-overlay { animation: none; } }
@media (max-width: 26rem) {
  .consent { padding: 1.3rem 1.25rem; }
  .consent-actions { flex-direction: column-reverse; }  /* Accept stays visually last */
}

/* ---- Social ---------------------------------------------------------------
   Static, in the footer, where people look for it. A floating bar was the other
   option and it is the wrong one here: it follows you down a page whose entire
   argument is restraint, and it competes with the one thing the page actually
   wants pressed, which is Join the waiting list.

   Icons rather than words because three brand glyphs are recognised faster than
   three nouns, and each carries an aria-label so nothing depends on knowing the
   shapes. */
.social {
  list-style: none;
  display: flex;
  gap: 0.5rem;
  margin: 0 0 1.4rem;
  padding: 0;
}
.social a {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 10px;
  color: var(--deep-muted);            /* 9.04:1 on --deep, and it is the icon that
                                          identifies the control, so it carries the bar */
  /* No resting border. A 1.44:1 outline is not restraint, it is a line nobody can
     quite see; the frame earns its place on hover, where it is 3.27:1. */
  border: 1px solid transparent;
  transition: color 0.16s ease, border-color 0.16s ease, background 0.16s ease;
}
.social svg { width: 18px; height: 18px; }
.social a:hover,
.social a:focus-visible {
  color: #fff;                       /* 13.79:1 on --deep */
  border-color: #7d7468;             /*  3.27:1, the measured dark-ground edge */
  background: #35302b;
}

/* =============================================================================
   V3 layer (2026-08-19). Aymen designed V3 in Claude Design and it is the law of
   the homepage: the harbour palette kept, the reading experience rebuilt around
   Space Grotesk, numbered section labels, ledger rows and friendly diagrams.
   Prefixed v3- so the retained business sections and every subpage keep their
   existing classes untouched.
   ========================================================================== */
.v3wrap { max-width: 1160px; margin: 0 auto; padding-left: clamp(20px, 3vw, 44px); padding-right: clamp(20px, 3vw, 44px); }
.v3eyebrow { font-size: 11.5px; font-weight: 700; letter-spacing: 0.1em; color: #574a7c; text-transform: uppercase; margin-bottom: 14px; }
.on-band .v3eyebrow, .v3dark .v3eyebrow { color: var(--crew-plan, #cbbfe4); }
.v3h1 { font-family: var(--serif); font-weight: 500; font-size: clamp(36px, 4.4vw, 58px); line-height: 1.06; letter-spacing: -0.025em; margin: 0 0 20px; text-wrap: balance; }
.v3h2 { font-family: var(--serif); font-weight: 500; font-size: clamp(26px, 2.8vw, 36px); line-height: 1.12; letter-spacing: -0.02em; margin: 0 0 12px; }
.v3lede { font-size: 16.5px; line-height: 1.65; color: #4f4a42; margin: 0; }
.on-band .v3lede { color: #ded7cb; }
.v3sec { padding: clamp(52px, 6vw, 88px) 0; }
.v3sec-tight { padding-top: 0; }
.v3card { border: 1px solid #e8e4dd; border-radius: 12px; background: #fff; }
.v3pad { padding: clamp(26px, 3.5vw, 48px); }

/* hero */
.v3hero { background: var(--band, #1a1714); color: #fff; }
.v3hero .v3grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(400px, 100%), 1fr)); gap: clamp(32px, 4vw, 64px); align-items: center; }
.v3hero p.sub { font-size: clamp(16px, 1.3vw, 19px); line-height: 1.6; color: #ded7cb; margin: 0 0 14px; max-width: 480px; text-wrap: pretty; }
.v3hero p.pitch { font-size: 15px; line-height: 1.6; color: #f0c9a8; margin: 0 0 34px; max-width: 460px; }
.v3stats { display: flex; gap: clamp(16px, 1.6vw, 24px); margin-top: 42px; padding-top: 22px; border-top: 1px solid #2a2521; flex-wrap: wrap; }
.v3stat .n { font-family: var(--serif); font-size: 25px; font-weight: 500; color: #fff; }
.v3stat .l { font-size: 9.5px; font-weight: 700; letter-spacing: 0.1em; color: #c4bdb2; margin-top: 5px; white-space: nowrap; }
.v3dark .v3stat .n { font-size: 30px; color: #8fd3ae; }
.v3dark .v3stat .l { color: #cfc8bd; }
.v3figcap { font-size: 13px; line-height: 1.6; color: #c4bdb2; margin-top: 12px; max-width: 520px; }

/* buttons in the V3 voice (scoped, so subpage buttons keep their look) */
.v3btn { display: inline-flex; align-items: center; background: #6b5b95; color: #fff; font-size: 15px; font-weight: 600; padding: 13px 24px; border-radius: 8px; white-space: nowrap; text-decoration: none; }
.v3btn:hover { background: #574a7c; color: #fff; }
.v3btn-ghost { display: inline-flex; align-items: center; border: 1px solid #6b645b; color: #fff; font-size: 15px; padding: 13px 22px; border-radius: 8px; white-space: nowrap; text-decoration: none; }
.v3btn-ghost:hover { border-color: #c4bdb2; color: #fff; }

/* feature triples inside a card */
.v3feat { border-top: 1px solid #e8e4dd; padding-top: 20px; }
.v3feat .t { font-size: 15.5px; font-weight: 600; margin-bottom: 6px; }
.v3feat .d { font-size: 15px; line-height: 1.6; color: #4f4a42; }
.v3feat svg { width: 40px; height: 40px; display: block; margin-bottom: 12px; }

/* bullet rows */
.v3pt { display: grid; grid-template-columns: 14px 1fr; gap: 12px; }
.v3pt .dot { width: 6px; height: 6px; border-radius: 50%; background: #6b5b95; margin-top: 8px; }
.v3pt .tx { font-size: 15.5px; line-height: 1.6; color: #4f4a42; }
.v3pt .tx b { color: #211e1a; font-weight: 600; }

/* framed diagram cards */
.v3frame { border: 1px solid #e8e4dd; border-radius: 12px; background: #fff; overflow: hidden; }
.v3frame-head { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid #e8e4dd; font-size: 10px; font-weight: 700; letter-spacing: 0.1em; color: #4f4a42; }
.v3frame-head .tag { margin-left: auto; font-size: 10px; letter-spacing: 0.08em; color: #574a7c; white-space: nowrap; }
.v3dark .v3frame { border-color: #453f38; background: #221d19; }
.v3dark .v3frame-head { border-color: #453f38; color: #cfc8bd; }
.v3dark .v3frame-head .live { margin-left: auto; font-size: 9px; letter-spacing: 0.08em; color: #8fd3ae; background: rgba(143,211,174,0.12); padding: 4px 8px; border-radius: 4px; white-space: nowrap; }

/* the dark production band */
.v3dark { background: #2a2622; color: #fff; }
.v3dark .v3lede { color: #cfc8bd; }
.v3dark .v3figcap { color: #cfc8bd; }

/* mission ledger */
.v3ledger { min-width: 0; }
.v3row { display: grid; grid-template-columns: 40px 1fr auto; gap: 16px; align-items: baseline; padding: 20px 0; border-top: 1px solid #e8e4dd; }
.v3row:last-child { border-bottom: 1px solid #e8e4dd; }
.v3row .no { font-family: var(--serif); font-size: 14px; font-weight: 600; color: #b0a99e; }
.v3row .t { font-size: 16.5px; font-weight: 600; margin-bottom: 4px; }
.v3row .d { font-size: 15px; line-height: 1.6; color: #4f4a42; }
.v3row .who { font-size: 9px; font-weight: 700; letter-spacing: 0.1em; color: #7a746a; white-space: nowrap; }
.v3row.gate { background: #ecf4ef; border-radius: 8px; padding-left: 14px; padding-right: 14px; }
.v3row.gate .no, .v3row.gate .who { color: #1f6b46; }

/* Facts about what a mission hands back. NOT the numbered ledger: .v3row is a three
   column grid (number, body, actor) and borrowing it for rows that have only a body
   crushed every sentence into the 40px number column. These are three statements, not a
   sequence, so they carry no numbers and need no grid. */
.v3facts { margin-top: 22px; }
.v3fact { padding: 18px 0; border-top: 1px solid #e8e4dd; }
.v3fact:last-child { border-bottom: 1px solid #e8e4dd; }
.v3fact .t { font-size: 16.5px; font-weight: 600; margin-bottom: 4px; }
.v3fact .d { font-size: 15px; line-height: 1.6; color: #4f4a42; max-width: 68ch; }

/* provider chips, with the real marks */
.v3prov { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.v3chip { border: 1px solid #d9d3e6; background: #fff; border-radius: 7px; padding: 8px 14px; font-size: 14px; font-weight: 500; white-space: nowrap; display: inline-flex; align-items: center; gap: 8px; }
.v3chip img { width: 12px; height: 12px; }
.v3prov .note { flex-basis: 100%; font-size: 12.5px; line-height: 1.5; color: #7a746a; }

/* capability lanes and bars */
.v3lane { display: flex; align-items: center; gap: 10px; }
.v3lane .l { font-size: 9px; font-weight: 700; letter-spacing: 0.08em; color: #7a746a; width: 52px; flex-shrink: 0; }
.v3lane .track { flex: 1; height: 5px; border-radius: 3px; background: #f1eff6; overflow: hidden; }
.v3lane .track > div { height: 100%; background: #6b5b95; }
.v3lane .track.clay { background: #fbf1e9; }
.v3lane .track.clay > div { background: #a24b1e; }
.v3bars { display: flex; align-items: flex-end; gap: 7px; height: 64px; border-bottom: 1px solid #e8e4dd; }
.v3bars > div { flex: 1; border-radius: 3px 3px 0 0; transform-origin: bottom; }
.v3ticker { font-size: 9.5px; font-weight: 700; letter-spacing: 0.08em; color: #7a746a; margin-top: 10px; }
.v3kv { display: flex; justify-content: space-between; gap: 12px; padding-bottom: 9px; border-bottom: 1px solid #e8e4dd; font-size: 14px; color: #211e1a; }
.v3kv:last-child { border-bottom: 0; padding-bottom: 0; }
.v3kv .ok { font-size: 11px; font-weight: 700; letter-spacing: 0.06em; color: #1f6b46; }

/* closing band */
.v3close { border-top: 1px solid #e8e4dd; padding-top: clamp(36px, 5vw, 60px); display: flex; align-items: flex-end; justify-content: space-between; gap: 32px; flex-wrap: wrap; }
.v3close h2 { font-family: var(--serif); font-weight: 500; font-size: clamp(26px, 3.2vw, 42px); line-height: 1.1; letter-spacing: -0.022em; margin: 0; max-width: 600px; }

/* V3 motion: friendly dots on breath-length loops, declared ONLY under the
   reduced-motion opt-in, exactly as the brand contract requires. */
@media (prefers-reduced-motion: no-preference) {
  @keyframes v3haloPulse { 0% { opacity: .55; transform: scale(1); } 70%, 100% { opacity: 0; transform: scale(1.32); } }
  @keyframes v3crewDot { 0% { opacity: 0; transform: translate(0,0); } 6% { opacity: 1; } 62% { opacity: 1; transform: translate(calc(var(--dx) * 1px), calc(var(--dy) * 1px)); } 70%, 100% { opacity: 0; transform: translate(calc(var(--dx) * 1px), calc(var(--dy) * 1px)); } }
  @keyframes v3trunkDot { 0%, 24% { opacity: 0; transform: translateX(0); } 28% { opacity: 1; transform: translateX(5px); } 44%, 54% { opacity: 1; transform: translateX(47px); } 72% { opacity: 1; transform: translateX(193px); } 78%, 100% { opacity: 0; transform: translateX(193px); } }
  @keyframes v3gateTop { 0%, 44% { transform: translateY(0); } 52%, 70% { transform: translateY(-16px); } 82%, 100% { transform: translateY(0); } }
  @keyframes v3gateBottom { 0%, 44% { transform: translateY(0); } 52%, 70% { transform: translateY(16px); } 82%, 100% { transform: translateY(0); } }
  @keyframes v3tickIn { 0%, 48% { opacity: 0; transform: scale(.4); } 57%, 72% { opacity: 1; transform: scale(1); } 80%, 100% { opacity: 0; transform: scale(.9); } }
  @keyframes v3cPulse { 0%, 100% { opacity: .25; } 50% { opacity: 1; } }
  @keyframes v3cFill { from { width: 0%; } to { width: var(--to, 66%); } }
  @keyframes v3cRise { from { transform: scaleY(.12); } to { transform: scaleY(1); } }
}

/* Add-ons live behind a conversation, not a price list: the card says what can
   grow and offers the one action, writing to us. */
.addons-ask { margin-top: 2.4rem; padding: clamp(22px, 3vw, 34px); display: flex; align-items: center; gap: clamp(20px, 3vw, 40px); flex-wrap: wrap; }
.addons-ask > div { flex: 1; min-width: 260px; }
.addons-ask p { margin: 0 0 10px; font-size: 15px; line-height: 1.6; max-width: 62ch; }
.addons-ask p:last-child { margin-bottom: 0; }
.addons-ask .quiet { font-size: 13.5px; color: #4f4a42; }

/* Secure by construction (2026-09-08). Three patterns the v3 layer did not have yet:
   a stat whose number reads as a positive (0 silent merges), a tick medallion that
   replaces the ledger's number when a row is a guarantee rather than a step, and a
   ghost button on the light ground (.v3btn-ghost is drawn for the dark band). */
.v3stat .n.ok { color: #8fd3ae; }
/* Four stats have to sit on one line inside a half-width hero column, in both
   languages; the label was sized for three. */
.v3hero .v3stat .l { font-size: 9px; letter-spacing: 0.08em; }
.v3tick { width: 22px; height: 22px; border-radius: 50%; background: #ecf4ef; display: flex; align-items: center; justify-content: center; }
.v3row .who.ok { color: #1f6b46; }
.v3kv .no { font-size: 11px; font-weight: 700; letter-spacing: 0.06em; color: #b4482f; }
.v3btn-ghost-light { display: inline-flex; align-items: center; border: 1px solid #d8d2c7; color: #211e1a; font-size: 15px; padding: 13px 22px; border-radius: 8px; white-space: nowrap; background: transparent; text-decoration: none; }
.v3btn-ghost-light:hover { background: #fff; border-color: #6b5b95; color: #211e1a; }
