*{box-sizing:border-box}
html,body{margin:0}
html{background:var(--canvas)}
.frame{container-type:inline-size;background:var(--canvas)}
.page{max-width:var(--container-wide);margin:0 auto;padding:0 var(--space-5)}
.sec{padding:var(--section-y-mobile) 0;border-top:1px solid var(--border-hairline)}
.sec--first{border-top:0;padding-top:var(--space-8);padding-bottom:var(--space-4)}
/* Hero is one column on small screens; the civic graph sits under the CTA. The two-column
   split only turns on where there is room for it (see the >=900px block). */
.hero-grid{display:grid;grid-template-columns:1fr;gap:var(--space-8);align-items:center}
.civic{margin:0}
.civic-lab{font-family:var(--font-mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;fill:currentColor}
.civic-cap{font-size:.8125rem;margin-top:var(--space-4);max-width:26rem}
.sechead{display:flex;flex-direction:column;gap:var(--space-3);margin:0 0 var(--space-6)}
.col{display:flex;flex-direction:column}
.tgt{display:inline-flex;align-items:center;min-height:var(--target-min)}
/* Pending contact items: label + slot annotation share a baseline and a real
   gap (inline-flex strips the source whitespace between them). */
.links > span.tgt{gap:var(--space-2);align-items:baseline;padding-block:var(--space-3)}
/* Source-line links: expand the hit area to 44px with a ::before, never by
   inflating the line — a static transform, not a transition. */
.card .role-metadata a,.p-handle{position:relative}
.card .role-metadata a::before,.p-handle::before{content:"";position:absolute;left:0;right:0;top:50%;height:var(--target-min);transform:translateY(-50%)}
.lnk{font-weight:var(--sans-medium)}
.slot{font-family:var(--font-mono);font-size:12px;line-height:1.5;color:var(--text-tertiary)}
.wordmark{font-family:var(--font-serif);font-variation-settings:var(--serif-display);font-size:1.5rem;font-weight:800;line-height:1.1;letter-spacing:-0.01em}
.hero-h{font-size:1.5rem}
.hero-p{font-size:1.0625rem}
.hero-sub{font-size:1rem;color:var(--text-secondary);max-width:34rem}
.stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-8) var(--space-5)}
.stat{display:flex;flex-direction:column;gap:var(--space-2)}
.stat .role-label-caps{overflow-wrap:anywhere}
.stat-n{font-size:2.25rem}
/* Comma-grouped numerals have no break opportunity, so long figures spill their
   track in the 2-up mobile grid. Step them down; the wider block resets all of
   .stat-n and wins on source order. */
.stat-n--long{font-size:1.5rem}
@container (max-width:380px){ .stat-n--long{font-size:1.3125rem} }
@container (max-width:340px){ .stats .stat-n{font-size:1.75rem} .stats .stat-n--long{font-size:1.125rem} }
.stat-c{font-size:.8125rem}
.products{display:grid;grid-template-columns:1fr;gap:var(--space-4)}
.prod{padding:var(--space-5);display:flex;flex-direction:column;gap:var(--space-3)}
/* Both cards are grid items and already stretch to equal height; what read as ragged was the
   shorter card ending early and leaving its link floating mid-card. Pin the figure row and the
   link to the bottom so the two line up whatever the prose above them does. */
.prod > .viz{margin-top:var(--space-1)}
.prod-fig{margin-top:auto;padding-top:var(--space-3);display:flex;gap:var(--space-3);align-items:baseline;flex-wrap:wrap}
.prod > .lnk{margin-top:var(--space-1)}
.cards{display:grid;grid-template-columns:1fr;gap:var(--space-4)}
.card{padding:var(--space-6);display:flex;flex-direction:column;gap:var(--space-4)}
/* Same reason as .prod-fig: cards pair up in a 2-col grid and stretch to equal height, so a
   shorter one left its source line floating. Pin the source line to the bottom of the card. */
.card > .role-metadata:last-child{margin-top:auto}
.card-b{font-size:.9375rem}
.eras{display:flex;flex-direction:column}
.era{display:flex;flex-direction:column;gap:var(--space-2);padding:var(--space-4) 0;border-top:1px solid var(--border-subtle)}
.era-h{display:flex;gap:var(--space-3);align-items:baseline;flex-wrap:wrap}
.era-b{font-size:.9375rem}
.oss{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
.oss li{padding:var(--space-2) 0;border-top:1px solid var(--border-subtle);display:flex;flex-direction:column;gap:var(--space-1)}
.team{display:grid;grid-template-columns:1fr;gap:0}
.person{display:flex;flex-direction:column;gap:var(--space-3);padding:var(--space-5) 0;border-top:1px solid var(--border-subtle)}
.p-head{display:flex;flex-direction:column;gap:var(--space-1)}
.p-data{display:flex;flex-direction:column;gap:var(--space-2);align-items:flex-start}
.p-fig{display:flex;flex-direction:column;gap:0}
.p-handle{align-self:flex-start}
/* Readiness ladder. Node names are set in the same mono caps as the civic-graph labels so the
   section reads as a bookend to the hero figure rather than an unrelated price list. */
.ready-list{display:flex;flex-direction:column;gap:var(--space-6)}
.ready{display:grid;grid-template-columns:1fr;gap:var(--space-2);padding-bottom:var(--space-6);border-bottom:1px solid var(--border-subtle)}
.ready:last-child{border-bottom:0;padding-bottom:0}
.ready-node{color:var(--text-primary)}
.ready-b{max-width:42rem}
.ready-foot{max-width:42rem;margin:0}
.ready-foot--lead{margin-top:var(--space-10)}
.ready-state{font-style:italic;color:var(--text-primary)}
@container (min-width:900px){
  .ready{grid-template-columns:minmax(0,13rem) minmax(0,1fr);gap:var(--space-6);align-items:baseline}
  /* line the closing note up with the body column, not the label gutter */
  .ready-foot{margin-left:calc(13rem + var(--space-6))}
}
.colophon{display:flex;flex-direction:column;gap:var(--space-2);padding:var(--space-6) 0 var(--space-12);border-top:1px solid var(--border-subtle)}
@container (min-width:900px){
  .sec{padding:var(--section-y-desktop) 0}
  .sec--first{padding:var(--space-16) 0 var(--space-6)}
  .hero-grid{grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);gap:var(--space-10)}
  .cta-btn{font-size:1.125rem;min-height:56px;padding:0 34px}
  .civic-lab{font-size:9.5px}
  .page{padding:0 var(--space-10)}
  .wordmark{font-size:1.75rem}
  .hero-h{font-size:2.5rem;max-width:36rem}
  .hero-p{font-size:1.25rem;max-width:min(34rem,100%)}
  .hero-sub{font-size:1.125rem;max-width:32rem}
  .stats{gap:var(--space-6)}
  .stat-n{font-size:1.75rem}
  .stat-c{font-size:.75rem}
  .products{grid-template-columns:1fr 1fr;gap:var(--space-6)}
  .prod{padding:var(--space-6)}
  .cards{grid-template-columns:1fr 1fr;gap:var(--space-6)}
  .eras{display:grid;grid-template-columns:repeat(5,1fr);gap:var(--space-5)}
  .era{padding:var(--space-4) 0 0}
  .era-h{flex-direction:column;gap:var(--space-1);align-items:flex-start}
  .era-b{font-size:.875rem}
  .oss{display:grid;grid-template-columns:1fr 1fr;column-gap:var(--space-10)}
  .team{grid-template-columns:repeat(4,1fr);gap:var(--space-6)}
  .person{padding:var(--space-4) 0 0}
  .team{align-items:start}
}
.viz{display:flex;flex-direction:column;gap:var(--space-1);color:var(--text-primary)}
.viz-legend{position:relative;height:36px;margin-top:var(--space-2)}
.viz-key{position:absolute;top:0;display:flex;flex-direction:column}
.viz-key:first-child{left:0}
.viz-key:last-child{left:56.8%}
.p-spark{margin:var(--space-1) 0}

.viz-cols{display:grid;grid-template-columns:repeat(10,minmax(0,1fr));gap:var(--space-2)}
.viz-years > div:nth-child(even):not(:last-child){visibility:hidden}
@container (min-width:900px){ .viz-years > div:nth-child(even):not(:last-child){visibility:visible} }

/* TYPE RESTRICTION (page-level, 2026-08-22) — Newsreader is reserved for
   headings: role-display-hero and role-display-section. Every other role is
   Archivo, differentiated by size, weight and the text rungs; IBM Plex Mono
   stays on identifiers only. Port into colors_and_type.css if adopted. */
.role-lede,.role-body-serif,.role-metadata,.role-quote{
  font-family:var(--font-sans);
  font-variation-settings:var(--sans-body);
}
.role-lede{font-weight:var(--sans-normal);line-height:1.5}
.role-body-serif{font-weight:var(--sans-normal);line-height:1.5}
.role-metadata{font-weight:var(--sans-normal)}
.role-quote{font-weight:var(--sans-normal)}
.p-head .role-body-serif{font-weight:var(--sans-semibold)}
.era-b{font-weight:var(--sans-medium)}


.cta-row{display:flex;gap:var(--space-4);align-items:center;margin-top:var(--space-2)}
/* The primary call to action carries the page; .role-plate on its own is the dialog-button size.
   .cta-btn was a hook in the markup with no rule behind it until 2026-08-24. */
.cta-btn{font-size:1.0625rem;min-height:52px;padding:0 30px;border-radius:calc(var(--radius-md) * 1.25)}
dialog#contact{border:0;padding:0;background:transparent;width:min(28rem,calc(100% - 2rem));color:var(--text-primary)}
dialog#contact::backdrop{background:color-mix(in srgb, var(--color-ink-dark) 55%, transparent)}
.contact-card[hidden]{display:none}
.contact-card{display:flex;flex-direction:column;gap:var(--space-5);padding:var(--space-6)}
.contact-head{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-4)}
.contact-close{min-width:var(--target-min);min-height:var(--target-min);margin:calc(var(--space-3) * -1) calc(var(--space-3) * -1) 0 0;border:0;background:transparent;color:var(--text-secondary);font-family:var(--font-sans);font-size:1.5rem;line-height:1;cursor:pointer;border-radius:var(--radius-md);transition:color var(--duration-base) var(--ease-standard),background var(--duration-base) var(--ease-standard)}
.contact-close:hover{color:var(--text-primary);background:var(--canvas)}
.field{display:flex;flex-direction:column;gap:var(--space-2)}
.field input,.field textarea{font-family:var(--font-sans);font-variation-settings:var(--sans-body);font-size:1rem;line-height:1.5;color:var(--text-primary);background:var(--canvas);border:0;border-radius:var(--radius-md);padding:var(--space-3);min-height:var(--target-min);box-shadow:inset 0 0 0 1px var(--border-subtle);transition:box-shadow var(--duration-base) var(--ease-standard)}
.field textarea{resize:vertical}
.field input:hover,.field textarea:hover{box-shadow:inset 0 0 0 1px var(--color-functional-light)}
.contact-foot{display:flex;align-items:center;gap:var(--space-4);flex-wrap:wrap}

.stack-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  border-top:1px dotted var(--border-subtle);border-left:1px dotted var(--border-subtle)}
.stack-grid > *{border-right:1px dotted var(--border-subtle);border-bottom:1px dotted var(--border-subtle);
  padding:var(--space-4);min-height:92px;min-width:0;display:flex;flex-direction:column;justify-content:space-between;gap:var(--space-3)}
.stk-chip{justify-content:flex-end;background:color-mix(in oklch,var(--text-primary) 7%,var(--canvas));
  color:var(--text-secondary);font-family:var(--font-mono);font-size:12px;line-height:1.3}
.stk-mark{height:32px;width:100%;max-width:104px}
.stk-img{height:100%;width:auto;max-width:100%;object-fit:contain;object-position:left center;display:block;opacity:.87}
[data-theme="dark"] .stk-img{filter:invert(1)}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]) .stk-img{filter:invert(1)}}

.stk-cap{font-size:12px;font-weight:var(--sans-medium);font-variation-settings:var(--sans-body);letter-spacing:.04em;line-height:1.3;color:var(--text-secondary)}
@container (min-width:640px){ .stack-grid{grid-template-columns:repeat(4,minmax(0,1fr))} }
@container (min-width:1180px){ .stack-grid{grid-template-columns:repeat(6,minmax(0,1fr))} }

.geo{display:flex;flex-direction:column;gap:var(--space-6)}
.geo-map{width:100%;color:var(--text-primary)}
.geo-side{display:flex;flex-direction:column;gap:var(--space-6)}
.geo-legend{display:flex;flex-direction:column;gap:var(--space-2)}
.geo-key{display:flex;align-items:center;gap:var(--space-3)}
.geo-sw{width:14px;height:14px;background:currentColor;color:var(--text-primary);flex:none}
.geo-top{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-2) var(--space-6)}
.geo-row{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-3);padding-bottom:var(--space-1);border-bottom:1px dotted var(--border-subtle)}
@container (min-width:900px){
  .geo{display:grid;grid-template-columns:minmax(0,1fr) 260px;gap:var(--space-10);align-items:start}
  .geo-top{grid-template-columns:1fr}
  .stats.stats--wide{grid-template-columns:repeat(4,minmax(0,1fr))}
}

/* Long-figure row: the numerals here run to 13 glyphs ("2,369,208,554") with no
   break opportunity, so it holds a smaller display size and stays at one column
   until the container can fit them. */
.stats.stats--wide{grid-template-columns:minmax(0,1fr)}
.stats--wide .stat-n{font-size:1.5rem}
@container (min-width:560px){ .stats.stats--wide{grid-template-columns:repeat(2,minmax(0,1fr))} }
@container (min-width:1120px){ .stats.stats--wide{grid-template-columns:repeat(4,minmax(0,1fr))} }

/* Six-tile strip: the binding floor is the caps label "CONVERSATIONAL" (164px),
   so 6-up only once the tracks can hold it; 3-up in between. */
@container (min-width:640px){ .stats{grid-template-columns:repeat(3,minmax(0,1fr))} }
@container (min-width:1220px){ .stats{grid-template-columns:repeat(6,minmax(0,1fr))} .stats .stat-n--long{font-size:1.5rem} }
.geo-fig{display:flex;flex-direction:column;gap:var(--space-2);padding-top:var(--space-4);border-top:1px solid var(--border-subtle)}
.prod-mark{height:32px;display:flex;align-items:center}
.prod-mark img{height:100%;width:auto;display:block;opacity:.87}
/* Amendment ships one black mark and is inverted for dark. Resistbot ships two real
   treatments — the light one is different artwork (2 paths, brand blue #064672) and not an
   inversion of the dark one — so it opts out of the filter and swaps by theme instead. */
[data-theme="dark"] .prod-mark img:not(.mark-light):not(.mark-dark){filter:invert(1)}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]) .prod-mark img:not(.mark-light):not(.mark-dark){filter:invert(1)}}
/* Three theme states: bare :root is light, an explicit data-theme wins in both directions. */
.prod-mark .mark-dark{display:none}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) .prod-mark .mark-light{display:none}
  :root:not([data-theme="light"]) .prod-mark .mark-dark{display:block}
}
[data-theme="dark"] .prod-mark .mark-light{display:none}
[data-theme="dark"] .prod-mark .mark-dark{display:block}
[data-theme="light"] .prod-mark .mark-light{display:block}
[data-theme="light"] .prod-mark .mark-dark{display:none}

.yr{font-size:12px;font-variant-numeric:tabular-nums}
@container (max-width:560px){ .yr-alt{display:none} }
@container (max-width:560px){ .viz-years{display:flex;justify-content:space-between} .viz-years>div:not(:first-child):not(:last-child){display:none} }

/* Dark-mode easter egg: a fixed field the page scrolls over. Monochrome ink
   dots, no gradient and no blur; animates opacity only, never transform. */
.egg{display:none;position:fixed;inset:0;overflow:hidden;pointer-events:none;z-index:0}
.egg i{position:absolute;width:2px;height:2px;border-radius:var(--radius-full);
  background:var(--text-primary);opacity:.1;animation:egg-tw 10s ease-in-out infinite}
.egg i.sm{width:1px;height:1px}
.egg i.lg{width:3px;height:3px}
@keyframes egg-tw{0%,100%{opacity:.05}50%{opacity:.3}}
@media (prefers-color-scheme:dark){ .egg{display:block} .frame{background:transparent} html{background:var(--canvas)} }
[data-theme="dark"] .egg{display:block}
[data-theme="dark"] .frame{background:transparent}
[data-theme="light"] .egg{display:none}
[data-theme="light"] .frame{background:var(--canvas)}
.page{position:relative;z-index:1}
@media (prefers-reduced-motion:reduce){ .egg i{animation:none;opacity:.16} }}
.lad{display:flex;flex-direction:column;gap:var(--space-3);margin-top:var(--space-4)}
.lad-row{display:grid;grid-template-columns:1fr;gap:2px}
.lad-lab{font-size:12px;color:var(--text-secondary)}
.lad-bar{display:block;height:10px;background:currentColor;min-width:2px}
.lad-n{font-size:1rem}
@container (min-width:640px){
  .lad-row{grid-template-columns:11rem minmax(0,1fr) 9rem;align-items:center;gap:var(--space-4)}
  .lad-n{text-align:right}
}
.viz-keys{display:flex;flex-wrap:wrap;gap:var(--space-2) var(--space-6);margin-top:var(--space-2)}
.viz-keys .viz-key{position:static;flex-direction:row;align-items:baseline;gap:var(--space-2)}
.dist{display:grid;grid-template-columns:repeat(8,minmax(0,1fr));gap:var(--space-5) var(--space-4);margin-top:var(--space-4)}
.dist-geo{display:block;width:100%;height:56px;color:var(--text-primary);min-width:0;justify-self:stretch}
.dist-col{display:grid;grid-template-rows:56px auto 4px auto;row-gap:var(--space-2);min-width:0;justify-items:start}
.dist-plot{display:block;width:100%;height:4px;background:color-mix(in oklch,var(--text-primary) 10%,transparent)}
.dist-bar{display:block;height:4px;background:var(--text-primary);opacity:.55}
.dist-v{font-size:1rem}
.dist-k{font-size:12px;color:var(--text-tertiary)}
@container (max-width:520px){ .dist{grid-template-columns:repeat(2,minmax(0,1fr))} }
@container (min-width:521px) and (max-width:900px){ .dist{grid-template-columns:repeat(4,minmax(0,1fr))} }
