/* ─────────────────────────────────────────────────────────────────────────
   Fyvie AI — home page (v2).

   Light paper, black ink, one accent. The accent is set to the ink here, so
   the whole page reads black and white; every accent mark on the page (the I
   in the wordmark, the hero bit, the rules and ticks, the arrows, the cube
   field's forward cubes) is driven by --accent, so putting a colour back is a
   one-line change. Type is the house pair: Stack Sans Notch for display, DM
   Mono for labels and copy. Scoped to this page only — the rest of the site
   keeps css/styles.css.
   ───────────────────────────────────────────────────────────────────────── */

/* Stack Sans Notch — self-hosted variable font (300–700) */
@font-face{font-family:'Stack Sans Notch';font-style:normal;font-weight:300 700;font-display:swap;src:url(../fonts/stack-sans-notch-latin.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+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Stack Sans Notch';font-style:normal;font-weight:300 700;font-display:swap;src:url(../fonts/stack-sans-notch-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}

:root{
  --paper:#FBFBFA;
  --ink:#0E0E0E;
  --accent:#0E0E0E;             /* black accent: the page goes monochrome */
  --on-accent:#FBFBFA;
  --muted:rgba(14,14,14,.55);
  --faint:rgba(14,14,14,.38);
  --hair:rgba(14,14,14,.08);
  --rule:rgba(14,14,14,.14);
  --display:'Stack Sans Notch',Helvetica,Arial,sans-serif;
  --mono:'DM Mono',ui-monospace,monospace;
  --pad:clamp(20px,3.4vw,48px);
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;background:var(--paper);color:var(--ink);font-family:var(--mono);font-size:14px;overflow-x:hidden;-webkit-font-smoothing:antialiased}
a{color:inherit;text-decoration:none}
::selection{background:var(--ink);color:var(--paper)}
.label{font-size:11px;letter-spacing:.24em;color:var(--muted)}

/* ── Hero, drawn at the 80% scale ────────────────────────────────────────
   The hero reads better zoomed out, so it is set as the browser would render
   it at 80%: every fixed px length here is 0.8x its natural value, clamp
   bounds included, while vw and em terms are left alone — zoom does not
   change what a vw resolves to on screen, only what a px does. Multiply the
   px values by 1.25 to put it back. The sections below the hero are at 100%,
   including --pad, which the hero overrides for itself.
   The 760px breakpoint is deliberately not rescaled: shifting it would hand
   phones between 608 and 760px the desktop hero.
   The header itself lives in css/site-header.css — it is shared with the
   pages on css/styles.css, so it cannot depend on the tokens set here.     */
.wordmark{display:flex;align-items:baseline;font-family:var(--display);font-size:clamp(14.4px,1.7vw,17.6px);font-weight:600;letter-spacing:.34em}
.wordmark span{color:var(--accent)}

.hero-v2{--pad:clamp(16px,3.4vw,38.4px);position:relative;min-height:100svh;display:flex;flex-direction:column;overflow:hidden;background:var(--paper)}
.hero-scrim{position:absolute;inset:0;z-index:0;pointer-events:none;background:radial-gradient(120% 80% at 22% 32%,rgba(251,251,250,.94) 0%,rgba(251,251,250,.72) 38%,rgba(251,251,250,0) 72%)}
.hero-body{position:relative;z-index:1;flex:1;display:flex;flex-direction:column;justify-content:space-between;gap:clamp(35.2px,6vw,57.6px);padding:clamp(48px,8vw,76.8px) var(--pad) calc(clamp(32px,5vw,51.2px) + 52px)}
.hero-kicker{display:flex;align-items:center;gap:11.2px;margin-bottom:clamp(19.2px,3.2vw,32px);font-size:8.8px}
.hero-kicker i{width:20.8px;height:1px;background:var(--accent)}
.hero-v2 h1{margin:0;max-width:16ch;font-family:var(--display);font-size:clamp(38.4px,8.4vw,134.4px);line-height:.9;font-weight:500;letter-spacing:-.03em;text-transform:uppercase;text-wrap:balance}
.hero-v2 h1 .ai{display:inline-flex;align-items:center;gap:.04em}
.bit{display:inline-block;width:.12em;height:.72em;background:var(--accent)}
.hero-row{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:clamp(22.4px,4vw,38.4px)}
.hero-actions{display:flex;align-items:center;gap:16px;flex-wrap:wrap}
.btn{display:inline-flex;align-items:center;gap:11.2px;padding:14.4px 20.8px;background:var(--ink);color:var(--paper);font-size:8.8px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;transition:opacity .2s}
.btn:hover{opacity:.78}
.btn b{font-weight:400;font-size:12px}
.hero-say{flex:1 1 336px;max-width:496px;min-width:min(256px,100%)}
.hero-say .tick{position:relative;height:1px;background:var(--rule);margin-bottom:20.8px}
.hero-say .tick:before{content:"";position:absolute;left:0;top:-1px;width:57.6px;height:2.4px;background:var(--accent)}
.hero-say p{margin:0;font-family:var(--display);font-size:clamp(22.4px,2.8vw,36.8px);line-height:1.04;font-weight:500;letter-spacing:-.032em;text-wrap:pretty}
.hero-say .deck{margin:17.6px 0 0;max-width:52ch;font-family:var(--mono);font-size:9.6px;font-weight:400;line-height:1.65;letter-spacing:.04em;color:var(--muted)}
@media(max-width:760px){
  .hero-v2 h1{font-size:clamp(33.6px,11.5vw,52.8px);line-height:.95;max-width:none}
  .hero-actions{gap:12.8px}
  .btn{padding:12.8px 16px;font-size:8px}
  .hero-say p{font-size:23.2px}
}

/* ── Deployment ──────────────────────────────────────────────────────────
   One fixed screen: the ink panel, the headline and all four devices are
   simply there, with no scroll track and no JavaScript. (It was a 300vh
   section with a sticky stage that ship-scroll.js drove through --flood /
   --title / --d1..--d4; that script is still in static/js if the
   choreography is ever wanted back.)                                       */
/* Six portrait cards on one row. The row is flex, not grid, so hovering a
   card can grow it with flex-grow — animatable everywhere, where an
   interpolated grid-template-columns is not. Card height is derived from the
   column width (--card-h) rather than an aspect-ratio, so it stays put while
   the width changes: 3:4 portrait at rest, ~1.8:1 landscape hovered, at every
   viewport. object-fit re-crops as it widens, so expanding uncovers more of
   the photograph.                                                           */
/* Glass: the panel behind the card is flat ink, so the pane itself is rim and
   sheen — a backdrop blur there would have nothing to frost. The one place it
   earns its keep is .device-copy, which frosts the photograph behind it.    */
@media(hover:hover) and (min-width:1101px){
}
/* Wrapped layouts drop the accordion: growing a card would reflow its row. */
@media(max-width:1100px){
}
@media(max-width:620px){
}
@media(max-width:760px){
}

/* ── Specialism ──────────────────────────────────────────────────────────
   Paper between two dark neighbours — the deployment screen above it and the
   licence graphic's weight below — with the three names given back in ink so
   the row of cards is the thing the eye lands on. The cards are the research
   page's, held open: index at the top, name on the floor, copy under it, and
   no hover to find, because the whole of each one is worth reading.

   The density row is the argument the names imply, so it is set apart by a
   full-strength rule rather than by another box: label left, the claim right
   in display type, and three measures under it on hairlines. The measures
   are per-unit deliberately — density is a ratio, and the three denominators
   are what an embedded product is short of.                                */
.spec{padding:clamp(84px,11vw,150px) var(--pad);background:var(--paper);border-bottom:1px solid var(--hair)}
.spec-head{display:grid;grid-template-columns:1.15fr .85fr;gap:clamp(28px,5vw,90px);align-items:end}
.spec-kicker{display:block;font-size:10px;letter-spacing:.24em;color:var(--muted)}
.spec-head h2{margin:20px 0 0;max-width:17ch;font-family:var(--display);font-size:clamp(34px,5.4vw,92px);line-height:.96;font-weight:500;letter-spacing:-.032em;text-wrap:balance}
.spec-deck{margin:0;max-width:52ch;font-size:12px;line-height:1.72;letter-spacing:.04em;color:var(--muted);text-wrap:pretty}

.spec-list{list-style:none;display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.6vw,22px);margin:clamp(44px,5.5vw,84px) 0 0;padding:0}
.spec-list li{display:flex;flex-direction:column;min-height:clamp(230px,23vw,320px);padding:18px 20px 24px;background:var(--ink);color:var(--paper)}
.spec-list li>span{font-size:9px;letter-spacing:.18em;color:rgba(251,251,250,.42)}
.spec-list h3{margin:auto 0 0;font-family:var(--display);font-size:clamp(24px,2.4vw,38px);line-height:1.02;font-weight:500;letter-spacing:-.028em;text-wrap:balance}
.spec-list p{margin:13px 0 0;font-size:11px;line-height:1.65;letter-spacing:.04em;color:rgba(251,251,250,.66);text-wrap:pretty}
.spec-list ::selection{background:var(--paper);color:var(--ink)}

.spec-density{margin-top:clamp(46px,6vw,88px);padding-top:clamp(24px,2.8vw,38px);border-top:1px solid var(--ink)}
.spec-density-head{display:grid;grid-template-columns:1.15fr .85fr;gap:clamp(20px,5vw,90px);align-items:start}
.spec-density-head p{margin:0;max-width:24ch;font-family:var(--display);font-size:clamp(22px,2.6vw,42px);line-height:1.04;font-weight:500;letter-spacing:-.026em;text-wrap:balance}
.spec-measures{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,2.4vw,40px);margin:clamp(30px,3.4vw,50px) 0 0}
.spec-measures>div{padding-top:14px;border-top:1px solid var(--rule)}
.spec-measures dt{font-size:9px;letter-spacing:.18em;color:var(--faint)}
.spec-measures dd{margin:11px 0 0;max-width:38ch;font-size:11px;line-height:1.65;letter-spacing:.04em;color:var(--muted);text-wrap:pretty}

@media(max-width:900px){
  .spec-head,.spec-density-head{grid-template-columns:1fr;align-items:start;gap:clamp(16px,2.6vw,26px)}
  .spec-head h2,.spec-density-head p,.spec-measures dd{max-width:none}
  .spec-list{grid-template-columns:1fr}
  .spec-list li{min-height:0}
  .spec-list h3{margin-top:clamp(26px,5vw,44px)}
  .spec-measures{grid-template-columns:1fr;gap:0}
  .spec-measures>div{padding-bottom:18px}
}

/* ── Business licenses ──────────────────────────────────────────────────── */
/* The band runs on ink: it is the page's ask, and the closing panels on
   about and research make the same turn. The button is .ent-link inverted,
   exactly as those two do it, and partner-tree.js is handed the swapped
   palette through the data-ink/data-grid/data-bg attributes on .partner-gfx. */
.enterprise-cta{--ent-pad:clamp(76px,8vw,120px);position:relative;padding:var(--ent-pad) var(--pad);background:var(--ink);color:var(--paper);display:grid;grid-template-columns:1fr auto;gap:clamp(30px,6vw,90px);align-items:center}
.ent-kicker{display:block;font-size:10px;letter-spacing:.24em;color:rgba(251,251,250,.55)}
.enterprise-cta h2{margin:0 0 26px;max-width:920px;font-family:var(--display);font-size:clamp(38px,6vw,96px);line-height:.92;font-weight:500;letter-spacing:-.032em;text-wrap:balance}
.enterprise-cta p{margin:0 0 46px;max-width:56ch;font-size:12px;line-height:1.65;letter-spacing:.04em;color:rgba(251,251,250,.55);text-wrap:pretty}
.ent-link{display:inline-flex;align-items:center;gap:26px;background:var(--ink);color:var(--paper);padding:19px 26px;font-size:11px;font-weight:500;letter-spacing:.14em;transition:opacity .2s}
.ent-link:hover{opacity:.78}
.ent-link b{font-size:17px;font-weight:400}
.enterprise-cta .ent-link{background:var(--paper);color:var(--ink)}
.enterprise-cta ::selection{background:var(--paper);color:var(--ink)}
/* The tree runs the full height of the section: the root sits up near the
   boundary with the band above and the product families land near the one
   below. Negative block margins cancel the section's own vertical padding,
   so the canvas spans it exactly. The stacked band keeps a squarish box on
   purpose — partner-tree.js turns the figure on its side in a landscape
   container, and a wide band crushes three generations into one edge.    */
.partner-gfx{position:relative;width:clamp(300px,36vw,540px);justify-self:end;align-self:stretch;margin-block:calc(var(--ent-pad) * -1);overflow:hidden}
@media(max-width:760px){
  .enterprise-cta{grid-template-columns:1fr;gap:44px}
  .enterprise-cta h2{font-size:clamp(34px,9.5vw,46px)}
  .partner-gfx{width:100%;justify-self:stretch;align-self:auto;margin-block:0;aspect-ratio:1/1}
}

/* ── News — hairline cards, images held in greyscale ────────────────────── */
@media(max-width:900px){
}

/* ── Footer ─────────────────────────────────────────────────────────────── */
.site-footer{border-top:1px solid var(--hair);padding:clamp(56px,8vw,96px) var(--pad) 26px;background:var(--paper)}
.footer-grid{display:grid;grid-template-columns:1fr auto;gap:44px;align-items:start}
.footer-brand .wordmark{font-size:20px}
.footer-brand p{margin:24px 0 0;max-width:44ch;font-size:11px;line-height:1.65;letter-spacing:.06em;color:var(--muted)}
.footer-nav{display:grid;gap:15px;justify-items:end;text-align:right;font-size:10px;letter-spacing:.18em}
.footer-nav a{transition:opacity .2s}
.footer-nav a:hover{opacity:.5}
.footer-base{margin-top:clamp(56px,9vw,110px);padding-top:17px;border-top:1px solid var(--hair);display:flex;justify-content:space-between;gap:14px;font-size:9px;letter-spacing:.16em;color:var(--faint)}
@media(max-width:760px){
  .footer-grid{grid-template-columns:1fr;gap:34px}
  .footer-nav{justify-items:start;text-align:left}
  .footer-base{flex-direction:column;gap:8px}
}

/* ── Contact ─────────────────────────────────────────────────────────────
   Shares this sheet with the home page for the tokens, header and footer.
   Two columns: the routed channels on the left (who to reach for what)
   and the form on the right, under one headline.                          */
.contact-v2{padding:clamp(56px,7vw,96px) var(--pad) clamp(70px,9vw,130px)}
.contact-head{max-width:1200px;border-bottom:1px solid var(--rule);padding-bottom:clamp(34px,4vw,56px)}
.contact-head h1{margin:0;font-family:var(--display);font-size:clamp(44px,7vw,116px);line-height:.88;font-weight:500;letter-spacing:-.035em;text-transform:uppercase}
.contact-head p{margin:clamp(22px,2.6vw,34px) 0 0;max-width:84ch;font-size:12px;line-height:1.65;letter-spacing:.04em;color:var(--muted)}
.contact-grid{display:grid;grid-template-columns:minmax(260px,.8fr) minmax(0,1.2fr);gap:clamp(40px,6vw,110px);padding-top:clamp(40px,5vw,72px)}

/* The routes column is an ink panel, so its rules and muted text are mixed
   from paper rather than from --hair/--rule/--muted, which are ink-based and
   would vanish against it. It stretches to the form's height by default.   */
.contact-routes{background:var(--ink);color:var(--paper);padding:clamp(28px,3vw,42px) clamp(24px,2.6vw,36px) clamp(34px,3.4vw,48px)}
.contact-routes h2{margin:0 0 clamp(24px,3vw,38px);font-family:var(--display);font-size:clamp(21px,2vw,29px);font-weight:500;letter-spacing:-.02em}
.route{padding:18px 0;border-top:1px solid rgba(251,251,250,.16)}
.route-label{display:block;font-size:9px;letter-spacing:.24em;color:rgba(251,251,250,.45)}
.route a{display:inline-block;margin-top:9px;font-size:13px;letter-spacing:.02em;border-bottom:1px solid rgba(251,251,250,.3);padding-bottom:2px;transition:border-color .2s,opacity .2s}
.route a:hover{border-color:var(--paper);opacity:.78}
.route a b{font-weight:400;font-size:15px}
.route p{margin:9px 0 0;font-size:11px;line-height:1.6;letter-spacing:.03em;color:rgba(251,251,250,.62)}
.route i{font-style:normal;color:var(--paper)}
.contact-routes ::selection{background:var(--paper);color:var(--ink)}

.contact-form{display:grid;gap:clamp(22px,2.4vw,30px);align-content:start}
.field-row{display:grid;grid-template-columns:1fr 1fr;gap:inherit}
.field{display:block;position:relative}
.field>span{display:block;font-size:11px;letter-spacing:.16em;color:var(--ink);font-weight: bold;}
.field input,.field textarea{display:block;width:100%;margin-top:11px;padding:13px 15px;border:1px solid var(--rule);background:transparent;color:var(--ink);font:400 15px var(--mono);letter-spacing:.01em;border-radius:0;transition:border-color .2s}
.field textarea{resize:vertical;min-height:120px;line-height:1.55}
.field input::placeholder,.field textarea::placeholder{color:rgba(14,14,14,.32)}
.field input:focus,.field textarea:focus{outline:0;border-color:var(--ink)}
.field-count{position:absolute;right:0;margin-top:8px;font-style:normal;font-size:9px;letter-spacing:.16em;color:var(--faint)}

.check{display:flex;align-items:flex-start;gap:13px;cursor:pointer;font-size:11px;line-height:1.55;letter-spacing:.03em;color:var(--muted)}
.check input{position:absolute;opacity:0;width:0;height:0}
.check i{flex:none;width:15px;height:15px;margin-top:1px;border:1px solid var(--rule);transition:background .18s,border-color .18s}
.check input:checked+i{background:var(--ink);border-color:var(--ink);box-shadow:inset 0 0 0 3px var(--paper)}
.check input:focus-visible+i{border-color:var(--ink);outline:2px solid var(--ink);outline-offset:2px}
.contact-legal{margin:0;font-size:10px;line-height:1.6;letter-spacing:.04em;color:var(--faint)}

.cf-send{justify-self:start;display:inline-flex;align-items:center;gap:26px;margin-top:4px;padding:19px 26px;border:0;background:var(--ink);color:var(--paper);font:500 11px var(--mono);letter-spacing:.14em;cursor:pointer;transition:opacity .2s}
.cf-send:hover{opacity:.78}
.cf-send:disabled{opacity:.45;cursor:default}
.cf-send b{font-weight:400;font-size:17px}
.field-error{margin:0;font-size:11px;letter-spacing:.03em;color:var(--ink);border-left:2px solid var(--ink);padding-left:12px}
.contact-success span{font-size:9px;letter-spacing:.24em;color:var(--faint)}
.contact-success p{margin:18px 0 0;font-family:var(--display);font-size:clamp(26px,2.6vw,40px);line-height:1.06;font-weight:500;letter-spacing:-.028em}

@media(max-width:900px){
  .contact-grid{grid-template-columns:1fr;gap:clamp(44px,7vw,64px)}
  .contact-routes{order:2}
}
@media(max-width:560px){
  .field-row{grid-template-columns:1fr}
}

/* ── Team ────────────────────────────────────────────────────────────────
   Same sheet again, and the same page head as contact: one headline over a
   rule, a paragraph under it, groups below.

   The card is the news card stood up in portrait — hairline pane, greyscale
   photograph, name and role set on paper beneath the rule rather than laid
   over the face. The page is monochrome by design (--accent is the ink), so
   the shots stay in greyscale; there is no colour-up on hover.

   Founders and advisors share that one card and differ only in track width,
   which is what puts the two groups in a hierarchy without a second
   component. Both grids are auto-fill, so adding people to data/team.yaml
   fills the row and then wraps.                                            */
.team-v2{padding:clamp(56px,7vw,96px) var(--pad) clamp(70px,9vw,130px)}
.team-head{max-width:1200px;border-bottom:1px solid var(--rule);padding-bottom:clamp(34px,4vw,56px)}
.team-head h1{margin:0;font-family:var(--display);font-size:clamp(44px,7vw,116px);line-height:.88;font-weight:500;letter-spacing:-.035em;text-transform:uppercase}
.team-head p{margin:clamp(22px,2.6vw,34px) 0 0;max-width:76ch;font-size:12px;line-height:1.65;letter-spacing:.04em;color:var(--muted);text-wrap:pretty}

.team-group{padding-top:clamp(40px,5vw,72px)}
.team-sub{margin:0 0 clamp(22px,2.4vw,30px);padding-top:clamp(30px,3.4vw,46px);border-top:1px solid var(--rule);font-family:var(--mono);font-size:10px;font-weight:400;letter-spacing:.24em;color:var(--muted)}
.team-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,340px),1fr));gap:clamp(14px,1.6vw,22px)}
.team-grid-advisors{grid-template-columns:repeat(auto-fill,minmax(min(100%,250px),1fr))}

.team-card{display:flex;flex-direction:column;border:1px solid var(--rule);background:var(--paper)}
.team-shot{position:relative;margin:0;aspect-ratio:3/4;overflow:hidden;background:#EFEEEC;border-bottom:1px solid var(--rule)}
.team-shot img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;filter:grayscale(1) contrast(1.04)}
.team-fallback{position:absolute;inset:0;display:grid;place-items:center;background-image:linear-gradient(var(--hair) 1px,transparent 1px),linear-gradient(90deg,var(--hair) 1px,transparent 1px);background-size:14px 14px}
.team-fallback span{font-family:var(--display);font-size:clamp(34px,3.4vw,46px);font-weight:500;letter-spacing:.04em;color:rgba(14,14,14,.22)}
.team-meta{padding:15px 17px 21px}
.team-meta h3{margin:0;font-family:var(--display);font-size:clamp(19px,1.7vw,27px);line-height:1.12;font-weight:500;letter-spacing:-.018em;text-wrap:pretty}
.team-meta p{margin:9px 0 0;font-size:9px;line-height:1.5;letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}
.team-grid-advisors .team-meta h3{font-size:clamp(17px,1.35vw,21px)}
@media(max-width:620px){
  .team-grid{grid-template-columns:repeat(auto-fill,minmax(min(100%,260px),1fr))}
  .team-grid-advisors{grid-template-columns:repeat(2,1fr)}
  .team-meta{padding:13px 14px 18px}
}

/* ── About ───────────────────────────────────────────────────────────────
   Three panels in the page's own rhythm: a statement on paper, the industry
   section on ink, the founders back on paper — the same paper/ink alternation
   the home page runs, at a third of the length.

   The opening panel is the statement split in two: a short uppercase title at
   the team page's heading size, then the sentence it used to be set in as a
   lede beneath it. Both are centred on the page — the one centred panel on the
   site, which is what makes the about page open on a statement rather than a
   column. The ticked rule is the home hero's, centred with it. The founders
   reuse .team-grid and the team card wholesale, so the two pages cannot drift
   apart.                                                                   */
.about-hero{padding:clamp(64px,9vw,132px) var(--pad) clamp(56px,7vw,106px);border-bottom:1px solid var(--rule);text-align:center}
.about-hero h1{margin:0 auto;max-width:15ch;font-family:var(--display);font-size:clamp(40px,7vw,116px);line-height:.9;font-weight:500;letter-spacing:-.035em;text-transform:uppercase;text-wrap:balance}
.about-lede{margin:clamp(30px,3.6vw,52px) auto 0;max-width:120ch}
.about-lede .tick{position:relative;height:1px;background:var(--rule);margin-bottom:clamp(18px,2vw,26px)}
.about-lede .tick:before{content:"";position:absolute;left:50%;top:-1px;width:72px;height:3px;margin-left:-36px;background:var(--accent)}
.about-lede p{margin:0;font-family:var(--display);font-size:clamp(21px,2.1vw,32px);line-height:1.1;font-weight:500;letter-spacing:-.028em;text-wrap:balance}

.about-solve{background:var(--ink);color:var(--paper);padding:clamp(80px,11vw,150px) var(--pad);display:grid;grid-template-columns:1.15fr .85fr;gap:clamp(34px,5vw,90px);align-items:end}
.about-solve h2{margin:0;max-width:16ch;font-family:var(--display);font-size:clamp(34px,5.2vw,84px);line-height:.94;font-weight:500;letter-spacing:-.032em;text-wrap:balance}
/* This paragraph is the one long read on the page, and it is paper-on-ink,
   where thin mono at low opacity goes soft. So it is set larger than the 12px
   deck used elsewhere, near-full opacity, on a 56ch measure.                */
.about-solve p{margin:0;max-width:56ch;font-size:clamp(13px,1vw,15.5px);line-height:1.75;letter-spacing:.03em;color:rgba(251,251,250,.88);text-wrap:pretty}
.about-solve ::selection{background:var(--paper);color:var(--ink)}

/* Centred to sit under the centred opening panel. The grid is the team page's
   own, re-tracked for two people: auto-fit collapses the empty tracks and
   justify-content centres what is left, so the pair sits in the middle of the
   page at a card width rather than stretching across it. The cards run wider
   here than on the team page — two founders, so the portraits can take the
   room the four-up grid there cannot give them. Adding founders to
   data/team.yaml fills the row outwards from the centre.

   The centring is the section's, not the card's: the name and role under each
   portrait stay left-aligned, as they are everywhere else the card appears. */
.about-founders{padding:clamp(70px,9vw,120px) var(--pad) clamp(80px,10vw,140px);text-align:center}
.about-founders h2{margin:0 0 clamp(28px,3.4vw,48px);font-family:var(--display);font-size:clamp(30px,4vw,62px);line-height:.98;font-weight:500;letter-spacing:-.03em}
.about-founders .team-grid{justify-content:center;grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),clamp(340px,34vw,470px)))}
.about-founders .team-meta{text-align:left;padding:18px 20px 24px}
.about-founders .team-meta h3{font-size:clamp(21px,2vw,32px)}
/* Closing panel: the page's fourth band, back on ink, centred like the
   opening one. The statement is display type; the location under it is the
   house label — mono, letterspaced, upper — which is also what the footer
   sets GLASGOW, UK in, so the two lines do not read as a repeat.           */
.about-place{background:var(--ink);color:var(--paper);padding:clamp(74px,10vw,132px) var(--pad);text-align:center}
.about-place p{margin:0 auto;max-width:18ch;font-family:var(--display);font-size:clamp(30px,4.6vw,74px);line-height:.98;font-weight:500;letter-spacing:-.032em;text-wrap:balance}
.about-place .about-where{margin-top:clamp(22px,2.6vw,34px);max-width:none;font-family:var(--mono);font-size:11px;font-weight:400;line-height:1.6;letter-spacing:.24em;text-transform:uppercase;color:rgba(251,251,250,.72)}
/* The home page's .ent-link, inverted: it is the same button, and it is on
   ink here, so the fill and the text swap. Nothing else about it changes.  */
.about-cta{margin-top:clamp(30px,3.6vw,46px);background:var(--paper);color:var(--ink)}
.about-place ::selection{background:var(--paper);color:var(--ink)}
@media(max-width:900px){
  .about-solve{grid-template-columns:1fr;gap:clamp(26px,4vw,38px);align-items:start}
  .about-solve h2{max-width:none}
  .about-place p{max-width:none}
}

/* ── Research ────────────────────────────────────────────────────────────
   Three bands: the opening statement, the two figures, the reasons. The two
   figures are one section on purpose — the argument is that they are the
   same weights twice, everything but the bit thrown away, and a band change
   between them would read as two separate claims. The first is a bracketed
   matrix beside the copy; the second breaks the page margin and runs black
   across the full width, because at one bit a value there is nothing left to
   line up in columns, only a field.

   The hero is the about page's, centred on a tick: same shape, its own class
   so the two pages can be tuned apart.                                     */
.rs-hero{padding:clamp(64px,9vw,132px) var(--pad) clamp(56px,7vw,106px);border-bottom:1px solid var(--rule);text-align:center}
.rs-hero h1{margin:0 auto;max-width:16ch;font-family:var(--display);font-size:clamp(44px,7.4vw,124px);line-height:.9;font-weight:500;letter-spacing:-.035em;text-transform:uppercase;text-wrap:balance}
.rs-lede{margin:clamp(28px,3.4vw,48px) auto 0;max-width:88ch}
.rs-lede .tick{position:relative;height:1px;background:var(--rule);margin-bottom:clamp(18px,2vw,26px)}
.rs-lede .tick:before{content:"";position:absolute;left:50%;top:-1px;width:72px;height:3px;margin-left:-36px;background:var(--accent)}
.rs-lede p{margin:0;font-family:var(--display);font-size:clamp(21px,2.1vw,32px);line-height:1.1;font-weight:500;letter-spacing:-.028em;text-wrap:balance}


.rs-band{padding:clamp(70px,9vw,124px) var(--pad)}
.rs-band>h2{margin:0 0 clamp(38px,4.6vw,72px);font-family:var(--display);font-size:clamp(34px,5.2vw,84px);line-height:.94;font-weight:500;letter-spacing:-.032em}

/* Copy left, figure right, and the copy is the one long read on each row, so
   it is set at the ink panel's body size rather than the 12px deck.        */
.rs-row{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(34px,5vw,84px);align-items:center}
.rs-row+.rs-row{margin-top:clamp(48px,6.5vw,104px)}
.rs-copy p{margin:0;max-width:44ch;font-family:var(--display);font-size:clamp(20px,2vw,30px);line-height:1.14;font-weight:500;letter-spacing:-.026em;text-wrap:pretty}
.rs-fn{font-family:var(--mono);font-size:.6em;vertical-align:super;opacity:.7}
.rs-fn:hover{opacity:1}
.rs-note{margin:clamp(30px,3.4vw,48px) 0 0;font-size:11px;line-height:1.7;letter-spacing:.04em;color:var(--muted)}



/* The matrix: a grid of cells between two drawn brackets. The brackets are
   the wrapper's own borders with the middle cut out by a gradient-free
   trick — a border-box with its long edge kept and its ends stubbed — so
   they scale with the type instead of being an image.                      */
.rs-fig{margin:0}
.mtx{display:flex;justify-content:center;gap:clamp(10px,1.2vw,18px);font-family:var(--mono);font-variant-numeric:tabular-nums}
.mtx:before,.mtx:after{content:"";flex:0 0 auto;width:clamp(9px,1vw,14px);border:1px solid var(--rule);border-right:none}
.mtx:after{border:1px solid var(--rule);border-left:none}
.mtx-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:clamp(9px,1.1vw,17px) clamp(12px,1.6vw,26px);padding:clamp(14px,1.6vw,22px) 0;font-size:clamp(11px,1.05vw,15px);letter-spacing:.02em;text-align:right}
.mtx-grid span{white-space:nowrap}
.rs-fig figcaption{margin-top:clamp(18px,2vw,26px);text-align:center;font-size:10px;letter-spacing:.24em;color:var(--muted)}

/* The bit figure is a band, not a bracketed grid: it breaks the band's own
   padding to run the full width of the page, black, with the digits set in
   it edge to edge. Columns auto-fill to the viewport and the height is
   pinned to --rows cells with the overflow clipped, so the template's spare
   cells fall away rather than leaving a ragged last row, and the field
   reads as continuing past both sides. Ones are paper, zeros are held
   back — that contrast is the figure; the digits themselves are texture. */
.rs-bitband{--cell:clamp(20px,2.4vw,38px);--rows:5;margin:clamp(48px,6.5vw,104px) calc(var(--pad) * -1) 0;padding:clamp(34px,4.4vw,64px) var(--pad) clamp(26px,3vw,40px);background:var(--ink);color:var(--paper)}
.rs-bitgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(var(--cell),1fr));grid-auto-rows:var(--cell);height:calc(var(--rows) * var(--cell));overflow:hidden;place-items:center;font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:calc(var(--cell) * .5);line-height:1;letter-spacing:0;color:rgba(251,251,250,.24)}
.rs-bitgrid .on{color:var(--paper)}
.rs-bitband figcaption{margin-top:clamp(20px,2.4vw,32px);text-align:center;font-size:10px;letter-spacing:.24em;color:rgba(251,251,250,.5)}
.rs-bitband ::selection{background:var(--paper);color:var(--ink)}

/* Four reasons, one card each, and the only ink panels on the page — the
   band is paper, so the row of black boxes is what the eye goes to.

   At rest the card is an index at the top and a line of display type on the
   floor. Hovering lifts the title up to the index and lets the copy rise
   into the space it left. Both halves of that are one flex-grow
   interpolation — the spacer above the title collapsing to its gap as the
   copy's box opens under it — because flex-grow animates where an auto
   margin or a height does not. The index is taken out of the flow so the
   spacer can be the card's :before and still sit under it.

   The copy is bottom-aligned in its box: it arrives at the floor the title
   just left, which is why the two moves read as one. Cards are sized so the
   copy fits the open state at the narrowest column — keep it to ~80
   characters if these are ever rewritten, or it will clip.                 */
.rs-why{padding-bottom:clamp(84px,10vw,140px)}
.rs-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:clamp(14px,1.6vw,22px)}
.rs-card{position:relative;display:flex;flex-direction:column;min-height:clamp(200px,20vw,280px);padding:18px 20px 22px;overflow:hidden;border:1px solid var(--ink);background:var(--ink);color:var(--paper)}
.rs-card span{position:absolute;top:18px;left:20px;font-size:10px;letter-spacing:.24em;color:rgba(251,251,250,.42)}
.rs-card:before{content:"";flex:1 1 0;min-height:clamp(28px,3.4vw,52px);transition:flex-grow .5s cubic-bezier(.16,1,.3,1)}
.rs-card h3{flex:none;margin:0;font-family:var(--display);font-size:clamp(24px,2.4vw,38px);line-height:1.02;font-weight:500;letter-spacing:-.028em;text-wrap:balance}
.rs-card p{flex:0 1 0;min-height:0;display:flex;align-items:flex-end;margin:0;font-size:11px;line-height:1.65;letter-spacing:.02em;color:rgba(251,251,250,.66);text-wrap:pretty;opacity:0;transform:translateY(10px);transition:flex-grow .5s cubic-bezier(.16,1,.3,1),opacity .3s,transform .45s cubic-bezier(.16,1,.3,1)}
@media(hover:hover){
  .rs-card:hover:before{flex-grow:0}
  .rs-card:hover p{flex-grow:1;opacity:1;transform:none}
}
/* No hover to give: touch gets the open card, copy and all.               */
@media(hover:none){
  .rs-card:before{flex-grow:0}
  .rs-card p{flex-grow:1;opacity:1;transform:none}
}

/* Closing panel: the about page's, under its own class so the two can be
   tuned apart. Ink under the ink cards is deliberate — the why row already
   broke the paper, and the band's bottom padding keeps the cards off the
   panel, so the page finishes on black rather than flickering back to paper
   for one band. The button is .ent-link inverted, exactly as about does it. */
.rs-close{background:var(--ink);color:var(--paper);padding:clamp(74px,10vw,132px) var(--pad);text-align:center}
.rs-close p{margin:0 auto;max-width:20ch;font-family:var(--display);font-size:clamp(30px,4.6vw,74px);line-height:.98;font-weight:500;letter-spacing:-.032em;text-wrap:balance}
.rs-cta{margin-top:clamp(30px,3.6vw,46px);background:var(--paper);color:var(--ink)}
.rs-close ::selection{background:var(--paper);color:var(--ink)}

@media(max-width:900px){
  .rs-row{grid-template-columns:1fr;gap:clamp(30px,5vw,44px)}
  .rs-copy p{max-width:none}
  .rs-close p{max-width:none}
  .mtx{justify-content:flex-start}
  .rs-fig figcaption{text-align:left;padding-left:clamp(19px,2vw,32px)}
}
@media(max-width:620px){
  .mtx-grid{gap:8px 12px;font-size:10.5px}
}

/* ── Solutions ───────────────────────────────────────────────────────────
   A one-word hero, a statement in a box, then the industries two to a row.

   The hero is the research page's without the lede — one word, so the
   headline is left to be the whole band rather than propped up by a tick
   and a second line it does not need.

   The statement is undrawn: no rule around it, and the hero's bottom padding
   pulled in so it sits close under the title. It is the second half of the
   headline, not a panel — the only thing between the two is the hero rule,
   and the space is tuned so that rule reads as a break in one thought
   rather than as the edge of a section. Its own space is all below, where
   it opens onto the grid.                                                  */
.sl-hero{padding:clamp(64px,9vw,132px) var(--pad) clamp(34px,4.2vw,58px);border-bottom:1px solid var(--rule);text-align:center}
.sl-hero h1{margin:0;font-family:var(--display);font-size:clamp(44px,7.4vw,124px);line-height:.9;font-weight:500;letter-spacing:-.035em;text-transform:uppercase}

.sl-band{padding:clamp(30px,3.6vw,50px) var(--pad) clamp(84px,10vw,140px)}
.sl-statement p{margin:0 auto;max-width:26ch;font-family:var(--display);font-size:clamp(26px,3.6vw,56px);line-height:1.02;font-weight:500;letter-spacing:-.03em;text-align:center;text-wrap:balance}

/* Two per row at every width the row still fits in — the count is fixed
   rather than auto-fit, so the pairing is the layout and not a side effect
   of the card's minimum width.

   The card is the news card turned over: the type is above the rule and the
   pane below it, so the row reads as eight statements each answered by a
   picture rather than eight pictures each captioned. That flip costs one
   thing — grid rows stretch to the tallest card, and the names run from
   "Travel" to "Government & Public Sector" — so the meta is the flexible
   box and the pane is fixed. The slack collects under the copy, which keeps
   every image in a row starting on the same line.                          */
.sl-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(14px,1.6vw,22px);margin-top:clamp(44px,5.5vw,84px)}
.sl-card{display:flex;flex-direction:column;border:1px solid var(--rule);background:var(--paper)}
.sl-meta{display:flex;flex-direction:column;flex:1 1 auto;padding:18px 17px clamp(22px,2.4vw,30px)}
/* .sl-index, not `.sl-meta span` — the meta block holds a button whose span
   an element selector would catch, and at a specificity .btn cannot answer. */
.sl-index{display:flex;justify-content:space-between;align-items:baseline;font-size:9px;letter-spacing:.18em;color:var(--faint)}
.sl-meta h3{margin:9px 0 0;font-family:var(--display);font-size:clamp(21px,2vw,32px);line-height:1.1;font-weight:500;letter-spacing:-.02em;text-wrap:pretty}
.sl-meta p{margin:12px 0 0;max-width:52ch;font-size:11px;line-height:1.65;letter-spacing:.04em;color:var(--muted);text-wrap:pretty}
.sl-shot{flex:none;position:relative;margin:0;aspect-ratio:16/10;overflow:hidden;background:#EFEEEC;border-top:1px solid var(--rule)}
.sl-shot img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;filter:grayscale(1) contrast(1.04)}
/* Empty pane: the team card's graph paper, no badge over it. An unfilled
   slot should read as ruled ground waiting for a picture, not as a caption
   apologising for one.                                                     */
.sl-slot{position:absolute;inset:0;background-image:linear-gradient(var(--hair) 1px,transparent 1px),linear-gradient(90deg,var(--hair) 1px,transparent 1px);background-size:14px 14px}

/* A card given a `link` in data/solutions.yaml is the anchor itself rather
   than a card containing one, so the whole pane is the target. It keeps the
   inert card's type and border — the row must not split into two looks — and
   says so with one arrow set opposite the index, which the border and the
   arrow answering together on hover confirm. An industry without a page yet
   is then simply a card that does nothing, not a card that looks unfinished. */
a.sl-card{color:inherit;text-decoration:none;transition:border-color .2s}
.sl-go{font-style:normal;color:var(--faint);transition:color .2s}
a.sl-card:hover{border-color:var(--ink)}
a.sl-card:hover .sl-go{color:var(--ink)}
a.sl-card:focus-visible{outline:2px solid var(--ink);outline-offset:2px}

/* Learn more is the home page's .btn unchanged — same fill, type and arrow —
   carried by a span rather than a link because the card around it is already
   the anchor. Only the placement is the card's: the wrapper takes the slack
   the copy used to collect (margin-top:auto) and holds the gap as its own
   padding, so a row's buttons sit on one line however long the copy above
   them runs, flush with the copy's left edge. Hover is the card's, not the
   button's — the whole pane is one target, so it answers as one thing.     */
.sl-act{margin-top:auto;padding-top:clamp(18px,2vw,26px);text-align:left}
a.sl-card:hover .btn{opacity:.78}

@media(max-width:760px){
  .sl-grid{grid-template-columns:1fr}
  .sl-shot{aspect-ratio:16/9}
  .sl-statement p{max-width:none}
}

/* ── Model tailoring ─────────────────────────────────────────────────────
   Five bands in the site's paper/ink alternation: the hero, the argument on
   ink, the constraints, the sequence, the close.

   The two middle bands are both on paper and are told apart by their form
   rather than their ground — the constraints are a set, so they are cards in
   a grid with no order implied past their numbering; the steps are a
   sequence, so they are rows down one column with a rule between each. Using
   the same card twice would have flattened that distinction, which is the
   only thing the page has to say about the difference.                     */
.mt-hero{padding:clamp(64px,9vw,132px) var(--pad) clamp(56px,7vw,106px);border-bottom:1px solid var(--rule);text-align:center}
.mt-hero h1{margin:0 auto;max-width:16ch;font-family:var(--display);font-size:clamp(44px,7.4vw,124px);line-height:.9;font-weight:500;letter-spacing:-.035em;text-transform:uppercase;text-wrap:balance}
.mt-lede{margin:clamp(28px,3.4vw,48px) auto 0;max-width:88ch}
.mt-lede .tick{position:relative;height:1px;background:var(--rule);margin-bottom:clamp(18px,2vw,26px)}
.mt-lede .tick:before{content:"";position:absolute;left:50%;top:-1px;width:72px;height:3px;margin-left:-36px;background:var(--accent)}
.mt-lede p{margin:0;font-family:var(--display);font-size:clamp(21px,2.1vw,32px);line-height:1.1;font-weight:500;letter-spacing:-.028em;text-wrap:balance}

/* The about page's ink statement band, headline left and the read right. Two
   paragraphs rather than one, so it is set at that band's size and measure —
   paper-on-ink goes soft below it.                                         */
.mt-brief{background:var(--ink);color:var(--paper);padding:clamp(80px,11vw,150px) var(--pad);display:grid;grid-template-columns:1.15fr .85fr;gap:clamp(34px,5vw,90px);align-items:start}
.mt-brief h2{margin:0;max-width:15ch;font-family:var(--display);font-size:clamp(34px,5.2vw,84px);line-height:.94;font-weight:500;letter-spacing:-.032em;text-wrap:balance}
.mt-brief-copy p{margin:0;max-width:56ch;font-size:clamp(13px,1vw,15.5px);line-height:1.75;letter-spacing:.03em;color:rgba(251,251,250,.88);text-wrap:pretty}
.mt-brief-copy p+p{margin-top:clamp(18px,1.8vw,26px)}
.mt-brief ::selection{background:var(--paper);color:var(--ink)}

.mt-band{padding:clamp(70px,9vw,124px) var(--pad)}
.mt-band>h2{margin:0 0 clamp(38px,4.6vw,72px);font-family:var(--display);font-size:clamp(34px,5.2vw,84px);line-height:.94;font-weight:500;letter-spacing:-.032em}

/* Six constraints, three up. The card is the solutions card with the pane
   taken off: index, name, copy, same hairline and paper.                   */
.mt-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.6vw,22px)}
.mt-card{padding:18px 19px clamp(24px,2.6vw,32px);border:1px solid var(--rule);background:var(--paper)}
.mt-card span{display:block;font-size:9px;letter-spacing:.18em;color:var(--faint)}
.mt-card h3{margin:9px 0 0;font-family:var(--display);font-size:clamp(21px,2vw,32px);line-height:1.1;font-weight:500;letter-spacing:-.02em}
.mt-card p{margin:12px 0 0;font-size:11px;line-height:1.65;letter-spacing:.04em;color:var(--muted);text-wrap:pretty}

/* The sequence: index and step name held left, the copy right, a rule above
   each. The rule is the row's own top border rather than a divider between
   rows, so the list opens and closes on one.                               */
.mt-process{padding-top:0}
.mt-steps{list-style:none;margin:0;padding:0;border-bottom:1px solid var(--rule)}
.mt-steps li{display:grid;grid-template-columns:1.15fr .85fr;gap:clamp(24px,5vw,90px);align-items:start;padding:clamp(28px,3.4vw,44px) 0;border-top:1px solid var(--rule)}
.mt-step-head span{display:block;font-size:9px;letter-spacing:.18em;color:var(--faint)}
.mt-step-head h3{margin:11px 0 0;max-width:18ch;font-family:var(--display);font-size:clamp(24px,2.6vw,42px);line-height:1.04;font-weight:500;letter-spacing:-.026em;text-wrap:balance}
.mt-steps p{margin:0;max-width:56ch;font-size:12px;line-height:1.72;letter-spacing:.04em;color:var(--muted);text-wrap:pretty}

/* Closing panel, as on research and about. */
.mt-close{background:var(--ink);color:var(--paper);padding:clamp(74px,10vw,132px) var(--pad);text-align:center}
.mt-close p{margin:0 auto;max-width:20ch;font-family:var(--display);font-size:clamp(30px,4.6vw,74px);line-height:.98;font-weight:500;letter-spacing:-.032em;text-wrap:balance}
.mt-cta{margin-top:clamp(30px,3.6vw,46px);background:var(--paper);color:var(--ink)}
.mt-close ::selection{background:var(--paper);color:var(--ink)}

@media(max-width:1000px){
  .mt-grid{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:760px){
  .mt-brief{grid-template-columns:1fr;gap:clamp(26px,4vw,38px)}
  .mt-brief h2{max-width:none}
  .mt-steps li{grid-template-columns:1fr;gap:clamp(14px,2vw,20px)}
  .mt-step-head h3{max-width:none}
  .mt-close p{max-width:none}
}
@media(max-width:560px){
  .mt-grid{grid-template-columns:1fr}
}

/* ── Sub-pages ───────────────────────────────────────────────────────────
   The register for pages that hang off a section — /industries/*, and the
   detail pages under /solutions/. Same fonts, same palette, same hairlines;
   a different pitch.

   A top-level page is full-bleed and centred, opens at 124px, and alternates
   paper and ink band by band. A sub-page is a column: crumbs over a smaller
   left-aligned title, sections numbered in a left rail beneath a rule, type
   a step down throughout, and ink held back until the closing panel. So the
   two read as different levels of the same site rather than as the same page
   written twice — which is the whole job, since a reader arrives here from a
   page built in the louder register and should feel they went down a level.

   Anything one sub-page needs past this — the embedded page's comparison
   table, say — is that page's own class laid on top.

   1180px is the same cap the privacy page sets on .pp-wrap, so the two
   things built off this register now hold one column width between them
   rather than two that are close enough to look like a mistake. Nothing
   here fills that width on its own — prose stops at 62ch, headings at 26ch
   — so widening the wrap spends the extra on the units that do: three ink
   cards across instead of two, and more paper either side of the figure
   panes.

   Two colours are re-cut here rather than taken from the site tokens, for
   the reason the privacy page sets out at length further down this sheet:
   --muted is rgba(14,14,14,.55), which composites to #797978 on our paper
   for 4.21:1, under the 4.5:1 WCAG AA floor for normal text — and --faint
   is far worse, 2.50:1. Those are caption settings. They hold up over the
   six-word run under a card title, which is the job they were cut for, and
   they do not hold up over the paragraphs a sub-page argues in.

     --sub-text   .70 alpha, 7.19:1 — AAA, and still visibly short of the
                  ink the headings are set in, so the page keeps its
                  hierarchy rather than flattening to one colour.
     --sub-faint  .58 alpha, 4.68:1 — over the AA floor, and still the
                  quietest thing in the column, which is all a footnote
                  under a table needs to be.

   Both are ratios against #FBFBFA specifically. Re-check them if the paper
   ever moves.                                                              */
.sub-wrap{
  --sub-text:rgba(14,14,14,.7);
  --sub-faint:rgba(14,14,14,.58);
  max-width:1180px;margin:0 auto;padding:clamp(38px,4.6vw,66px) var(--pad) clamp(66px,8vw,108px)}

.sub-head{padding-bottom:clamp(20px,2.4vw,34px)}
.sub-crumbs{display:flex;flex-wrap:wrap;align-items:center;gap:10px;font-size:10px;letter-spacing:.24em;color:var(--muted)}
.sub-crumbs a{color:var(--muted);transition:color .2s}
.sub-crumbs a:hover{color:var(--ink)}
.sub-crumbs i{font-style:normal;color:var(--faint)}
.sub-head h1{margin:clamp(18px,2.2vw,30px) 0 0;font-family:var(--display);font-size:clamp(34px,5.4vw,76px);line-height:.94;font-weight:500;letter-spacing:-.032em;text-wrap:balance}
.sub-deck{margin:clamp(15px,1.7vw,23px) 0 0;max-width:46ch;font-family:var(--display);font-size:clamp(17px,1.6vw,24px);line-height:1.16;font-weight:500;letter-spacing:-.02em;color:var(--muted);text-wrap:pretty}

/* Each section opens on a full rule with its number hanging in the left
   rule. The rule is the sub-page's structure — it is what a reader scrolling
   quickly sees instead of the 84px headings upstream.                      */
.sub-sec{margin-top:clamp(34px,4vw,58px);padding-top:clamp(26px,3vw,40px);border-top:1px solid var(--ink)}
.sub-body{min-width:0}
.sub-body>h2{margin:0;max-width:26ch;font-family:var(--display);font-size:clamp(22px,2.4vw,38px);line-height:1.04;font-weight:500;letter-spacing:-.026em;text-wrap:balance}

/* Size and tracking move with the colour, because all three were cut for a
   caption and none of them survives a paragraph on its own.

   12.5px to 13px is a small step and a deliberate one: 62ch at 13px is
   484px, which is the split's left column to within 4px (see .sub-split
   below), so the measure and the column still land together and the widened
   wrap does not have to be re-divided. Anything larger and the cap stops
   binding, the copy wraps to the column instead, and that arithmetic has to
   be redone.

   Tracking comes down from .035em, which is the change that costs nothing
   and buys the most. DM Mono is spaced by construction — every character
   already occupies the same advance — so tracking it further does not open
   the line, it pulls words apart into loose letters. That is what makes a
   long mono run tiring to read, and it is why the privacy page's four-token
   re-cut lists tracking alongside size and colour rather than under it.    */
.sub-prose{margin-top:clamp(17px,1.9vw,26px)}
.sub-prose p{margin:0;max-width:62ch;font-size:13px;line-height:1.78;letter-spacing:.018em;color:var(--sub-text);text-wrap:pretty}
.sub-prose p+p{margin-top:clamp(13px,1.4vw,19px)}
.sub-note{margin:clamp(17px,1.9vw,25px) 0 0;max-width:62ch;font-size:11px;line-height:1.7;letter-spacing:.02em;color:var(--sub-faint);text-wrap:pretty}

/* A section that runs its copy against a figure. The heading stays out of
   the split and keeps the full measure — put it in the left column and it
   wraps to three cramped lines with the figure's corner jammed against its
   x-height. The split starts under it: prose left, figure right, and the
   figure stretches to the grid row, whose height is the prose's height, so
   the two columns share all four edges and the figure reads as part of the
   text block rather than a box hanging near it.

   The columns are uneven on purpose, and the ratio is arithmetic rather
   than taste: the copy caps itself at 62ch, which is 484px at 13px, so a
   left column wider than that buys nothing but a dead strip between the
   text's ragged right edge and the figure's hard one. At the wrap's cap
   there are 1032px to divide, and 1fr 1.15fr puts 480px on the left — the
   measure to within 4px — and hands the remainder to the figure. An even
   split would leave the copy 32px short of its own column. Below the cap
   the copy is the narrower thing anyway and the ratio stops mattering. The
   split carries the prose's clamp itself and zeroes the inner margin, so
   the gap under the heading is the same whether a section splits or not.

   What stands in the right column is the page's own business — the embedded
   page sets its chip plate there (.eh-plate, below). Not a photograph: a
   sub-page is typography from the crumbs to the close, and the only pages
   that carry photography set it inside a card system. One photo loose on a
   page of type reads as pasted in at any size or crop.                     */
.sub-split{display:grid;grid-template-columns:1fr 1.15fr;gap:clamp(24px,3.6vw,52px);margin-top:clamp(17px,1.9vw,26px)}
.sub-split .sub-prose{margin-top:0}
/* Stacked before the 760px the rest of this register breaks at: half the
   page is a fair measure at 1180 and a mean one at 800, and the figure
   loses less by dropping below the copy than the copy loses by narrowing.  */
@media(max-width:880px){
  .sub-split{grid-template-columns:1fr;gap:clamp(20px,3vw,30px)}
}

/* Ink cards. The top-level pages set this unit as a hairline box on paper,
   so filling it keeps the two levels apart while making the list the one
   dark thing on a page that is otherwise all paper until the close — which
   is what makes it read as the answer to the heading above it rather than as
   more of the same argument.

   It is the research page's why card, and it works the same way: at rest a
   title alone on the floor of the box, and hovering lifts it to the ceiling
   while the copy rises into the space it left. Both moves are one flex-grow
   interpolation — the spacer above the title collapsing as the copy's box
   opens under it — because flex-grow animates where an auto margin or a
   height does not. No index here, so the spacer can be the card's own
   :before and collapse to nothing, putting the title flush under the top
   padding rather than under a label.

   The copy is bottom-aligned in its box, arriving at the floor the title
   just left, which is what makes the two moves read as one.

   min-height:0 on that copy is load-bearing, not tidying. A flex item's
   min-height defaults to auto, which is its content height — so a zero
   basis alone does not close the box, the paragraph keeps its full height
   while invisible, and the title floats above a reserved gap instead of
   sitting on the floor. Removing it puts the resting title back in the
   middle of the card.

   Three across, two down. Six cards divide either way, and three columns is
   what the widened wrap is for: the block reads as one band of the page's
   one dark material rather than a three-row list, which is what it needs to
   be now that it opens the page instead of closing it.

   The card's own type had to come down with the column. At two across the
   box was ~500px and a 26px title sat in it comfortably; at ~350px the same
   title runs to three lines, so the ceiling drops to 23px. min-height goes
   the other way for the same reason — a narrower box takes more lines to
   say the same thing, and the copy only has the height the card was already
   given, since hovering redistributes that height rather than adding to it.
   Overrun is clipped by overflow:hidden, silently, so the floor here is set
   against the longest card (Intelligence Density, five lines at the tightest
   three-column width) rather than against the average.                     */
.sub-list{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(12px,1.4vw,18px);margin:clamp(18px,2.2vw,30px) 0 0;padding:0;list-style:none}
.sub-list li{display:flex;flex-direction:column;min-height:clamp(196px,20vw,236px);padding:17px 18px clamp(21px,2.3vw,27px);overflow:hidden;background:var(--ink);color:var(--paper)}
.sub-list li:before{content:"";flex:1 1 0;transition:flex-grow .5s cubic-bezier(.16,1,.3,1)}
.sub-list h3{flex:none;margin:0;font-family:var(--display);font-size:clamp(17px,1.6vw,23px);line-height:1.1;font-weight:500;letter-spacing:-.02em;text-wrap:balance}
.sub-list p{flex:0 1 0;min-height:0;display:flex;align-items:flex-end;margin:0;font-size:11px;line-height:1.68;letter-spacing:.04em;color:rgba(251,251,250,.66);text-wrap:pretty;opacity:0;transform:translateY(10px);transition:flex-grow .5s cubic-bezier(.16,1,.3,1),opacity .3s,transform .45s cubic-bezier(.16,1,.3,1)}
.sub-list ::selection{background:var(--paper);color:var(--ink)}
@media(hover:hover){
  .sub-list li:hover:before{flex-grow:0}
  .sub-list li:hover p{flex-grow:1;opacity:1;transform:none}
}
/* No hover to give: touch gets the open card, copy and all.               */
@media(hover:none){
  .sub-list li:before{flex-grow:0}
  .sub-list p{flex-grow:1;opacity:1;transform:none}
}
/* Three across needs the wrap near its cap to stay honest — under about
   940px the cards are narrow enough that every title takes three lines. Two
   across is the old layout and holds down to the register's own 760px
   break, where it goes to one. Six cards divide evenly at all three counts,
   so no step leaves a short row.                                           */
@media(max-width:940px){
  .sub-list{grid-template-columns:repeat(2,1fr)}
}


/* The closing panel goes full-bleed, outside .sub-wrap, so the page still
   ends the way every other page on the site ends — but a size down, because
   it is closing a sub-page and not a front door.                           */
.sub-close{background:var(--ink);color:var(--paper);padding:clamp(56px,7vw,94px) var(--pad);text-align:center}
.sub-close p{margin:0 auto;max-width:48ch;font-family:var(--display);font-size:clamp(24px,3.4vw,52px);line-height:1;font-weight:500;letter-spacing:-.03em;text-wrap:balance}
.sub-cta{margin-top:clamp(26px,3vw,38px);background:var(--paper);color:var(--ink)}
.sub-close ::selection{background:var(--paper);color:var(--ink)}

@media(max-width:760px){
  .sub-body>h2{max-width:none}
  .sub-list{grid-template-columns:1fr}
  .sub-close p{max-width:none}
}

/* ── Embedded hardware ───────────────────────────────────────────────────
   Three components on top of the sub-page register — the comparison table,
   the measured-stats strip, and the chip plate. The table is set
   as a spec sheet — mono throughout, tabular figures so the three columns
   of numbers line up digit under digit, hairline rows, no vertical rules.
   The one-bit column is the only thing on the page held at full ink and the
   two floating-point columns are set in --muted beside it; that contrast is
   the whole comparison, which is why the column needs no highlight or
   badge. Adding FP4 did not change that rule — it put a second column on
   the muted side of it, which is the correct side, since the row that
   matters reads the same in both.

   A min-width with a scroller around it rather than a stacked layout on
   small screens: four short columns still read side by side, and the
   comparison stops being one the moment the rows are cut apart. The floor
   is set a little under the table's natural no-wrap width (~573px, set by
   the weight-arithmetic row, which now carries multiply-accumulate twice),
   so the longest row may break to two lines at the very bottom before the
   scroller takes over — the same trade the three-column version made at
   380px. Below about 560px viewport it scrolls.                            */
.eh-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;margin-top:clamp(18px,2.2vw,30px)}
.eh-table{width:100%;min-width:520px;border-collapse:collapse;font-family:var(--mono);font-variant-numeric:tabular-nums}
.eh-table th,.eh-table td{padding:clamp(12px,1.4vw,18px) 12px;text-align:right;vertical-align:baseline;border-top:1px solid var(--rule)}
.eh-table th:first-child,.eh-table td:first-child{padding-left:0;text-align:left}
.eh-table th:last-child,.eh-table td:last-child{padding-right:0}
.eh-table thead th{padding-top:0;border-top:0;border-bottom:1px solid var(--ink);font-size:9px;font-weight:400;letter-spacing:.2em;text-transform:uppercase;color:var(--muted)}
.eh-table tbody th{font-size:11px;font-weight:400;letter-spacing:.04em;color:var(--ink)}
.eh-table tbody td{font-size:clamp(12px,1.15vw,15.5px);letter-spacing:.01em;color:var(--muted)}
.eh-table .eh-ours{color:var(--ink)}
.eh-table tbody .eh-ours{font-weight:500}

/* Three headline multipliers drawn from the published memory, speed and
   energy comparisons. Same spec-sheet material as the table — hairline top
   rules, mono labels, tabular figures — with the multiplier itself the one
   thing set in display type, because it is the whole argument. Labels take
   --sub-faint, which the register cut for exactly this: a caption over a
   figure that carries its own weight. Stacks to a ruled list on phones,
   like the homepage's density measures.                                    */
.eh-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,2vw,32px);margin:clamp(24px,2.8vw,40px) 0 0}
.eh-stats>div{padding-top:clamp(12px,1.4vw,18px);border-top:1px solid var(--rule)}
.eh-stats dt{font-size:9px;letter-spacing:.2em;color:var(--sub-faint)}
.eh-stats dd{margin:12px 0 0}
.eh-stats strong{display:block;font-family:var(--display);font-size:clamp(30px,3.4vw,54px);line-height:1;font-weight:500;letter-spacing:-.03em;font-variant-numeric:tabular-nums}
.eh-stats dd span{display:block;margin-top:10px;max-width:30ch;font-size:11px;line-height:1.65;letter-spacing:.02em;color:var(--sub-text);text-wrap:pretty}
@media(max-width:640px){
  .eh-stats{grid-template-columns:1fr;gap:0}
  .eh-stats>div{padding-bottom:20px}
  .eh-stats dd span{max-width:none}
}

/* The plate beside the opening prose: the chip mark from images/icons/,
   set on the graph paper the site draws its panes with, the way a part sits
   on the plate of a datasheet. The pane keeps the figure column's job in
   the split — hairline edges, height borrowed from the prose — and the mark
   floats centred in whatever it gets, sized well inside the box so it reads
   as a set plate rather than a stretched illustration.

   The mark comes in as an <img> so the icon file stays the single source;
   an img cannot inherit page colour, so the file's fills carry the ink hex
   (#0E0E0E) rather than pure black. The squares against the 14px grid is
   the same pixel-on-graph-paper language as the rest of the site's panes,
   which is what lets an icon stand where a photograph could not.           */
.eh-plate{display:flex;align-items:center;justify-content:center;margin:0;min-height:216px;padding:clamp(24px,3vw,40px);border:1px solid var(--rule);background-image:linear-gradient(var(--hair) 1px,transparent 1px),linear-gradient(90deg,var(--hair) 1px,transparent 1px);background-size:14px 14px}
.eh-plate img{display:block;width:min(78%,344px);height:auto}

/* Embedded editorial layout. The general sub-page register keeps prose on a
   deliberately short measure; this page has enough sustained argument that
   the unused half of the sheet looked accidental. Here the section heading
   becomes a proper left rail and the copy uses a pair of comfortable reading
   columns. Evidence blocks then span the sheet and visually reset the pace. */
.eh-page .sub-head{
  display:grid;
  grid-template-columns:minmax(0,.82fr) minmax(300px,.48fr);
  column-gap:clamp(40px,7vw,110px);
  align-items:end;
}
.eh-page .sub-crumbs{grid-column:1/-1}
.eh-page .sub-head h1{grid-column:1}
.eh-page .sub-deck{grid-column:2;margin-bottom:.08em;max-width:34ch}

.eh-page .sub-sec{margin-top:clamp(48px,6.5vw,88px);padding-top:clamp(24px,2.8vw,38px)}
.eh-page .sub-sec>.sub-body{
  display:grid;
  grid-template-columns:minmax(210px,.68fr) minmax(0,1.42fr);
  column-gap:clamp(36px,6vw,92px);
  row-gap:clamp(28px,3.4vw,46px);
  align-items:start;
}
.eh-page .sub-sec .sub-body>h2{
  grid-column:1;
  margin:0;
  max-width:14ch;
  font-size:clamp(27px,3.1vw,45px);
  line-height:.98;
}
.eh-page .sub-sec .sub-body>h2:before{
  content:attr(data-section);
  display:block;
  margin-bottom:clamp(16px,1.8vw,24px);
  font-family:var(--mono);
  font-size:9px;
  line-height:1;
  font-weight:400;
  letter-spacing:.2em;
  color:var(--sub-faint);
}
.eh-page .sub-sec>.sub-body>.sub-prose,
.eh-page .sub-sec>.sub-body>.sub-split{
  grid-column:2;
  grid-row:1;
  margin-top:0;
}
.eh-page .sub-prose{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(22px,3vw,42px);
}
.eh-page .sub-prose p{
  max-width:none;
  font-size:clamp(12.5px,1.08vw,14px);
  line-height:1.75;
  letter-spacing:.008em;
}
.eh-page .sub-prose p+p{margin-top:0}
.eh-page .sub-prose p:last-child:nth-child(odd){
  grid-column:1/-1;
  margin-top:4px;
  padding:clamp(18px,2.2vw,28px) clamp(20px,2.5vw,32px);
  border-left:2px solid var(--ink);
  background:rgba(14,14,14,.045);
  color:var(--ink);
}

.eh-page .sub-split{grid-template-columns:1fr;gap:clamp(26px,3vw,40px)}
.eh-page .eh-plate{min-height:clamp(180px,20vw,245px)}

.eh-page .eh-stats,
.eh-page .eh-scroll,
.eh-page .sub-sec>.sub-body>.sub-note{
  grid-column:1/-1;
}
.eh-page .eh-stats{margin-top:clamp(4px,1vw,12px)}
.eh-page .eh-stats>div{
  min-height:190px;
  padding:clamp(16px,1.8vw,23px) clamp(16px,1.8vw,24px) clamp(18px,2vw,26px);
  border:1px solid var(--rule);
  background:rgba(14,14,14,.018);
}
.eh-page .eh-stats strong{font-size:clamp(34px,4vw,58px)}
.eh-page .eh-stats dd span{max-width:34ch}
.eh-page .sub-sec>.sub-body>.sub-note{
  margin:calc(clamp(28px,3.4vw,46px) * -1 + clamp(15px,1.8vw,24px)) 0 0;
  padding-top:clamp(14px,1.6vw,20px);
  max-width:none;
  border-top:1px solid var(--rule);
}
.eh-page .eh-scroll{margin-top:0}

@media(max-width:880px){
  .eh-page .sub-head{grid-template-columns:1fr}
  .eh-page .sub-head h1,.eh-page .sub-deck{grid-column:1}
  .eh-page .sub-deck{max-width:46ch;margin-bottom:0}
  .eh-page .sub-sec>.sub-body{grid-template-columns:1fr;row-gap:clamp(22px,3vw,30px)}
  .eh-page .sub-sec .sub-body>h2{grid-column:1;max-width:20ch}
  .eh-page .sub-sec>.sub-body>.sub-prose,
  .eh-page .sub-sec>.sub-body>.sub-split{grid-column:1;grid-row:auto}
}
@media(max-width:640px){
  .eh-page .sub-prose{grid-template-columns:1fr;gap:18px}
  .eh-page .sub-prose p:last-child:nth-child(odd){grid-column:auto;margin-top:0}
  .eh-page .eh-stats>div{min-height:0}
  .eh-page .sub-sec>.sub-body>.sub-note{margin-top:calc(clamp(28px,3.4vw,46px) * -1 + 16px)}
}



/* ── Privacy policy ──────────────────────────────────────────────────────
   A reference document rather than a page of argument, so it is set as one.
   It keeps the sub-page register — crumbs over a left-aligned title,
   sections numbered against a full rule, ink held back until the close —
   but the sub-page's own reading measure is wrong here: nobody reads this
   top to bottom, they arrive looking for one clause. So the column gains a
   standing contents rail, and the numbering that hangs decoratively in the
   left rule upstream becomes the thing the rail points at.

   The rail is sticky rather than fixed because the header is neither: it
   scrolls away, and the rail should take its place at the top of the
   viewport rather than fight it for the same 60px. Under 900px it stops
   being a rail and becomes a two-column index sitting above the document,
   which is the only place it can go once the page is one column wide.

   Type runs a step ABOVE the sub-pages', which is the opposite of what the
   page length suggests and is the whole point. Everywhere else on the site
   body copy is a short supporting passage under a large heading: 12.5px,
   --muted, tracked out .035em. That setting is doing a different job — it
   is a caption, and it is read in six-line runs.

   Eight thousand words of it is unreadable, and measurably so: --muted is
   rgba(14,14,14,.55), which composites to #797978 on our paper for a
   contrast ratio of 4.21:1. That is under the 4.5:1 WCAG AA floor for
   normal text. At 12.5px, positive tracking on a monospace face, it is the
   hardest reading on the site.

   So the four settings that matter are re-cut here as page-scoped tokens,
   and every rule below draws from them rather than restating numbers:

     --pp-text   .88 alpha, 13.86:1. Near-ink, a hair short of it so the
                 page reads soft rather than printed.
     --pp-size   up from 12.5px. Mono needs less size than a proportional
                 face for the same x-height, but not this much less.
     --pp-track  down from .035em. A monospace face is already spaced by
                 construction; tracking it further pulls words apart into
                 loose letters, which is what makes long mono runs tiring.
     --pp-lh     leading tracks the measure. See below — this page sets one
                 column width for everything, which is wide, and a long line
                 needs more leading or the eye loses its place on the return
                 sweep back to the left edge.

   Nothing carries its own measure. Prose, lists, drafting notes and tables
   all run the full width of the body column and share one right edge, so
   the page reads as a single column of blocks rather than as prose with
   tables sticking out past it. That alignment is the brief.

   Because nothing caps itself, the measure is whatever the column happens
   to be, and --pp-size is the only thing holding it: type has to grow as
   the column does or the line count per line runs away. The two ramps here
   and in the 900px query hold the body between 66 and 85 characters from
   360px to 1920px. On a single flat ramp the same layout ran 46 to 97, the
   worst of it at ordinary laptop widths where the type had bottomed out
   while the column was still opening.

   85 is still over the 45–75 that reads most comfortably (in a monospace
   face 1ch is exactly one character, so those are literal counts), and the
   leading above is set wide to carry it. Long-form argument would not
   survive this measure; a reference document scanned for one clause does.
   If it still reads too wide, .pp-wrap's max-width is the single lever —
   1180px to 1100px pulls every block in together, which is the property
   worth keeping.

   The face itself stays DM Mono. --display is a headline cut, never used
   below 14.4px or under weight 500 anywhere in this sheet, and putting the
   one long read on the site into a different family would cost more than
   the poor setting did.                                                    */
.pp-wrap{
  --pp-text:rgba(14,14,14,.88);
  --pp-size:clamp(15px,1.3vw,16px);
  --pp-track:.012em;
  --pp-lh:1.78;
  max-width:1180px;margin:0 auto;padding:clamp(38px,4.6vw,66px) var(--pad) clamp(56px,7vw,92px)}

/* The masthead line: the two dates the document is legally read against,
   set as data rather than as a sentence.                                   */
.pp-meta{display:flex;flex-wrap:wrap;gap:10px clamp(20px,3vw,44px);margin:clamp(20px,2.4vw,32px) 0 0;padding-top:clamp(14px,1.6vw,20px);border-top:1px solid var(--rule)}
.pp-meta>div{display:flex;flex-wrap:wrap;align-items:baseline;gap:9px}
.pp-meta dt{font-size:9px;letter-spacing:.22em;text-transform:uppercase;color:var(--faint)}
.pp-meta dd{margin:0;font-size:11px;letter-spacing:.06em;color:var(--ink)}

/* The rail widens with the type it holds. Most contents labels run 23–26
   characters, which at 11.5px is about 180px of text before the counter
   column — under the old 196px they all wrapped, and a nav that wraps every
   other line stops being scannable, which is the only thing it is for.    */
.pp-cols{display:grid;grid-template-columns:clamp(160px,16vw,214px) 1fr;gap:clamp(26px,4vw,60px);align-items:start;margin-top:clamp(30px,3.6vw,50px)}

.pp-toc{position:sticky;top:22px;max-height:calc(100vh - 44px);overflow-y:auto;padding-top:clamp(20px,2.4vw,30px);border-top:1px solid var(--ink)}
.pp-toc h2{margin:0 0 12px;font-family:var(--mono);font-size:9px;font-weight:400;letter-spacing:.22em;text-transform:uppercase;color:var(--faint)}
.pp-toc ol{margin:0;padding:0;list-style:none;counter-reset:pp}
.pp-toc li{counter-increment:pp;break-inside:avoid}
.pp-toc a{display:grid;grid-template-columns:22px 1fr;gap:8px;padding:5px 0;font-size:11.5px;line-height:1.42;letter-spacing:var(--pp-track);color:var(--pp-text);transition:color .2s}
.pp-toc a:before{content:counter(pp,decimal-leading-zero);color:var(--faint)}
.pp-toc a:hover{color:var(--ink)}

/* scroll-margin, not a magic top offset: these are anchor targets, and a
   heading that lands flush against the viewport edge reads as cut off.    */
.pp-sec{display:grid;grid-template-columns:clamp(36px,4vw,54px) 1fr;gap:clamp(10px,1.4vw,18px);padding-top:clamp(24px,2.8vw,38px);border-top:1px solid var(--ink);scroll-margin-top:22px}
.pp-sec+.pp-sec{margin-top:clamp(30px,3.6vw,52px)}
.pp-num{padding-top:.42em;font-size:10px;letter-spacing:.16em;color:var(--faint)}
.pp-body{min-width:0}
.pp-body>h2{margin:0;max-width:24ch;font-family:var(--display);font-size:clamp(21px,2.2vw,34px);line-height:1.05;font-weight:500;letter-spacing:-.026em;text-wrap:balance}
/* h3 has to move up with the body: at the old size it landed within a
   couple of px of 15px body text and stopped reading as a heading at all. */
.pp-body h3{margin:clamp(26px,2.9vw,38px) 0 0;font-family:var(--display);font-size:clamp(17px,1.5vw,22px);line-height:1.2;font-weight:500;letter-spacing:-.016em}
/* The gap between paragraphs is now a little over one line rather than
   under it, so a break reads as a break instead of as a wide leading.     */
.pp-body p{margin:clamp(15px,1.6vw,21px) 0 0;font-size:var(--pp-size);line-height:var(--pp-lh);letter-spacing:var(--pp-track);color:var(--pp-text);text-wrap:pretty}
.pp-body strong{color:var(--ink);font-weight:500}
.pp-body a{box-shadow:inset 0 -1px 0 var(--rule);transition:box-shadow .2s}
.pp-body a:hover{box-shadow:inset 0 -1px 0 var(--ink)}

.pp-list{margin:clamp(15px,1.6vw,21px) 0 0;padding:0;list-style:none}
.pp-list li{position:relative;padding-left:21px;font-size:var(--pp-size);line-height:var(--pp-lh);letter-spacing:var(--pp-track);color:var(--pp-text);text-wrap:pretty}
.pp-list li+li{margin-top:11px}
.pp-list li:before{content:"";position:absolute;left:0;top:.82em;width:8px;height:1px;background:var(--muted)}
.pp-list strong{color:var(--ink);font-weight:500}

/* The embedded page's spec sheet, re-cut for text: left-aligned, top-
   aligned so a long cell does not drag its short neighbours down the row,
   and no tabular figures because there are no figures to line up.
   --wide is for the CCPA disclosure grid, which is six columns of prose and
   cannot be made to fit; it scrolls rather than collapsing, because the row
   is the disclosure and cutting it apart loses it.

   A cell is scanned rather than read in runs, so it sits one step under the
   body size — but it takes the same colour, because 11px of --muted was the
   worst-lit text on the page and a retention period nobody can read is not
   a disclosure. The wide table's min-width grows with the type, or the
   columns it was holding open just collapse again.                         */
.pp-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;margin-top:clamp(18px,2.1vw,26px)}
.pp-table{width:100%;border-collapse:collapse;font-family:var(--mono);text-align:left}
.pp-table th,.pp-table td{padding:clamp(11px,1.2vw,15px) 16px;vertical-align:top;border-top:1px solid var(--rule);font-size:calc(var(--pp-size) - 2px);line-height:1.62;letter-spacing:var(--pp-track);font-weight:400}
.pp-table th:first-child,.pp-table td:first-child{padding-left:0}
.pp-table th:last-child,.pp-table td:last-child{padding-right:0}
.pp-table thead th{padding-top:0;border-top:0;border-bottom:1px solid var(--ink);font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;color:var(--muted)}
.pp-table tbody th{color:var(--ink);font-weight:500}
.pp-table tbody td{color:var(--pp-text)}
.pp-table--wide{min-width:1000px}
.pp-table--pairs tbody th{width:34%}

/* Every unresolved item in the source template — a date, an address, an
   address for rights requests, a document that has not been written yet —
   is marked here rather than guessed at. A privacy policy that misdescribes
   what a company does is itself the violation, so an invented email that
   bounces is worse than a visible gap. Finishing the page means filling
   these in and deleting the marks; it does not mean deleting this rule.

   Toned down from the first pass: there are 55 of these, and a mark loud
   enough to read well once is a stutter on every third line when it is
   that dense. It has to interrupt the sentence without breaking it.       */
.pp-tbc{padding:1px 5px;border:1px dashed var(--rule);background:rgba(14,14,14,.04);font-size:.92em;letter-spacing:.05em;color:var(--ink)}

/* Instructions the template addressed to whoever finishes it — not policy
   text. Kept on the page and kept visibly apart from it, so they get
   answered rather than quietly shipped as though they were clauses.

   Two classes deep on purpose: these are paragraphs sitting inside .pp-body,
   and .pp-body p already carries a class and a type. A single class would
   lose the cascade to it and render as ordinary policy text, which is the
   one thing this must never look like.                                     */
.pp-doc .pp-draft{margin:clamp(16px,1.8vw,22px) 0 0;padding:13px 0 13px 16px;border-left:2px solid var(--ink);background:rgba(14,14,14,.04);font-size:calc(var(--pp-size) - 1.5px);line-height:1.68;letter-spacing:var(--pp-track);color:var(--pp-text)}
.pp-doc .pp-draft b{display:block;margin-bottom:4px;font-size:9.5px;font-weight:400;letter-spacing:.22em;text-transform:uppercase;color:var(--muted)}

/* Below this the rail stops taking its 214px out of the row, so the body
   column jumps wider at the exact moment the viewport gets smaller — 595px
   at 901px wide, 789px at 899px. Type on a single ramp cannot follow that
   step, and left alone it is the worst measure on the page. So the ramp is
   re-based for the stacked layout: steeper, and starting higher.          */
@media(max-width:900px){
  .pp-wrap{--pp-size:clamp(14px,1.85vw,16.5px)}
  .pp-cols{grid-template-columns:1fr;gap:clamp(30px,4vw,44px)}
  .pp-toc{position:static;max-height:none;overflow:visible}
  .pp-toc ol{columns:2;column-gap:clamp(20px,4vw,40px)}
}
@media(max-width:620px){
  .pp-sec{grid-template-columns:1fr;gap:7px}
  .pp-num{padding-top:0}
  .pp-body>h2{max-width:none}
  .pp-toc ol{columns:1}
}

/* ── Models — three modalities across one black field ────────────────────
   Language, vision and audio each own a panel of the section background,
   with their own generative canvas behind the copy. Inverted: paper type
   on ink, so the ink-on-paper ordering of the page breaks here and the
   models read as the darkroom in the middle of the site.                  */
.models{background:var(--ink);color:var(--paper)}
.models-layout{padding:clamp(82px,10vw,142px) var(--pad) clamp(74px,8vw,116px)}
.models-head h2{margin:0 0 clamp(40px,5vw,72px);font-family:var(--display);font-size:clamp(22px,4.1vw,68px);line-height:.94;font-weight:500;letter-spacing:-.032em;white-space:nowrap;text-wrap:nowrap}

/* Hairline gaps, not borders: the grid's own background shows through the
   1px gutters, so the three panels read as divisions of one field. */
.model-fields{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:rgba(251,251,250,.16);border:1px solid rgba(251,251,250,.16)}
.model-field{position:relative;display:flex;flex-direction:column;justify-content:flex-end;min-height:clamp(500px,62vh,660px);overflow:hidden;background-color:var(--ink);background-image:linear-gradient(rgba(251,251,250,.03) 1px,transparent 1px),linear-gradient(90deg,rgba(251,251,250,.03) 1px,transparent 1px);background-size:48px 48px;isolation:isolate}
.model-field:before{content:"";position:absolute;z-index:1;inset:0;pointer-events:none;background:linear-gradient(180deg,rgba(14,14,14,0) 30%,rgba(14,14,14,.6) 58%,var(--ink) 88%)}
.model-viz{position:absolute;z-index:0;inset:0;width:100%;height:100%;display:block;pointer-events:none}
.model-field-body{position:relative;z-index:2;padding:clamp(24px,2.4vw,36px)}
.model-status{display:inline-flex;align-items:center;gap:8px;font-size:9.5px;letter-spacing:.18em;color:rgba(251,251,250,.68)}
.model-status i{width:6px;height:6px;background:var(--paper);border-radius:50%;box-shadow:0 0 0 3px rgba(251,251,250,.12)}
.model-status--development i{background:transparent;border:1px solid rgba(251,251,250,.7);box-shadow:none}
.model-field h3{margin:clamp(13px,1.5vw,20px) 0 0;font-family:var(--display);font-size:clamp(28px,2.7vw,44px);line-height:.92;font-weight:500;letter-spacing:-.032em}
.model-tag{margin:clamp(9px,1vw,13px) 0 0;font-family:var(--display);font-size:clamp(15px,1.2vw,19px);font-weight:500;letter-spacing:-.015em;color:rgba(251,251,250,.55)}
.model-desc{margin:clamp(16px,1.8vw,24px) 0 0;max-width:42ch;font-size:11px;line-height:1.72;letter-spacing:.035em;color:rgba(251,251,250,.6);text-wrap:pretty}
/* Contact prompt flush at the foot of each panel — a direct child of the
   card, after the copy block, so the flex column pins it to the bottom
   edge. Revealed on that panel's hover; it always occupies its space, so
   revealing it shifts nothing, and living inside the panel means the
   pointer never leaves the hover target on its way down. Outline register:
   a hairline top rule, no fill — the card's own edges close the box.
   Keyboard users get it via :focus-within (an opacity:0 link is still
   tabbable). */
.model-cta{position:relative;z-index:2;display:flex;align-items:center;justify-content:center;gap:13px;padding:clamp(15px,1.7vw,21px);border-top:1px solid rgba(251,251,250,.22);color:var(--paper);font-size:10px;font-weight:500;letter-spacing:.2em;text-transform:uppercase;opacity:0;transform:translateY(7px);pointer-events:none;transition:opacity .28s,transform .28s cubic-bezier(.16,1,.3,1),border-color .25s,background-color .25s}
.model-cta b{font-weight:400;font-size:13px;transition:transform .3s cubic-bezier(.16,1,.3,1)}
.model-field:hover .model-cta,.model-field:focus-within .model-cta{opacity:1;transform:none;pointer-events:auto}
.model-cta:hover{border-color:rgba(251,251,250,.55);background:rgba(251,251,250,.05)}
.model-cta:hover b,.model-cta:focus-visible b{transform:translateX(5px)}
.model-cta:focus-visible{outline:2px solid var(--paper);outline-offset:-4px}
/* No hover on touch — the prompt would be unreachable, so it just stays up. */
@media(hover:none){.model-cta{opacity:1;transform:none;pointer-events:auto}}

@media(max-width:1000px){
  .model-fields{grid-template-columns:1fr}
  .model-field{min-height:clamp(400px,52vh,480px)}
}
@media(max-width:620px){
  .models-layout{padding-top:68px;padding-bottom:70px}
  /* Too narrow for one legible line — wrap rather than overflow. */
  .models-head h2{font-size:clamp(32px,8.6vw,44px);white-space:normal;text-wrap:balance}
  .model-field{min-height:380px}
  .model-field-body{padding:24px 22px 28px}
}

/* ── Why one bit — sell the outcome through a same-memory comparison ───── */

@keyframes capacity-load{0%,12%{transform:scaleX(0)}32%,100%{transform:scaleX(1)}}

@media(max-width:1000px){
}
@media(max-width:700px){
}
@media(prefers-reduced-motion:reduce){
}

/* ── Who we serve — a ledger of industries with hover image reveals ───────
   Full-width hairline rows in the news-card register: index, industry name
   in display type, one line of copy, and a floating greyscale image that
   appears over the row's right side on hover. Touch and narrow viewports
   drop the reveal and stack the copy under the name.                      */
.serve{padding:clamp(90px,12vw,100px) var(--pad) 0;background:var(--paper)}
.serve-kicker{font-size:10px;letter-spacing:.24em;color:var(--muted)}
@media(hover:hover){
}
@media(max-width:900px){
}

/* ── Who we serve, GTM revision: beachhead panel + expansion ledger ─────── */
@media(max-width:900px){
  .serve-foot{flex-direction:column;align-items:flex-start}
}

/* ── Drift field ──────────────────────────────────────────────────────────
   hero-drift.js mounts its canvas inside .hero-v2, which is relative and
   overflow:hidden — the field is the hero's own backdrop and is clipped at
   its bottom edge. The sections below keep their paper backgrounds.       */
main{position:relative}

/* ── Who we serve, outage revision: the argument as a working machine ─────
   The ink panel's left half is a live schematic (js/serve-outage.js): the
   link to cloud AI severs, its heartbeat flatlines, the on-device model's
   never does. Copy and partner meta sit to the right; the expansion ledger
   collapses to one hairline strip of constraints.                         */
@media(max-width:900px){
}


/* ── Who we serve, direct answer: three partner columns + market rail ────   clamp(22px,5.6vw,92px);  */
.serve-lede{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(28px,4vw,80px);align-items:end;margin-bottom:clamp(36px,4.6vw,58px)}
.serve-lede h2{margin:0;font-family:var(--display);font-size:clamp(22px,4.1vw,68px);line-height:.92;font-weight:500;letter-spacing:-.032em;white-space:nowrap;text-wrap:nowrap}
.serve-lede p{margin:0 0 8px;max-width:40ch;font-size:11.5px;line-height:1.75;letter-spacing:.035em;color:rgba(14,14,14,.68);text-wrap:pretty}
.who-grid{display:grid;grid-template-columns:repeat(3,1fr);border-top:1px solid var(--ink)}
.who-grid article{padding:clamp(22px,2.6vw,34px) clamp(18px,2.2vw,30px) clamp(26px,3vw,40px) 0;min-height:clamp(190px,19vw,270px);display:flex;flex-direction:column}
.who-grid article+article{border-left:1px solid var(--rule);padding-left:clamp(18px,2.2vw,30px)}
.who-grid span{font-size:9.5px;letter-spacing:.2em;color:var(--muted)}
.who-grid h3{margin:auto 0 12px;font-family:var(--display);font-size:clamp(24px,2.5vw,40px);font-weight:500;letter-spacing:-.025em;line-height:.95}
.who-grid p{margin:0;max-width:40ch;font-size:11px;line-height:1.7;letter-spacing:.035em;color:rgba(14,14,14,.66);text-wrap:pretty}
.serve-cta{display:flex;justify-content:flex-start;padding:clamp(30px,3.8vw,48px) 0 clamp(30px,3.8vw,48px)}
@media(max-width:900px){
  .serve-lede{grid-template-columns:1fr;gap:18px}
  .who-grid{grid-template-columns:1fr}
  .who-grid article{min-height:0;border-left:0;padding-left:0}
  .who-grid article+article{border-top:1px solid var(--rule)}
}

/* Who-grid, illustrated: hairline SVG pictograms, one line of copy each */
.who-grid article{min-height:0}
.who-grid h3{margin:0 0 10px}
.who-grid p{max-width:34ch}

/* Who-grid, photographic: greyscale panes in the news-card treatment */
.who-photo{margin:0 0 clamp(18px,2.2vw,28px);aspect-ratio:4/3;overflow:hidden;border:1px solid var(--rule);background:#EFEEEC}
.who-photo img{width:100%;height:100%;object-fit:cover;filter:grayscale(1) contrast(1.06);transition:transform .6s cubic-bezier(.16,1,.3,1)}
.who-grid article:hover .who-photo img{transform:scale(1.035)}

/* Who-grid, equalised: identical columns separated by gap, not dividers,
   so all three photo panes render at exactly the same size. */
.who-grid{gap:clamp(22px,3vw,44px)}
.who-grid article{padding:clamp(22px,2.6vw,34px) 0 clamp(26px,3vw,40px)}
.who-grid article+article{border-left:0;padding-left:0}

/* ── Research band — the proof: three published numbers and a link ────────
   Tinted paper so it reads as its own beat between who-we-serve and the
   licensing close. Numbers straight from the published SPQ report.         clamp(34px,4.6vw,76px);  clamp(22px,5.6vw,92px);*/
.research-band{padding:clamp(80px,10vw,100px) var(--pad);background:var(--paper);border-top:1px solid var(--hair);border-bottom:1px solid var(--hair)}
.rb-kicker{font-size:10px;letter-spacing:.24em;color:var(--muted)}
.research-band h2{margin:20px 0 clamp(40px,5vw,64px);max-width:1600px;font-family:var(--display);font-size:clamp(22px,4.1vw,68px); line-height:.94;font-weight:500;letter-spacing:-.032em;text-wrap:balance}
.rb-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(22px,3vw,44px)}
.rb-stats article{border-top:1px solid var(--ink);padding-top:clamp(20px,2.4vw,30px)}
.rb-stats strong{display:block;font-family:var(--display);font-size:clamp(52px,6.2vw,104px);font-weight:500;letter-spacing:-.04em;line-height:.9;font-variant-numeric:tabular-nums}
.rb-stats strong i{font-style:normal;font-size:.45em;letter-spacing:0}
.rb-stats article>span{display:block;margin-top:13px;font-size:9.5px;letter-spacing:.18em;color:var(--muted)}
.rb-stats p{margin:10px 0 0;max-width:34ch;font-size:11px;line-height:1.65;letter-spacing:.035em;color:rgba(14,14,14,.62);text-wrap:pretty}
.rb-link{display:inline-flex;align-items:center;gap:12px;margin-top:clamp(36px,4.4vw,56px);font-size:10px;font-weight:500;letter-spacing:.2em;border-bottom:1px solid var(--rule);padding-bottom:7px;transition:border-color .25s}
.rb-link:hover{border-color:var(--ink)}
.rb-link b{font-size:14px;font-weight:400}
@media(max-width:900px){.rb-stats{grid-template-columns:1fr;gap:26px}}

/* Research band, pre-publication state */
.rb-note{margin:0;max-width:56ch;font-size:11.5px;line-height:1.75;letter-spacing:.035em;color:rgba(14,14,14,.68);text-wrap:pretty}
.rb-status{display:inline-flex;align-items:center;gap:10px;margin-top:clamp(26px,3vw,40px);font-size:9.5px;letter-spacing:.18em;color:var(--muted)}
.rb-status i{width:7px;height:7px;border:1px solid var(--ink);border-radius:50%}
.research-band h2{margin-bottom:clamp(22px,2.6vw,34px)}
.rb-link{display:inline-flex;margin-top:clamp(30px,3.6vw,48px)}

/* ── Advantages of 1-bit models — four vertical bar charts. Ink = 1-bit
   result, grey = conventional comparison; every bar carries its value
   above and its name below, so grey/ink is reinforcement, not the only
   carrier of meaning. A bar with an inline `bottom` offset is a min–max
   range band, not a zero-anchored bar.                                  */
.adv-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(30px,3.6vw,54px) clamp(24px,2.6vw,44px);margin-top:clamp(40px,5vw,64px)}
/* The ink why-card rides above the ruled card, so the hairline that opens
   each column lives on the kicker, not the article. */
.adv-kicker{display:block;border-top:1px solid var(--ink);padding-top:clamp(18px,2.2vw,26px);font-size:9.5px;letter-spacing:.18em;color:var(--muted)}
.adv-card>strong{display:block;margin-top:14px;font-family:var(--display);font-size:clamp(34px,3.4vw,56px);font-weight:500;letter-spacing:-.035em;line-height:.9;font-variant-numeric:tabular-nums}
.adv-card>strong i{font-style:normal;font-size:.5em;letter-spacing:0}
.adv-line{margin:10px 0 0;max-width:46ch;font-size:11px;line-height:1.65;letter-spacing:.035em;color:rgba(14,14,14,.62);text-wrap:pretty}
/* Ink why-card atop each column: the research page's "Why?" reasons,
   restated above the graph that proves each one. */
.adv-why{margin:0 0 clamp(18px,2.2vw,26px);padding:clamp(14px,1.6vw,20px) clamp(15px,1.8vw,22px);background:var(--ink);color:var(--paper)}
.adv-why h4{margin:0;font-family:var(--display);font-size:clamp(15px,1.35vw,20px);font-weight:500;letter-spacing:-.015em}
.adv-why p{margin:8px 0 0;font-size:10px;line-height:1.68;letter-spacing:.03em;color:rgba(251,251,250,.72);text-wrap:pretty}
.adv-chart{margin-top:clamp(22px,2.6vw,34px)}
.adv-bars{position:relative;display:flex;justify-content:center;height:150px;margin:26px auto 44px;border-bottom:1px solid rgba(14,14,14,.4)}
.adv-col{position:relative;flex:0 1 76px;height:100%}
.adv-col i{position:absolute;bottom:0;left:50%;transform:translateX(-50%);width:min(52px,68%);background:rgba(14,14,14,.28)}
.adv-col b{position:absolute;left:50%;transform:translateX(-50%);font-weight:400;font-size:10px;letter-spacing:.04em;font-variant-numeric:tabular-nums;white-space:nowrap;color:var(--muted)}
.adv-col span{position:absolute;top:calc(100% + 10px);left:50%;transform:translateX(-50%);width:110px;text-align:center;font-size:8.5px;letter-spacing:.1em;line-height:1.6;color:var(--muted)}
.adv-col--hero i{background:var(--ink)}
.adv-col--hero b{font-weight:500;font-size:11px;color:var(--ink)}
.adv-col--hero span{color:var(--ink)}
.adv-mark{position:absolute;left:0;right:0;height:1px;background:rgba(14,14,14,.45)}
.adv-axisnote{margin:0;font-size:9px;letter-spacing:.08em;text-align:center;color:var(--muted)}
.adv-foot{margin:clamp(30px,3.6vw,48px) 0 0;max-width:74ch;font-size:9.5px;line-height:1.7;letter-spacing:.04em;color:var(--muted);text-wrap:pretty}
@media(max-width:1100px){.adv-grid{grid-template-columns:1fr 1fr}}
@media(max-width:640px){.adv-grid{grid-template-columns:1fr;gap:36px}}

/* Footer subscribe */

/* (The paper scrims that used to lift these headlines clear of the drift
   field are gone with it — the field no longer reaches past the hero.) */
