/* ============================================================
   Granule Labs — shared stylesheet.

   Extracted from index.html and 404.html, which were ~70%
   byte-identical. Page-specific rules stay inline in each page.

   PALETTES — swap by changing data-theme on <html>.
   Append ?themes to any URL to get an on-page switcher.
   ============================================================ */

/* A — SODIUM. Pure black, sodium-vapor amber. Night operations,
   monitoring, the observability beachhead. Furthest from magenta. */
[data-theme="sodium"]{
  --bg:#08090A; --lift:#111315; --rule:#23272B;
  --text:#F2F4F5; --muted:#8A9299;
  --accent:#FFB020; --accent-dim:#5C4210; --accent-2:#4DD9C0;
}

/* B — ULTRAVIOLET. Black with a cold violet and ice highlight.
   Reads AI/compute. Closest of the four to Blank Metal's register. */
[data-theme="uv"]{
  --bg:#07070C; --lift:#101018; --rule:#22222F;
  --text:#F0F0F5; --muted:#8A8AA0;
  --accent:#7C5CFF; --accent-dim:#2C2160; --accent-2:#5EE6FF;
}

/* C — HALIDE. Black with signal cyan. Cold, instrument-panel,
   engineering-first. Most "infrastructure vendor" of the set. */
[data-theme="halide"]{
  --bg:#06090B; --lift:#0E1417; --rule:#1E282D;
  --text:#EDF3F5; --muted:#7E8F97;
  --accent:#22D3EE; --accent-dim:#0B4854; --accent-2:#FFC24B;
}

/* D — EMBER. Black with a deep molten orange-red. The edgiest,
   and the one most likely to feel aggressive to an enterprise buyer. */
[data-theme="ember"]{
  --bg:#0A0807; --lift:#151110; --rule:#2A2220;
  --text:#F5F0ED; --muted:#998A84;
  --accent:#FF5F2E; --accent-dim:#5E2110; --accent-2:#F2C078;
}

/* Fallback: a page shipped without data-theme, or with a typo, used to
   render completely unstyled. It now falls back to sodium. */
:root{
  --bg:#08090A; --lift:#111315; --rule:#23272B;
  --text:#F2F4F5; --muted:#8A9299;
  --accent:#FFB020; --accent-dim:#5C4210; --accent-2:#4DD9C0;
  --measure:60ch;
}

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

/* Guard against stray horizontal scroll. Must be `clip`, not `hidden`:
   overflow-x:hidden makes the element a scroll container, which breaks
   position:sticky on the top bar. `clip` does not. */
html{ overflow-x:clip; }

body{
  background:var(--bg);
  color:var(--text);
  font-family:'Archivo', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size:17px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  min-height:100svh;
  display:flex;
  flex-direction:column;
}

.wrap{
  width:100%;
  max-width:980px;
  margin:0 auto;
  padding-left:max(24px, env(safe-area-inset-left));
  padding-right:max(24px, env(safe-area-inset-right));
}

/* ---------- top bar ---------- */
.topbar{
  position:sticky;
  top:0;
  z-index:50;
  background:var(--bg);
  padding-top:clamp(22px,4vw,32px);
  padding-bottom:clamp(18px,3vw,26px);
  flex-shrink:0;
  border-bottom:1px solid var(--rule);
}
.topbar .wrap{
  display:flex;
  flex-wrap:wrap;
  align-items:baseline;
  justify-content:space-between;
  gap:14px 32px;
}

/* Larger than the placeholder's 12px — this is the site's logo now. */
.wordmark{
  font-family:'IBM Plex Mono', monospace;
  font-size:clamp(17px,3.9vw,21px);
  font-weight:500;
  letter-spacing:0.2em;
  text-transform:uppercase;
  margin:0;
  color:var(--text);
  text-decoration:none;
  display:inline-block;
  white-space:nowrap;
}
.wordmark span{ color:var(--accent); }
.wordmark:focus-visible{ outline:2px solid var(--accent); outline-offset:4px; border-radius:2px; }

.nav{
  display:flex;
  flex-wrap:wrap;
  gap:6px 22px;
  font-family:'IBM Plex Mono', monospace;
  font-size:12px;
  letter-spacing:0.08em;
  text-transform:uppercase;
}
.nav a{
  color:var(--muted);
  text-decoration:none;
  padding-bottom:2px;
  border-bottom:1px solid transparent;
  transition:color .18s ease, border-color .18s ease;
}
.nav a:hover{ color:var(--text); }
.nav a[aria-current="page"]{ color:var(--accent); border-bottom-color:var(--accent); }
.nav a:focus-visible{ outline:2px solid var(--accent); outline-offset:4px; border-radius:2px; }

@media (max-width: 700px){
  .topbar{
    padding-top:14px;
    padding-bottom:10px;
  }
  .topbar .wrap{
    flex-direction:column;
    align-items:stretch;
    gap:9px;
  }
  .nav{
    flex-wrap:nowrap;
    /* Without min-width:0 a flex item will not shrink below its content
       width, so overflow-x:auto never engages and the nav pushes the
       page sideways instead of scrolling. */
    min-width:0;
    max-width:100%;
    overflow-x:auto;
    overscroll-behavior-x:contain;
    -webkit-overflow-scrolling:touch;
    scrollbar-width:none;
    font-size:11px;
    /* Grouping is a ratio, not a gap. letter-spacing inflates the spaces
       inside each item too, so the space between "WHAT" and "WE" ended up
       close to the space between whole items. Tighten one, widen the other. */
    gap:0 24px;
    padding-bottom:3px;
    /* Fade the trailing edge so an off-screen item reads as scrollable
       rather than missing. Removed once there is nothing left to reveal —
       otherwise it dims the last item, which is the current page. */
    -webkit-mask-image:linear-gradient(to right, #000 88%, transparent 100%);
    mask-image:linear-gradient(to right, #000 88%, transparent 100%);
  }
  .nav.at-end{
    -webkit-mask-image:none;
    mask-image:none;
  }
  .nav::-webkit-scrollbar{ display:none; }
  .nav a{ white-space:nowrap; word-spacing:-0.18em; }
}

/* ---------- hero ---------- */
.hero{
  flex:1 0 auto;
  display:flex;
  flex-direction:column;
  justify-content:center;
  padding:clamp(40px,9vw,84px) 0 clamp(36px,7vw,64px);
}

/* Interior pages: content flows top-down rather than centring. */
.page{
  flex:1 0 auto;
  padding:clamp(38px,7vw,68px) 0 clamp(30px,6vw,56px);
}

h1{
  font-size:clamp(2.15rem, 8.2vw, 4.3rem);
  line-height:1.02;
  letter-spacing:-0.038em;
  font-weight:600;
  margin:0 0 clamp(20px,3.4vw,30px);
  max-width:14ch;
}
h1 em{ font-style:normal; color:var(--accent); }

/* Interior headline: same face, smaller, allowed to run wider. */
.page h1{ font-size:clamp(1.9rem, 6vw, 3.1rem); max-width:20ch; }

h2{
  font-size:clamp(1.35rem, 3.4vw, 1.8rem);
  line-height:1.15;
  letter-spacing:-0.024em;
  font-weight:600;
  margin:0 0 clamp(14px,2.4vw,20px);
  /* 22ch was orphaning short headings — "…for AI." fell to its own line.
     Wide enough for a ~34-character heading to sit on one, and balance
     splits the longer ones evenly instead of leaving a stub. */
  max-width:34ch;
  text-wrap:balance;
}
h2 em{ font-style:normal; color:var(--accent); }

h3{
  font-size:1.06rem;
  line-height:1.3;
  font-weight:600;
  letter-spacing:-0.012em;
  margin:0 0 8px;
}

.eyebrow{
  font-family:'IBM Plex Mono', monospace;
  font-size:12px;
  font-weight:500;
  letter-spacing:0.2em;
  text-transform:uppercase;
  color:var(--accent);
  margin:0 0 clamp(14px,2.4vw,20px);
}

.lede{
  font-size:clamp(1rem, 2vw, 1.2rem);
  color:var(--muted);
  max-width:var(--measure);
  margin:0 0 clamp(26px,4.4vw,38px);
  text-wrap:pretty;
}
.lede strong{ color:var(--text); font-weight:500; }

p{ text-wrap:pretty; }

/* ---------- sections ---------- */
.section{
  padding-top:clamp(38px,6.5vw,64px);
  margin-top:clamp(38px,6.5vw,64px);
  border-top:1px solid var(--rule);
}

.kicker{
  font-family:'IBM Plex Mono', monospace;
  font-size:11.5px;
  font-weight:500;
  letter-spacing:0.2em;
  text-transform:uppercase;
  color:var(--muted);
  margin:0 0 clamp(16px,2.6vw,22px);
}

.body{
  color:var(--muted);
  max-width:var(--measure);
  margin:0 0 18px;
}
.body strong{ color:var(--text); font-weight:500; }
.body:last-child{ margin-bottom:0; }

/* ---------- grids and cards ---------- */
.grid{
  display:grid;
  gap:clamp(18px,3vw,26px);
  grid-template-columns:repeat(auto-fit, minmax(240px, 1fr));
}
.grid-2{ grid-template-columns:repeat(auto-fit, minmax(300px, 1fr)); }

.card{
  border:1px solid var(--rule);
  border-radius:6px;
  background:var(--lift);
  padding:clamp(18px,2.6vw,24px);
}
.card p{ color:var(--muted); margin:0; font-size:0.95rem; }
.card .num{
  font-family:'IBM Plex Mono', monospace;
  font-size:11px;
  letter-spacing:0.16em;
  color:var(--accent-2);
  display:block;
  margin-bottom:10px;
}

/* Offering cards answer three short questions instead of running a
   paragraph. Two across on desktop, one on mobile (.grid-2 handles the
   collapse — the minmax floor is what wraps it, no media query needed). */
.offer{ display:flex; flex-direction:column; }
.offer h3{ margin-bottom:clamp(14px,2.2vw,18px); }

.qa{ margin:0 0 clamp(14px,2.2vw,18px); }
.qa:last-child{ margin-bottom:0; }
.qa .q{
  font-family:'IBM Plex Mono', monospace;
  font-size:10.5px;
  font-weight:500;
  letter-spacing:0.16em;
  text-transform:uppercase;
  color:var(--accent-2);
  margin:0 0 5px;
}
.qa p{ color:var(--muted); margin:0; font-size:0.95rem; }

/* "What you get" is the answer people actually scan for, so it gets an
   inset panel, an accent rule, and full-brightness text. Sits on --bg
   inside a --lift card, so it reads as recessed rather than bolted on. */
.qa.get{
  margin-top:auto;
  padding:14px 16px;
  background:var(--bg);
  border:1px solid var(--rule);
  border-left:2px solid var(--accent);
  border-radius:0 5px 5px 0;
}
.qa.get .q{ color:var(--accent); }
.qa.get p{ color:var(--text); }

/* Offerings and pillars: a rule on the left, no box. Denser, more
   technical, and it keeps five items from reading as a pricing table. */
.item{
  border-left:2px solid var(--rule);
  padding:2px 0 2px 20px;
  margin:0 0 clamp(26px,4vw,36px);
  max-width:var(--measure);
  transition:border-color .2s ease;
}
.item:last-child{ margin-bottom:0; }
.item:hover{ border-left-color:var(--accent); }
.item p{ color:var(--muted); margin:0 0 12px; }
.item p:last-child{ margin-bottom:0; }
.item .tag{
  font-family:'IBM Plex Mono', monospace;
  font-size:11px;
  letter-spacing:0.14em;
  text-transform:uppercase;
  color:var(--accent-2);
  display:block;
  margin-bottom:9px;
}
.item .quiet{ color:var(--muted); opacity:.78; font-size:0.92rem; }

/* ---------- people ---------- */
.people{
  display:grid;
  gap:clamp(20px,3.4vw,30px);
  /* auto-FILL, not auto-fit: empty tracks are kept, so a section holding
     one person still sits in a quarter-width column and its photo matches
     a full row. Sized for four across; more just wrap. */
  grid-template-columns:repeat(auto-fill, minmax(210px, 1fr));
}
.person .shot{
  display:block;
  width:100%;
  max-width:260px;
  /* The width/height attributes on the img reserve layout space, but they
     also set CSS height, which beats aspect-ratio. height:auto hands it back. */
  height:auto;
  aspect-ratio:1;
  object-fit:cover;
  border-radius:6px;
  border:1px solid var(--rule);
  margin:0 0 16px;
  /* Photos are the only colour on the site; settle them into the palette
     so a mix of studio and phone shots reads as one set. */
  filter:grayscale(1) contrast(1.04) brightness(.94);
  transition:filter .35s ease;
}
.person:hover .shot{ filter:grayscale(0) contrast(1) brightness(1); }
.person h3{ margin-bottom:3px; }
.person .role{
  font-family:'IBM Plex Mono', monospace;
  font-size:11px;
  letter-spacing:0.14em;
  text-transform:uppercase;
  color:var(--accent);
  margin:0 0 10px;
}
.person p{ color:var(--muted); font-size:0.95rem; margin:0; }
.person .li{
  display:inline-flex;
  align-items:center;
  gap:7px;
  font-family:'IBM Plex Mono', monospace;
  font-size:11px;
  letter-spacing:0.08em;
  color:var(--muted);
  text-decoration:none;
  transition:color .18s ease;
}
.person .li svg{ fill:currentColor; }
.person .li:hover{ color:var(--accent); }
.person .li:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; border-radius:2px; }

@media (prefers-reduced-motion: reduce){
  .person .shot{ transition:none; }
}

/* ---------- plain lists ---------- */
.list{
  list-style:none;
  padding:0;
  margin:0;
  max-width:var(--measure);
}
.list li{
  color:var(--muted);
  padding:14px 0;
  border-bottom:1px solid var(--rule);
}
.list li:first-child{ border-top:1px solid var(--rule); }
.list li b{ color:var(--text); font-weight:500; }

/* Institutional partners — logo above the name. */
.partners{
  display:grid;
  grid-template-columns:repeat(auto-fit, minmax(210px, 1fr));
  gap:clamp(14px,2.4vw,20px);
  list-style:none;
  padding:0;
  margin:clamp(20px,3.2vw,28px) 0 0;
  max-width:620px;
}
.partners li{ display:flex; }
.partners a{
  flex:1 1 auto;
  border:1px solid var(--rule);
  border-radius:8px;
  background:var(--lift);
  padding:clamp(18px,2.6vw,24px);
  display:flex;
  flex-direction:column;
  gap:18px;
  align-items:flex-start;
  justify-content:space-between;
  min-height:132px;
  text-decoration:none;
  transition:border-color .18s ease, background-color .18s ease;
}
.partners a:hover{ border-color:var(--muted); background:var(--bg); }
.partners a:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; }
.plogo{
  height:42px;
  width:auto;
  max-width:100%;
  opacity:.82;
  transition:opacity .18s ease;
}
.partners a:hover .plogo{ opacity:1; }
/* Stand-in until the real asset arrives. */
.pmark{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:42px;
  height:42px;
  border:1px solid var(--rule);
  border-radius:4px;
  font-family:'Archivo', sans-serif;
  font-size:21px;
  font-weight:600;
  color:var(--muted);
}
.pname{
  font-family:'IBM Plex Mono', monospace;
  font-size:11px;
  letter-spacing:0.14em;
  text-transform:uppercase;
  color:var(--muted);
  transition:color .18s ease;
}
.partners a:hover .pname{ color:var(--accent); }

/* Advisors / other name chips — names, not logos. */
.names{
  display:flex;
  flex-wrap:wrap;
  gap:10px 14px;
  padding:0;
  margin:0;
  list-style:none;
}
.names li{
  font-family:'IBM Plex Mono', monospace;
  font-size:12.5px;
  letter-spacing:0.06em;
  color:var(--text);
  border:1px solid var(--rule);
  border-radius:5px;
  padding:9px 14px;
  background:var(--lift);
}

/* Anchored sections must clear the sticky top bar, which is 85px on
   mobile and 93px on desktop — otherwise a jump link lands underneath it. */
[id]{ scroll-margin-top:clamp(100px,11vw,118px); }
html{ scroll-behavior:smooth; }
@media (prefers-reduced-motion: reduce){ html{ scroll-behavior:auto; } }

/* Technology attribution row.
   NOT a partner badge. Granule Labs is not a ClickHouse partner — the
   vault lists that as a Phase 2 to-do — so nothing here may read as an
   endorsement or an official mark. */
.techrow{
  display:flex;
  flex-wrap:wrap;
  gap:12px 14px;
  margin-top:clamp(22px,3.4vw,30px);
}
.techbadge{
  display:inline-flex;
  align-items:center;
  gap:10px;
  padding:10px 15px;
  border:1px solid var(--rule);
  border-radius:6px;
  background:var(--lift);
  font-family:'IBM Plex Mono', monospace;
  font-size:12px;
  letter-spacing:0.04em;
  color:var(--muted);
  text-decoration:none;
  transition:border-color .18s ease, color .18s ease;
}
.techbadge:hover{ border-color:var(--accent); color:var(--text); }
.techbadge:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; }
.techbadge b{ color:var(--text); font-weight:500; }
.techbadge svg{ flex:0 0 auto; display:block; }

/* ---------- signature: the granule strip ---------- */
.granules{ margin:0 0 clamp(28px,5vw,44px); }

.strip{
  display:flex;
  gap:2px;
  align-items:flex-end;
  height:clamp(40px,9vw,60px);
  width:100%;
}

.g{
  --i:0;                     /* cursor proximity, 0..1 — set by app.js */
  flex:1 1 0;
  min-width:0;
  height:38%;
  background:var(--rule);
  border-radius:1px;
  transition:height .55s cubic-bezier(.2,.75,.3,1), background-color .55s ease;
}
.g.read{
  height:100%;
  background:var(--accent);
  box-shadow:0 0 12px -2px var(--accent);
}

/* Cursor mode: granules rise and warm toward the pointer. Short
   transition so the strip tracks rather than lags. */
.strip[data-strip-mode="cursor"] .g{
  height:calc(38% + (var(--i) * 62%));
  background-color:color-mix(in srgb, var(--rule), var(--accent) calc(var(--i) * 100%));
  transition:height .22s ease-out, background-color .22s ease-out;
}

/* ============================================================
   Column grid — what each layer of the architecture stops reading.

   Three stages against the same query. Deliberately slow, and
   replayable, because the whole point is that you can watch it.
   ============================================================ */
.scanviz{
  border:1px solid var(--rule);
  border-radius:8px;
  background:var(--lift);
  padding:clamp(16px,2.6vw,22px);
  margin-top:clamp(24px,4vw,34px);
}

.scanviz .q{
  font-family:'IBM Plex Mono', monospace;
  font-size:11px; letter-spacing:0.14em; text-transform:uppercase;
  color:var(--muted); margin:0 0 10px;
}
.scanviz .query{
  font-family:'IBM Plex Mono', monospace;
  font-size:clamp(11px,2.4vw,12.5px);
  color:var(--muted);
  background:var(--bg);
  border:1px solid var(--rule);
  border-radius:5px;
  padding:9px 12px;
  margin:0 0 16px;
  overflow-x:auto;
  white-space:nowrap;
}
.scanviz .query b{ color:var(--accent-2); font-weight:500; }

/* Three toggles rather than a timed replay — the point is to compare
   the architectures, which means the reader controls the comparison. */
.archtabs{
  display:flex;
  flex-wrap:wrap;
  gap:6px;
  margin:0 0 16px;
}
.archtab{
  font:inherit;
  font-family:'IBM Plex Mono', monospace;
  font-size:11.5px;
  letter-spacing:0.05em;
  cursor:pointer;
  padding:9px 13px;
  border-radius:5px;
  background:transparent;
  color:var(--muted);
  border:1px solid var(--rule);
  transition:color .18s ease, border-color .18s ease, background-color .18s ease;
}
.archtab:hover{ color:var(--text); border-color:var(--muted); }
.archtab[aria-pressed="true"]{
  color:var(--bg);
  background:var(--accent);
  border-color:var(--accent);
}
.archtab:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; }

.colgrid{
  display:grid;
  gap:2px;
  margin:0 0 14px;
  max-width:420px;              /* smaller — it is a diagram, not a hero */
}
.cell{
  aspect-ratio:1;
  border-radius:1.5px;
  background:var(--rule);
  opacity:.45;
  transition:background-color .3s ease, opacity .3s ease;
}
.cell.hit{ background:var(--muted); opacity:1; }
.cell.keep{ background:var(--accent); opacity:1; }

/* Grid on the left, the number it produces on the right. */
.scanbody{
  display:grid;
  gap:clamp(18px,3vw,32px);
  grid-template-columns:repeat(auto-fit, minmax(240px, 1fr));
  align-items:center;
}
.readnum{
  font-family:'IBM Plex Mono', monospace;
  font-size:clamp(1.9rem,5.5vw,2.9rem);
  font-weight:500;
  letter-spacing:-0.03em;
  color:var(--accent);
  margin:0;
  line-height:1;
  transition:color .3s ease;
}
.readcap{
  font-family:'IBM Plex Mono', monospace;
  font-size:11px; letter-spacing:0.14em; text-transform:uppercase;
  color:var(--muted); margin:6px 0 0;
}
.readnote{ color:var(--muted); font-size:0.92rem; margin:14px 0 0; max-width:34ch; }
.readnote b{ color:var(--text); font-weight:500; }

/* ============================================================
   Org breakdown — the same delivery, two shapes.
   ============================================================ */
.org{
  display:grid;
  gap:clamp(16px,2.6vw,26px);
  grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);
  margin-top:clamp(22px,3.4vw,30px);
}
.vs{
  align-self:center;
  font-family:'IBM Plex Mono', monospace;
  font-size:13px;
  letter-spacing:0.14em;
  text-transform:uppercase;
  color:var(--muted);
  margin:0;
}
@media (max-width: 780px){
  .org{ grid-template-columns:1fr; }
  .vs{ justify-self:center; }
}
.orgcol{
  border:1px solid var(--rule);
  border-radius:6px;          /* match .card — 8px read as a heavier, separate device */
  background:var(--lift);
  padding:clamp(16px,2.4vw,20px);
}
.orgcol.now{ border-color:var(--accent-dim); }

.orgtotal{
  font-family:'IBM Plex Mono', monospace;
  font-size:clamp(1.6rem,4.4vw,2.1rem);
  font-weight:500;
  letter-spacing:-0.02em;
  margin:0 0 2px;
  color:var(--text);
}
.orgcol.now .orgtotal{ color:var(--accent); }
.orgsub{
  font-family:'IBM Plex Mono', monospace;
  font-size:11px; letter-spacing:0.1em; text-transform:uppercase;
  color:var(--muted); margin:0 0 16px;
}

.role{
  display:flex; align-items:center; gap:10px;
  padding:7px 0;
  border-top:1px solid var(--rule);
  font-size:0.9rem;
  color:var(--muted);
}
.role:first-of-type{ border-top:0; }
.role .name{ flex:1 1 auto; }
.role .pips{ display:flex; gap:3px; flex:0 0 auto; }
.pip{ width:7px; height:7px; border-radius:50%; background:var(--muted); opacity:.55; }
.orgcol.now .pip{ background:var(--accent); opacity:1; }
.role.ai .name{ color:var(--accent-2); }

/* ============================================================
   Stats table + the names that run on it.
   ============================================================ */
.stats{
  width:100%;
  border-collapse:collapse;
  margin-top:clamp(20px,3.2vw,28px);
  font-size:0.95rem;
}
.stats th,
.stats td{
  text-align:left;
  padding:14px 16px 14px 0;
  border-top:1px solid var(--rule);
  vertical-align:baseline;
}
.stats tr:first-child th,
.stats tr:first-child td{ border-top:0; }
.stats th{
  font-family:'IBM Plex Mono', monospace;
  font-size:11px; letter-spacing:0.14em; text-transform:uppercase;
  font-weight:500;
  color:var(--muted);
  white-space:nowrap;
  width:1%;
  padding-right:24px;
}
.stats .big{
  font-family:'IBM Plex Mono', monospace;
  font-size:clamp(1.05rem,2.6vw,1.3rem);
  color:var(--accent);
  display:block;
  margin-bottom:3px;
}
.stats td span{ color:var(--muted); }

/* Stats on the left, who runs on it on the right. */
/* Equal halves, equal height — one horizontal band, stacked on mobile. */
.statsrow{
  display:grid;
  gap:clamp(20px,3.4vw,34px);
  grid-template-columns:1fr 1fr;
  align-items:stretch;
  margin-top:clamp(20px,3.2vw,28px);
}
@media (max-width: 760px){
  .statsrow{ grid-template-columns:1fr; }
}
.statsrow .stats{ margin-top:0; }

.logopanel{
  border:1px solid var(--rule);
  border-radius:8px;
  background:var(--lift);
  padding:clamp(16px,2.4vw,20px);
  display:flex;
  flex-direction:column;
}
.logopanel .q{
  font-family:'IBM Plex Mono', monospace;
  font-size:11px; letter-spacing:0.14em; text-transform:uppercase;
  color:var(--muted); margin:0 0 14px;
}

.users{
  display:grid;
  grid-template-columns:repeat(2, 1fr);
  gap:1px;
  padding:0; margin:0; list-style:none;
  background:var(--rule);
  border:1px solid var(--rule);
  border-radius:6px;
  overflow:hidden;
}
.users{ flex:1 1 auto; }
.users li{ display:flex; }
.users a{
  flex:1 1 auto;
  padding:16px 12px;
  background:var(--lift);
  display:flex;
  align-items:center;
  justify-content:center;
  min-height:62px;
  text-decoration:none;
  transition:background-color .18s ease;
}
.users a:hover{ background:var(--bg); }
.users a:focus-visible{ outline:2px solid var(--accent); outline-offset:-2px; }
/* Monochrome, inheriting --muted. Rendering every mark in one weight is
   both more restrained than a colour logo wall and less likely to read
   as a client roster. */
.users svg{
  width:30px;
  height:30px;
  fill:var(--muted);
  opacity:.85;
  transition:fill .18s ease, opacity .18s ease;
}
.users a:hover svg{ fill:var(--text); opacity:1; }
.logopanel .caveat{
  font-size:0.84rem;
  color:var(--muted);
  margin:14px 0 0;
  line-height:1.5;
}

.footnote{
  color:var(--muted);
  font-size:0.78rem;
  line-height:1.5;
  opacity:.8;
  max-width:56ch;
  margin:10px 0 0;
}

/* In-page jump links, for a page long enough to need them. */
.jumps{
  display:flex;
  flex-wrap:wrap;
  gap:8px;
  margin:clamp(18px,3vw,26px) 0 0;
  padding:0;
  list-style:none;
}
.jump{
  display:inline-flex;
  align-items:baseline;
  font-family:'IBM Plex Mono', monospace;
  font-size:11.5px;
  letter-spacing:0.06em;
  color:var(--muted);
  text-decoration:none;
  border:1px solid var(--rule);
  border-radius:5px;
  padding:9px 13px;
  background:var(--lift);
  transition:color .18s ease, border-color .18s ease;
}
.jump:hover{ color:var(--text); border-color:var(--muted); }
.jump:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; }
.jump b{ color:var(--accent-2); font-weight:500; margin-right:8px; }

/* A headline figure inside a card, with its source underneath.
   Scoped to .card so it out-specifies `.card p`, which sets 0.95rem. */
.card .figure, .figure{
  font-family:'IBM Plex Mono', monospace;
  font-size:clamp(1.35rem,3.2vw,1.8rem);
  font-weight:500;
  letter-spacing:-0.02em;
  color:var(--accent);
  margin:0 0 10px;
  line-height:1.1;
}
.src{
  font-family:'IBM Plex Mono', monospace;
  font-size:10.5px;
  letter-spacing:0.08em;
  color:var(--muted);
  text-decoration:none;
  border-bottom:1px solid var(--rule);
  display:inline-block;
  margin-top:14px;
  padding-bottom:1px;
  transition:color .18s ease, border-color .18s ease;
}
.src:hover{ color:var(--accent); border-color:var(--accent); }
.src:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; }

/* ============================================================
   Pillars — category, claim, plain fact, then the punch set apart.
   Separating the fact from the argument lets the block be read three
   ways: headlines only, headlines plus rules, or all of it.
   ============================================================ */
.pillars{
  display:grid;
  column-gap:clamp(28px,4.5vw,44px);
  row-gap:clamp(34px,5vw,52px);
  /* 340px floor puts four pillars in a 2x2 rather than 3 + an orphan. */
  grid-template-columns:repeat(auto-fit, minmax(340px, 1fr));
  /* Four rows — category, claim, fact, punch — so each pillar can align
     to them rather than stacking independently. Without this the blocks
     staircase down to the right as line counts differ. */
  grid-template-rows:auto auto auto auto;
  /* No margin-top. The pillars are the first in-flow thing in their section, so this
     stacked on the section's own 64px padding and produced 100px of dead space where
     every other page gets 64. (The heading above them is .sr-only and out of flow,
     which is why a :first-child override does not match.) */
}
.pillar{
  display:grid;
  grid-row:span 4;
  grid-template-rows:subgrid;
  row-gap:0;
}
.pillar .cat{
  align-self:start;
  font-family:'IBM Plex Mono', monospace;
  font-size:11.5px;
  font-weight:500;
  letter-spacing:0.16em;
  text-transform:uppercase;
  color:var(--accent-2);
  margin:0 0 12px;
}
.pillar h3{
  align-self:start;
  font-size:clamp(1.3rem,3vw,1.6rem);
  line-height:1.1;
  letter-spacing:-0.028em;
  font-weight:600;
  margin:0 0 14px;
  max-width:none;
  text-wrap:balance;
}
.pillar .fact{
  align-self:start;
  color:var(--muted);
  font-size:0.95rem;
  margin:0 0 18px;
}
.pillar .punch{
  align-self:start;
  border-left:2px solid var(--accent);
  padding:2px 0 2px 16px;
  margin:0;
  color:var(--text);
  font-size:0.95rem;
  line-height:1.5;
}

/* ============================================================
   How we work — the claim first, then what it replaced.
   ============================================================ */

/* Pull quote — breaks up a long run of body text with something the
   eye lands on. Used sparingly. */
.pull{
  border-left:2px solid var(--accent);
  padding:2px 0 2px 20px;
  margin:clamp(22px,3.4vw,30px) 0;
  font-size:clamp(1.05rem,2.4vw,1.25rem);
  line-height:1.4;
  color:var(--text);
  max-width:var(--measure);
  text-wrap:pretty;
}
.pull b{ color:var(--accent); font-weight:500; }

/* ---- scan comparison: what an index actually buys you ----
   Full scan lights every granule but in muted grey — it reads as weight
   and waste. The indexed read lights three in accent — precision. */
.strip[data-strip-mode="scan-all"] .g.read{
  background:var(--muted);
  box-shadow:none;
}

.scanbox{ display:flex; flex-direction:column; }
.scanbox .strip{ margin-top:4px; }
.scanbox .readout{ margin-top:12px; }
.verdict{
  font-family:'IBM Plex Mono', monospace;
  font-size:11px;
  letter-spacing:0.14em;
  text-transform:uppercase;
  margin:0 0 2px;
  color:var(--muted);
}
.scanbox.win .verdict{ color:var(--accent); }

/* ---- fill: granules rise into a profile when scrolled into view ---- */
.strip[data-strip-mode="fill"].on .g{
  animation:fill .7s cubic-bezier(.2,.75,.3,1) both;
}
@keyframes fill{
  from{ height:38%; }
  to  { height:var(--h,64%); }
}

/* ---- drift: a slow travelling wave. Pure CSS, staggered per granule,
   so nothing is written from JS on every frame. ---- */
.strip[data-strip-mode="drift"] .g{
  animation:drift 3.6s ease-in-out infinite;
}
@keyframes drift{
  0%,100%{ height:38%; }
  50%    { height:64%; }
}

/* ---- the ratio figure: same grid, far fewer people ---- */
.ratio{
  display:grid;
  gap:clamp(22px,4vw,38px);
  grid-template-columns:repeat(auto-fit, minmax(230px, 1fr));
  margin-top:clamp(22px,3.4vw,30px);
}
.dots{
  display:grid;
  grid-template-columns:repeat(10, 1fr);
  gap:5px;
  max-width:240px;
  margin:10px 0 14px;
}
.dot{
  aspect-ratio:1;
  border-radius:50%;
  background:var(--rule);
}
.dot.on{ background:var(--muted); }
.dots.few .dot.on{
  background:var(--accent);
  box-shadow:0 0 10px -2px var(--accent);
}
.ratio .count{
  font-family:'IBM Plex Mono', monospace;
  font-size:clamp(1.5rem,4vw,2rem);
  font-weight:500;
  color:var(--text);
  margin:0 0 2px;
  letter-spacing:-0.02em;
}
.ratio .few-count{ color:var(--accent); }

/* Touch devices have no pointer to follow, so the strip reads itself —
   a slow pass, then a rest. Same idea as the cursor mode with time as
   the input. Pure CSS: nothing is written per frame. */
.strip[data-strip-mode="cursor"].auto .g{
  animation:autoscan 5s ease-in-out infinite;
}
@keyframes autoscan{
  0%   { height:38%; background-color:var(--rule); }
  7%   { height:82%; background-color:var(--accent); }
  20%  { height:38%; background-color:var(--rule); }
  100% { height:38%; background-color:var(--rule); }
}

/* One sweep across the index. Nothing matches, so nothing stays lit. */
.scanning .g{ animation:sweep .5s ease-out both; }

@keyframes sweep{
  0%   { background:var(--rule); }
  45%  { background:var(--accent-dim); }
  100% { background:var(--rule); }
}

.readout{
  font-family:'IBM Plex Mono', monospace;
  font-size:clamp(10.5px,2.6vw,12.5px);
  line-height:1.7;
  color:var(--muted);
  margin:14px 0 0;
  display:flex;
  flex-wrap:wrap;
  gap:2px 20px;
}
.readout b{ color:var(--accent-2); font-weight:500; }

/* ---------- actions ---------- */
.actions{
  display:flex;
  flex-wrap:wrap;
  align-items:baseline;
  gap:12px 28px;
  padding-top:clamp(26px,4vw,34px);
  border-top:1px solid var(--rule);
}
.actions.bare{ border-top:0; padding-top:0; }
/* Hero CTA reads as part of the lede rather than a separate band below a rule. */
.actions.flush{ border-top:0; padding-top:0; margin-top:clamp(6px,1.4vw,12px); }

.actions a{
  font-size:clamp(1rem,3.4vw,1.12rem);
  font-weight:500;
  color:var(--text);
  text-decoration:none;
  border-bottom:2px solid var(--accent-dim);
  padding-bottom:2px;
  word-break:break-word;
  transition:border-color .18s ease, color .18s ease;
}
.actions a:hover{ border-color:var(--accent); color:var(--accent); }
.actions a:focus-visible{ outline:2px solid var(--accent); outline-offset:4px; border-radius:2px; }

.status{
  font-family:'IBM Plex Mono', monospace;
  font-size:11.5px;
  letter-spacing:0.09em;
  text-transform:uppercase;
  color:var(--muted);
}
.status i{
  font-style:normal; display:inline-block;
  width:6px; height:6px; border-radius:50%;
  background:var(--accent); margin-right:8px; vertical-align:middle;
}

/* ---------- footer ---------- */
footer{
  flex-shrink:0;
  margin-top:clamp(40px,7vw,72px);
  padding:24px 0 max(30px, env(safe-area-inset-bottom));
  border-top:1px solid var(--rule);
  font-family:'IBM Plex Mono', monospace;
  font-size:11px;
  letter-spacing:0.06em;
  color:var(--muted);
}
footer .wrap{
  display:flex;
  flex-wrap:wrap;
  justify-content:space-between;
  gap:10px 28px;
}
footer nav{ display:flex; flex-wrap:wrap; gap:8px 20px; }
footer a{ color:var(--muted); text-decoration:none; }
footer a:hover{ color:var(--accent); }
footer a:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; border-radius:2px; }

/* ---------- theme switcher (only with ?themes) ---------- */
#themebar{
  position:fixed; bottom:16px; left:50%; transform:translateX(-50%);
  display:none; gap:6px; padding:8px;
  background:var(--lift); border:1px solid var(--rule); border-radius:8px;
  font-family:'IBM Plex Mono', monospace; font-size:11px; z-index:99;
}
#themebar.on{ display:flex; }
#themebar button{
  font:inherit; cursor:pointer; padding:6px 10px; border-radius:5px;
  background:transparent; color:var(--muted); border:1px solid var(--rule);
}
#themebar button[aria-pressed="true"]{ color:var(--bg); background:var(--accent); border-color:var(--accent); }

@media (prefers-reduced-motion: reduce){
  .g{ transition:none; }
  .strip[data-strip-mode="cursor"].auto .g{ animation:none; }
  .strip[data-strip-mode="cursor"] .g{ transition:none; }
  .scanning .g{ animation:none; }
}

/* ---------- spacing utilities ----------
   These replace 17 inline style="" attributes. They are not a design system —
   they are exactly the one-off spacing values that were already in the markup,
   lifted verbatim so the Content-Security-Policy can keep `style-src` free of
   'unsafe-inline'. An inline style attribute is indistinguishable, to CSP, from
   an injected one; the whole point of the policy is that the browser can tell.
   Declared last so they win on source order against equal-specificity rules. */
/* Doubled, for weight: `.actions.bare{padding-top:0}` is 0,2,0 and the inline
   style these replace used to outrank it. Same trick as .note-inset below. */
.pt-1.pt-1{ padding-top:clamp(20px,3vw,26px); }
.pt-2.pt-2{ padding-top:clamp(24px,3.6vw,32px); }
.mt-0{ margin-top:0; }
.mt-1{ margin-top:clamp(22px,3.4vw,30px); }
.mt-2{ margin-top:clamp(24px,3.6vw,32px); }
.mt-3{ margin-top:clamp(24px,4vw,32px); }
.mt-4{ margin-top:clamp(24px,4vw,34px); }
.mt-5{ margin-top:clamp(26px,4vw,34px); }
.mt-6{ margin-top:clamp(30px,4.6vw,42px); }
.mt-7{ margin-top:clamp(30px,5vw,44px); }
/* Two declarations, so it needs the extra weight `.body`/`.quiet` would otherwise
   win on. Kept as one class because it is one intent: the inset footnote. */
.note-inset.note-inset{ margin-top:14px; font-size:0.88rem; }

/* ---------- accessibility utilities ----------
   .sr-only removes content visually while keeping it in the accessibility tree
   and in the tab order. It is never `display:none` — that drops it from both,
   which is the single most common way a skip link ships broken. */
.sr-only{
  position:absolute;
  width:1px; height:1px;
  padding:0; margin:-1px;
  overflow:hidden;
  clip-path:inset(50%);
  white-space:nowrap;
  border:0;
}

/* The skip link is .sr-only until focused, then it is the first thing on screen.
   Sized past 44x44 deliberately: it is the one control allowed above that bar. */
.skip-link:focus{
  position:fixed;
  top:12px; left:12px;
  z-index:100;
  width:auto; height:auto;
  clip-path:none;
  margin:0;
  padding:14px 20px;
  background:var(--lift);
  color:var(--text);
  font-family:'IBM Plex Mono', monospace;
  font-size:13px;
  letter-spacing:0.08em;
  text-transform:uppercase;
  text-decoration:none;
  border:2px solid var(--accent);
  border-radius:4px;
}

/* A base focus ring. The eleven per-selector rules above are an allowlist, so
   anything not on it — every mailto: link, every inline prose link — got only
   the UA default. Zero-specificity via :where(), at the same 2px/accent the
   existing rules use, so nothing already styled changes. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible{
  outline:2px solid var(--accent);
  outline-offset:3px;
  border-radius:2px;
}

/* Section labels are headings, semantically — three pages jumped h1 -> h3
   because .kicker was a <p>. Promoting it to <h2> must not move a pixel, so the
   h2-only properties are reset to what the <p> computed. */
h2.kicker{
  line-height:1.6;
  max-width:none;
  text-wrap:wrap;
}

/* Inline code. Nothing used <code> until How We Do It needed to name codecs and
   settings as content rather than prose, so this rule changes no existing page. */
code{
  font-family:'IBM Plex Mono', monospace;
  font-size:0.92em;
  color:var(--accent-2);
}

/* ---------- surface inventory ----------
   Three columns: what it is, where it is, and who it is for. The third is the
   reason the page exists — a list of URLs is a sitemap; naming the consumer is
   what makes it a statement. */
.surf{ margin:0 0 clamp(26px,4vw,38px); }
.surf .row{
  display:grid;
  grid-template-columns:minmax(150px,1.05fr) minmax(130px,0.95fr) 1.9fr;
  gap:10px 26px;
  padding:15px 0;
  border-top:1px solid var(--rule);
  align-items:baseline;
}
.surf .row:last-child{ border-bottom:1px solid var(--rule); }
.surf .nm{ font-weight:600; }
.surf .wh{ color:var(--muted); font-size:0.94rem; }
.surf .pa a{ color:var(--accent-2); text-decoration:none; border-bottom:1px solid transparent; }
.surf .pa a:hover{ border-bottom-color:var(--accent-2); }
@media (max-width: 700px){
  .surf .row{ grid-template-columns:1fr; gap:3px; padding:16px 0; }
}

/* ---------- the path that missed (404) ----------
   Lived in a <style> block inside 404.html until now, which meant it never applied:
   `style-src` carries no 'unsafe-inline', and that blocks a <style> ELEMENT just as
   hard as a style="" attribute. The box rendered unstyled on every enforcing browser.
   Appended here rather than merged in above so this file stays a clean fast-forward
   for the site branch. */
.path{
  font-family:'IBM Plex Mono', monospace;
  font-size:clamp(11.5px,2.8vw,13px);
  color:var(--muted);
  background:var(--lift);
  border:1px solid var(--rule);
  border-radius:5px;
  padding:10px 14px;
  margin:0 0 clamp(28px,5vw,44px);
  max-width:100%;
  overflow-x:auto;
  white-space:nowrap;
  -webkit-overflow-scrolling:touch;
}
.path b{ color:var(--text); font-weight:500; }

/* ---------- inline prose links ----------
   Every anchor on the site was styled by a container class — .nav a, .actions a,
   .jump, .src, footer a, .partners a. There was no rule for a link inside body copy,
   so the first one written rendered as browser-default blue-on-black (and purple once
   visited). The careers postings need them: mailto: links in the EEO and Apply text.
   Scoped to where prose actually lives, so nothing already styled changes. */
.body a, .list a, .item p a{
  color:var(--accent-2);
  text-decoration:none;
  border-bottom:1px solid var(--rule);
  transition:color .18s ease, border-color .18s ease;
}
.body a:hover, .list a:hover, .item p a:hover{
  color:var(--accent);
  border-bottom-color:var(--accent);
}

/* ---------- home hero, sitting up ----------
   .hero centres its content in the leftover viewport height, which on the
   placeholder pushed the strip a long way below the top bar. The strip is the
   first thing you should see, so the home page opts out of centring and takes
   half the top padding. */
.hero.top{
  justify-content:flex-start;
  padding-top:clamp(20px,4.5vw,42px);
}

/* ---------- stacked actions ----------
   .actions is a single wrapping row, which put the CTA, the address and the
   status shoulder to shoulder. .stack gives each its own line; .pair keeps the
   address and its status together on one. */
.actions.stack{
  flex-direction:column;
  align-items:flex-start;
  gap:clamp(12px,2vw,16px);
}
.actions .pair{
  display:flex;
  flex-wrap:wrap;
  align-items:baseline;
  gap:8px 20px;
}

/* ---------- hiring flow ----------
   Four steps read as a sequence rather than four more bordered rows. The rule
   runs through the numbers to the next step; the item that ends a row does not
   get one, which is why the column count is fixed per breakpoint rather than
   auto-fit — a dangling connector is worse than a reflow. */
.flow{
  display:grid;
  grid-template-columns:repeat(4, 1fr);
  gap:clamp(18px,3vw,26px);
  margin:clamp(24px,4vw,34px) 0 0;
  padding:0;
  list-style:none;
}
.flow li{
  position:relative;
  padding-top:46px;
}
.flow li::before{
  content:"";
  position:absolute;
  top:16px;
  left:34px;
  right:calc(-1 * clamp(18px,3vw,26px));
  height:1px;
  background:var(--rule);
}
.flow .n{
  position:absolute;
  top:0;
  left:0;
  width:33px;
  height:33px;
  display:flex;
  align-items:center;
  justify-content:center;
  border:1px solid var(--accent-dim);
  border-radius:50%;
  background:var(--bg);
  font-family:'IBM Plex Mono', monospace;
  font-size:12px;
  letter-spacing:0.04em;
  color:var(--accent);
}
.flow h3{ margin:0 0 7px; font-size:1rem; }
.flow p{ color:var(--muted); font-size:0.93rem; margin:0; }

.flow li:nth-child(4n)::before{ display:none; }

@media (max-width: 860px){
  .flow{ grid-template-columns:repeat(2, 1fr); }
  .flow li:nth-child(4n)::before{ display:block; }
  .flow li:nth-child(2n)::before{ display:none; }
}

@media (max-width: 560px){
  .flow{ grid-template-columns:1fr; gap:0; }
  .flow li{ padding:0 0 clamp(22px,4vw,30px) 50px; }
  /* Turned on its side: the rule now runs down the column to the next number. */
  .flow li::before{
    top:36px;
    bottom:-3px;
    left:16px;
    right:auto;
    width:1px;
    height:auto;
  }
  .flow li:nth-child(2n)::before{ display:block; }
  .flow li:last-child::before{ display:none; }
  .flow li:last-child{ padding-bottom:0; }
}

/* Bold lead-ins inside an .item. .list li b already got this; .item never had a
   bold in it until the postings moved onto the left-rule pattern, so the lead-in
   was inheriting --muted and doing no work. */
.item p b{ color:var(--text); font-weight:500; }

/* ---------- real bullets ----------
   .list is a stack of hairline-separated rows, which is right for four items and
   reads as a wall at eight. This is the plain bulleted list the site never had:
   markers in accent, no rules, tight enough to scan. */
.bullets{
  margin:0 0 18px;
  padding-left:1.15em;
  max-width:var(--measure);
  color:var(--muted);
}
.bullets li{ margin:0 0 10px; padding-left:5px; }
.bullets li:last-child{ margin-bottom:0; }
.bullets li::marker{ color:var(--accent); }
.bullets b{ color:var(--text); font-weight:500; }

/* A long requirements list is reference material, not argument — it reads better
   a notch down from body copy. */
.bullets.sm{ font-size:0.92rem; }
.bullets.sm li{ margin-bottom:8px; }

/* ---------- home hero, balanced ----------
   The lede's bottom margin plus .actions.flush's top margin stacked into a gap
   roughly three times the one between the two CTA lines. Both gaps are now set
   from the same place. The stack gap is a few pixels larger on purpose: the
   link's underline sits below its text, and the lede's line-height leaves
   half-leading under its last line, so equal CSS values do not read as equal. */
.hero.top .lede{ margin-bottom:clamp(16px,2.6vw,21px); }
.hero.top .actions.flush{ margin-top:0; }
.actions.stack{ gap:clamp(18px,3vw,26px); }
