/* ============================================================================
   SITE.CSS — this site's own stylesheet, on the design system's cascade layers.
   ----------------------------------------------------------------------------
   Loads AFTER amber.css and shares its layer order, which is the whole contract:

     reset → tokens → ground → type → layout → components → utilities → overrides

   A later layer beats an earlier one regardless of specificity, and within one
   layer specificity and source order decide as they always did. amber.css fills
   the early layers and the generic half of `components`; this file fills:

     components  the site's own components — page layouts, cards, instruments,
                 the reconstruction plates. Where both files style the same thing
                 in this layer, this file is later and wins ties; where the system
                 is more specific it wins, which is the point of sharing a layer
                 rather than stacking one on the other.
     utilities   the extracted single-purpose classes (.xi-*), above components
     overrides   the last word — what once had to be written !important

   There is no theme attribute. There is one look, and its dark passages are the
   two bookends the system defines ([data-ground="bookend"]), not a mode.

   SOURCE: css/site/ — one file per layer below, concatenated by tools/build-css.py.
   Edit those files, never this one; `build-css.py --check` is a gate. (It was first
   folded from styles.css, ember.css and amber-bridge.css on 2026-09-12; that generator
   preserved every declaration value; everything after that date is a decision.
   ============================================================================ */
@layer reset, tokens, ground, type, layout, components, utilities, overrides;

@layer tokens{/* ── the site's own tokens, declared on every carrier the system re-derives tier 2 on,
   so they resolve against THAT carrier's roles: paper on the page, light on a bookend,
   one stop deeper on a tint. A custom property resolves where it is declared. */
:root, [data-ground="bookend"], [data-tint], .a-tinted{
  --act-2: var(--acc-violet);                 /* the second stop of a two-accent gradient */
  --cta-grad: linear-gradient(92deg, var(--acc-copper), var(--acc-amber));
  --cta-grad-hover: linear-gradient(92deg, var(--copper-700), var(--amber-700));   /* one stop deeper on paper */
  --cta-fill-hover-copper: var(--copper-700);   /* F: one stop deeper on paper */
  --ink-wash: color-mix(in srgb, var(--text-primary) 5%, transparent);   /* a raised fill */
  --act-wash: color-mix(in srgb, var(--act) 8%, transparent);            /* a hover fill */
  --link-ink: var(--acc-violet);              /* this site's links are violet, by decision */
  --door-ink: var(--violet-700);              /* a quiet door: one stop deeper than a link, so it reads the same on paper and on a tint (cta-grammar-check saw two inks for one component) */
  --link-ink-hover: color-mix(in srgb, var(--acc-violet) 78%, var(--text-primary));
}
/* a control edge on the bookend owes 1.4.11 its 3:1; the system's 37% cream measured 2.83:1
   on this site's #140C16 (nontext-contrast-check) — 42% clears it. Logged for the system. */
[data-ground="bookend"]{--border-strong:color-mix(in srgb, var(--neutral-100) 42%, transparent); --door-ink:var(--violet-100);
  --cta-grad-hover:linear-gradient(92deg, var(--copper-50), var(--amber-50)); --cta-fill-hover-copper:var(--copper-50)}
/* one stop lighter on a bookend */}
@layer components{/* ── from styles.css ── */
/* A figure image centres in its figure. An img is inline-level, so one
   given a max-width narrower than its figure sits hard LEFT and leaves
   the remainder as dead space — 180px of it on the O2 case at 1440.
   Stated on the component so no page has to remember it. */
figure > img, figure > svg, figure > video, figure > picture{display:block;margin-inline:auto}
/* ============================================================
   Arpit Maheshwari — Portfolio styles
   Cleaned up Phase 11J: pruned dead rules, kept only what
   renders on the live site. ~200 lines (was 340).
   ============================================================ */

/* ----- Design tokens (see DESIGN-SYSTEM.md — single source of truth) ----- */
:root{--ff-display:'Source Serif 4',Georgia,'Times New Roman',serif;--ff-sans:'Source Sans 3',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;--ff-label:'Source Sans 3',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;--ff-mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,monospace;--ease-out:cubic-bezier(0.16,1,0.3,1);--space-2:2px;--fs-micro:12px;--fs-eyebrow:12px;--fs-caption:13px;--fs-ui:14px;--fs-body:18px;--fs-lead:21px;--fs-card:22px;--fs-title:clamp(35px,2.9vw,46px);--fs-title-lg:clamp(40px,5vw,55px);--fs-hero:clamp(40px,5.5vw,64px);--fs-metric:clamp(38px,4.4vw,48px);--fs-metric-sm:24px;--section-y:90px;--page-x:64px;--inner-max:1180px;--measure:62ch;--radius:4px}
@media(max-width:900px){:root{--section-y:64px;--page-x:32px}}
@media(max-width:600px){:root{--section-y:48px;--page-x:24px}}
/* ----- Reset + base ----- */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth;font-size:16px}
/* The scrolling element is `html`, so a reduced-motion override scoped to `body` never
   applies (ember.css:253 targeted body.p-home and did nothing). Motion sensitivity is a
   vestibular accessibility need, not a preference — smooth scroll can trigger nausea. */
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{background:var(--surface-page);color:var(--text-body);font-family:var(--ff-sans);line-height:1.7;overflow-x:hidden;letter-spacing:-0.003em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}
a{color:inherit;text-decoration:none}
img{display:block;max-width:100%}
h1,h2,h3,h4,h5,h6{scroll-margin-top:80px}
.nav-links a[aria-current]{color:var(--accent-text)}
/* ----- Marginalia — the personality layer (Arpit's pick, 2026-07-29) -----
   Handwritten notes + pen-drawn SVG scribbles over the design system. Rules:
   notes state existing facts only; ≤1 note per section; gold, Caveat, ±2° tilt. */
.hand{font-family:'Caveat',cursive;color:var(--accent-text);line-height:1.25;pointer-events:none;letter-spacing:0;text-transform:none}
/* Focus states (a11y) */
a:focus-visible,button:focus-visible,input:focus-visible,textarea:focus-visible{outline:2px solid var(--accent-text);outline-offset:3px}
input[type="email"]:focus-visible,input[type="text"]:focus-visible,textarea:focus-visible{background-color:color-mix(in srgb, var(--accent-text) 5%, transparent)}
/* Visually-hidden labels (a11y) — read by screen readers, removed from visual flow */
.visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.proof-chip:focus-visible{outline:2px solid var(--accent-text);outline-offset:-2px}
/* Case cards — hover lift + keyboard focus (was inline onmouseover) */
.case-card-v2:hover{transform:translateY(-4px)}
.case-card-v2:focus-visible{outline:2px solid var(--accent-text);outline-offset:3px}
@media (max-width:600px){}
/* Icons */
.icon{width:20px;height:20px;stroke:currentColor;fill:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
/* Skip link (a11y) */
.skip-link{position:absolute;top:-100px;left:16px;background:var(--accent-text);color:var(--surface-page);padding:12px 24px;font-size:14px;font-weight:600;z-index:10000;border-radius:0 0 4px 4px;transition:top .2s}
.skip-link:focus{top:0}
/* Subtle noise overlay */
body::before{content:'';position:fixed;inset:0;pointer-events:none;z-index:9990;opacity:.4;background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.04'/%3E%3C/svg%3E")}
/* ----- Navigation ----- */
#nav{position:fixed;top:0;left:0;right:0;z-index:100;padding:24px 48px;display:flex;align-items:center;justify-content:space-between;background:color-mix(in srgb, var(--surface-page) 60%, transparent);backdrop-filter:blur(8px);transition:background .4s,backdrop-filter .4s,padding .3s}
/* THE SITE MARK — one declaration, not 32.
   This size was written out as a separate extracted class on every page
   that shows the logo (.xi-patterns-003, .xi-home-003, ...), each with
   !important. Thirty-two identical rules is not a system; it is the same
   decision copied until nobody owns it. Changing the mark size used to
   mean editing 32 rules and hoping none was missed. */
.site-logo{width:40px;height:40px}
#nav.scrolled{background:color-mix(in srgb, var(--surface-page) 92%, transparent);backdrop-filter:blur(16px);padding:16px 48px;border-bottom:1px solid var(--border-strong)}
.nav-logo{font-family:var(--ff-mono);font-size:13px;letter-spacing:.02em;color:var(--accent-text);white-space:nowrap}
.nav-links{display:flex;gap:40px;list-style:none;align-items:center}
.nav-links a:not(.cta){font-size:13px;letter-spacing:.02em;color:var(--text-muted);position:relative;transition:color .2s;white-space:nowrap}
.nav-links a::after{content:'';position:absolute;bottom:-3px;left:0;width:0;height:1px;background:var(--accent-text);transition:width .3s var(--ease-out)}
.nav-links a:hover{color:var(--text-body)}
.nav-links a:hover::after{width:100%}
.nav-links li.nav-book a{color:var(--accent-text)}
.nav-links li.nav-book a:hover{color:var(--accent-text);opacity:.78}
/* 2026-09-10 — .nav-cta is PLACEMENT ONLY now. Appearance belongs to the .cta
   component, which the nav door composes. Before this, .nav-cta (styles) plus
   html[data-theme=ember] .nav-cta (ember) plus body.p-home .nav-cta between
   them re-declared font, size, tracking, padding, border, radius, colour and
   weight — so the nav door rendered 48px tall at .08em tracking while the same
   component elsewhere rendered 44px at .02em. That is execution lesson 11: a
   component that does not own its critical properties renders differently per
   context. Measured before the fix: 5 different shapes across 71 instances. */
.nav-cta{transition:background .3s,color .3s}
/* order:1 puts the hamburger visually LAST (its original position) while the DOM keeps
   it before .nav-links, so Tab reaches the drawer it opens instead of skipping past it.
   The order property does not affect tab order — that is the point. */
.menu-toggle{display:none;order:1;flex-direction:column;gap:4px;cursor:pointer;background:none;border:none;padding:12px 8px;margin:-14px -10px}
.menu-toggle span{width:24px;height:1px;background:var(--text-body);transition:transform .3s,opacity .3s}
/* ----- Hero -----
   The prototype's hero block lived here: #hero, .hero-bg, .hero-grid-lines,
   .hero-headline (+ .line, .line-inner, em) and .hero-cta-row, including a
   half-second line-by-line entrance animation. The shipped hero is
   .hero > .hero-split > .hero-copy > h1#h-hero; every selector in this block
   matched 0 elements on all 39 live pages. Removed 2026-09-07 — the last time a
   dead prototype block was left to rot here, one generic selector inside it
   (`nav ul{gap:24px}`) silently retargeted onto the real nav and sat 16px off on
   the homepage for weeks. */
/* ----- Section scaffolding ----- */
.section{padding:var(--section-y) var(--page-x);border-top:1px solid var(--border-hairline)}
.section-inner{max-width:var(--inner-max);margin:0 auto}
/* ===== DESIGN SYSTEM — section grammar (see DESIGN-SYSTEM.md §6) =====
   Every section, every surface: .eyebrow + .section-title. One scale, one grammar. */
.eyebrow{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);font-weight:500;letter-spacing:.02em;color:var(--accent-text);margin:0;display:flex;align-items:center;gap:12px}
.section-title{font-family:var(--ff-display);font-weight:400;font-size:var(--fs-title);letter-spacing:-.01em;color:var(--text-body);margin:12px 0 0;max-width:24ch}
.lead{font-family:var(--ff-display);font-weight:300;font-size:var(--fs-lead);line-height:1.4;color:var(--text-body);max-width:46ch}
.card-title{font-family:var(--ff-display);font-weight:400;font-size:var(--fs-card);line-height:1.3;letter-spacing:-.005em;color:var(--text-body);margin:0}
.u-body{font-family:var(--ff-sans);font-size:var(--fs-body);line-height:1.7;color:var(--text-muted);max-width:var(--measure)}
.u-ui{font-family:var(--ff-sans);font-size:var(--fs-ui);line-height:1.6;color:var(--text-muted)}
/* Governed cream 'act' — dark base, cream peak. ONLY the receipts + one-idea bands. */
.act-cream{--accent-text:var(--accent-fill);background:var(--surface-page);color:var(--text-body);border-top:none}
@media(max-width:900px){}
a.thought-card{padding:32px;border:1px solid var(--border-strong);border-radius:4px;background:var(--surface-card);transition:border-color .3s,transform .3s var(--ease-out);display:flex;flex-direction:column}
a.thought-card:hover{border-color:var(--accent);transform:translateY(-4px)}
a.thought-card.featured{background:var(--surface-sunken)}
/* ----- Footer ----- */
footer{border-top:1px solid var(--border-strong);padding:40px 48px;display:flex;align-items:center;justify-content:space-between}
.footer-logo{font-family:var(--ff-mono);font-size:12px;letter-spacing:.02em;color:var(--text-faint)}
.footer-note{font-family:var(--ff-mono);font-size:var(--fs-micro);color:var(--text-muted)}
.footer-back{font-family:var(--ff-mono);font-size:var(--fs-micro);letter-spacing:.02em;color:var(--text-faint);display:flex;align-items:center;gap:8px;transition:color .2s;cursor:pointer;background:none;border:none}
.footer-back:hover{color:var(--accent-text)}
/* ----- Reveal animations ----- */
@keyframes reveal{}
/* Scroll-reveal removed 2026-09-07 — it delayed content without reporting a
   state change. Nothing on the site hides itself on load now. */
/* ----- Dyslexia-friendly mode ----- */
.dyslexia-toggle{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:transparent;border:1px solid var(--border-strong);border-radius:4px;color:var(--text-faint);font-family:var(--ff-mono);font-size:var(--fs-micro);letter-spacing:0.05em;cursor:pointer;transition:border-color 0.3s,color 0.3s,background 0.3s}
.dyslexia-toggle:hover{border-color:var(--accent);color:var(--text-body)}
.dyslexia-toggle.active{border-color:var(--accent-text);color:var(--accent-text);background:color-mix(in srgb, var(--accent-text) 8%, transparent)}
.dyslexia-toggle svg{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:1.5}
body.dyslexia-mode{font-family:'Lexend',sans-serif;letter-spacing:0.03em;word-spacing:0.1em}
body.dyslexia-mode .thought-excerpt,
body.dyslexia-mode .pullquote-card-text,
body.dyslexia-mode .remote-card-desc{font-family:'Lexend',sans-serif;line-height:2;letter-spacing:0.03em;word-spacing:0.1em}
body.dyslexia-mode .thought-title,
body.dyslexia-mode .remote-card-title{font-family:'Lexend',sans-serif}
/* ----- Exit-Intent Banner (newsletter capture on pattern pages) ----- */

/* ----- abbr[title] tooltips ----- */
abbr[title]{position:relative;text-decoration:none;border-bottom:1px dashed var(--accent-text);cursor:help}
abbr[title]:hover{color:var(--accent-text)}
abbr[title]::after{content:attr(title);position:absolute;bottom:140%;left:50%;transform:translateX(-50%) scale(0.9);background:var(--surface-card);border:1px solid var(--border-strong);color:var(--text-body);padding:8px 12px;font-size:12px;line-height:1.5;border-radius:4px;width:min(240px,calc(100vw - 32px));display:none;box-shadow:var(--elev-2);z-index:1000;opacity:0;pointer-events:none;transition:opacity 0.2s cubic-bezier(0.16,1,0.3,1),transform 0.2s cubic-bezier(0.16,1,0.3,1);font-family:var(--ff-sans);font-weight:normal;text-transform:none;text-align:left;white-space:normal}
abbr[title]::before{content:"";position:absolute;bottom:125%;left:50%;transform:translateX(-50%);border-width:6px;border-style:solid;border-color:var(--border-strong) transparent transparent transparent;z-index:1000;opacity:0;pointer-events:none;transition:opacity 0.2s cubic-bezier(0.16,1,0.3,1)}
abbr[title]:hover::after,abbr[title]:focus::after,abbr[title]:active::after{display:block;opacity:1;transform:translateX(-50%) scale(1);pointer-events:auto}
/* no hover, no tooltip: on touch the box could only appear clipped off-viewport;
   the surrounding prose (and the glossary) carry the definitions (2026-09-02 sweep) */
@media(hover:none){abbr[title]{cursor:inherit}}
abbr[title]:hover::before,abbr[title]:focus::before,abbr[title]:active::before{opacity:1;pointer-events:auto}
/* ----- Responsive: tablet (769px–1024px) ----- */
@media(min-width:769px) and (max-width:1024px){#nav{padding:20px 32px}}
/* ----- Responsive: mobile + tablet hamburger (≤900px) ----- */
@media(max-width:1100px){.nav-links{display:none;flex-direction:column;align-items:stretch;position:fixed;top:64px;left:0;right:0;background:color-mix(in srgb, var(--surface-page) 97%, transparent);padding:32px 24px;gap:24px;border-bottom:1px solid var(--border-strong);z-index:99}
.nav-links a:not(.cta){display:block;padding:12px 16px;font-size:15px;white-space:normal}
.nav-links.nav-open{display:flex}
.menu-toggle{display:flex}
/* Once .nav-links hide, the bar holds only logo | CTA | hamburger — and space-between
     parks the CTA in the middle of the gap (measured: left 482 in a 1000px viewport).
     margin-left:auto groups it with the hamburger on the right. This lived only in the
     <=768 block, so 769-1100px shipped with the CTA floating. Caught by Arpit 2026-08-06. */
  .nav-cta{margin-left:auto;margin-right:16px}}
/* ----- Responsive: mobile (≤768px) ----- */
@media(max-width:768px){#nav{padding:16px 20px;gap:8px}
.nav-logo span{display:none}
#nav.scrolled{padding:12px 24px}
.nav-cta{margin-left:auto;margin-right:16px}
html,body{font-size:16px}
/* was keyed on the style attribute itself; retargeted at extraction (theme-swap migration) */
  /* 2026-09-10: was text-align:center. Arpit specified this footer himself —
     "on the left can I have a two liner of text of name and the second line is
     about copyright" — and centring it below 768px contradicted that: the note
     wrapped to two centred lines whose second line sat indented, reading as a
     ragged block rather than a two-liner. Left is his arrangement at every width.
     align-items:flex-start is the other half and the reason my first attempt
     looked fixed on the homepage only: this is a flex COLUMN, so align-items
     centred each child BOX. text-align only governs text inside the box. On the
     homepage .footer-words is full width, so centring it was invisible; on the
     other 37 it shrink-fits to 266px and was pushed to x=62. */
  footer{flex-direction:column;gap:16px;text-align:left;align-items:flex-start}
.footer-logo,.footer-note,.footer-back{font-size:13px;min-height:44px;display:inline-flex;align-items:center;padding:4px 4px}}
/* ----- Responsive: small mobile (≤480px) ----- */
@media(max-width:480px){h1,h2,h3{scroll-margin-top:120px}}
/* ============================================================
   P19-B · VISUAL EVIDENCE SYSTEM (case pages)
   ============================================================ */
/* Vitals strip — the 10-second layer at the top of every case */
.case-vitals{display:flex;flex-wrap:wrap;gap:0;margin:0 0 40px;border:1px solid var(--border-strong);border-radius:var(--radius-2);overflow:hidden}
.case-vitals > div{flex:1 1 160px;min-width:140px;padding:16px 16px;border-right:1px solid var(--border-strong);background:var(--surface-card)}
.case-vitals > div:last-child{border-right:none}
.case-vitals dt{font-family:var(--ff-mono);font-size:var(--fs-micro);letter-spacing:.02em;color:var(--text-muted);margin:0 0 4px}
.case-vitals dd{font-family:var(--ff-display);font-weight:400;font-size:var(--fs-body);line-height:1.3;color:var(--text-body);margin:0;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual;font-variant-numeric:tabular-nums lining-nums}
.case-vitals dd.gold{color:var(--accent-text)}
.case-jump{display:flex;flex-wrap:wrap;gap:16px;margin:0 0 48px;font-family:var(--ff-mono);font-size:var(--fs-micro);letter-spacing:.02em}
.case-jump a{color:var(--text-muted);text-decoration:none;border-bottom:1px solid var(--border-strong);padding-bottom:2px;transition:color .2s,border-color .2s}
.case-jump a:hover{color:var(--accent-text);border-color:var(--accent-fill)}
/* Reconstruction frame — interactive, NDA-safe demos */
/* Interactive moments — THE RUNNING APP WINDOW (2026-08-06, iteration 5, Arpit-directed).
   Root cause of four rejections: the widget wore the site's PRINT language (uppercase mono,
   letterpress paper) — and print is static by definition, so no amount of chips, cream, or
   shadows made it read as operable. The fix is identity, not decoration: the widget now
   speaks the same visual language as the reconstruction PLATES — a light app window with
   chrome dots, sentence-case product type, and a real segmented control. People recognize
   software because they use it all day; recognition is the affordance. The ghost self-demo
   (assets/recon-live.js) supplies the behavioral proof.
   Tokens re-point to the app-light context INSIDE the window; contrast audited on the real
   pixels. No uppercase, no bold shouting, no compensating shadows inside the window. */
/* The .recon blocks are SIMULATIONS of a client's shipped product, and their
   tokens are deliberately NOT raised with the rest of the site (2026-09-10).
   Their borders measure 1.03:1 to 1.25:1, which fails WCAG 1.4.11 like the
   others did — but these are depictions of what AdTech, FinTech, Org Design,
   O2 and PTC actually looked like. Restyling them to pass would falsify the
   evidence the case study rests on, which canon forbids. Flagged to Arpit as
   a known, reasoned exception rather than silently fixed or silently left. */
.recon{margin:32px 0 48px;border:1px solid rgba(255,255,255,0.12);border-radius:10px;overflow:hidden;position:relative;--surface-page:#FFFFFF;--surface-sunken:#F4F5F7;--surface-card:#F4F5F7;--text-body:#16181D;--text-muted:#282B31;--text-faint:#282B31;--accent-text:#8A6210;--accent-fill:#8A6210;--accent-text:#6B4C0C;--border-strong:#E3E6EA;--accent:#C9CED6;--status-negative:#B63D0B;--status-caution:var(--accent-fill);--status-positive:#0E7A5F;--acc-copper:#0E7A5F;background:var(--surface-sunken);color:var(--text-body);box-shadow:0 30px 64px rgba(0,0,0,0.45)}
/* the chrome bar — same idiom as the plates: dark strip, three window dots, quiet title */
/* WRAPS. This row is a flex nowrap containing a BARE TEXT NODE — the "Reconstruction —
   anonymised … client under NDA" provenance line — beside an svg and the clock, both
   flex-shrink:0, plus two ::before/::after dots. At 390px the fixed items and the text's
   minimum exceeded the 260px content box by 30px, and .recon has overflow:hidden, so the
   NDA caption and "session 0:00" were cut off on fintech and vc-diligence. An anonymous
   flex item cannot be given min-width:0 — there is no selector for a text node — so the
   row wraps instead. It only wraps when it must; nothing moves at desktop widths. */
.recon-badge{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:12px 16px;background:#22252B;border-bottom:1px solid #2E323A;font-family:var(--ff-mono);font-size:10px;letter-spacing:0.04em;text-transform:none;color:#8D95A3}
.recon-badge::before{content:"";width:9px;height:9px;border-radius:50%;background:#3A3F48;flex:0 0 auto;box-shadow:14px 0 0 #3A3F48, 28px 0 0 #3A3F48;margin-right:32px}
.recon-badge::after{content:"";width:7px;height:7px;border-radius:50%;background:#37B87E;flex:0 0 auto;animation:reconPulse 2.4s ease-in-out infinite}
@keyframes reconPulse{0%,100%{opacity:1}
50%{opacity:.35}}
.rl-spark{width:60px;height:14px;margin-left:auto;flex:0 0 auto;opacity:.9}
.rl-clock{font-family:var(--ff-mono);font-size:10px;color:#8D95A3;flex:0 0 auto;font-variant-numeric:tabular-nums}
.recon-stage{padding:20px 24px}
/* product controls: sentence case, sans, real-software idioms */
.recon button{font-family:var(--ff-sans);font-size:13px;letter-spacing:0;text-transform:none;font-weight:500;background:#FFFFFF;color:var(--text-body);border:1px solid #D5D9DF;border-radius:6px;padding:8px 12px;box-shadow:0 1px 2px rgba(22,24,29,0.06);cursor:pointer;transition:background .15s, border-color .15s}
.recon button:hover{background:#F7F8FA;border-color:#C9CED6}
.recon button:active{transform:translateY(0.5px)}
.recon button:focus-visible{outline:2px solid #8A6210;outline-offset:2px}
/* the segmented control — the most recognized "pick one" idiom in software */
.recon-stage [role="group"]{display:inline-flex;gap:2px;padding:3px;background:#E7E9EE;border:1px solid #DCDFE5;border-radius:8px}
.recon-stage [role="group"] button{background:transparent;border:none;box-shadow:none;border-radius:6px;color:#282B31}
.recon-stage [role="group"] button:hover{background:rgba(255,255,255,0.6)}
.recon-stage [role="group"] button[aria-pressed="true"]{background:#FFFFFF;color:#16181D;font-weight:600;box-shadow:0 1px 3px rgba(22,24,29,0.16)}
.recon-caption{padding:12px 16px;border-top:1px solid #E3E6EA;background:#FFFFFF;font-family:var(--ff-sans);font-size:11.5px;letter-spacing:0;text-transform:none;color:#282B31}
/* the ghost cursor — the widget demonstrating itself once (assets/recon-live.js) */
.rl-ghost{position:absolute;top:0;left:0;width:16px;height:16px;margin:-8px 0 0 -8px;border-radius:50%;background:rgba(22,24,29,0.85);box-shadow:0 0 0 4px rgba(22,24,29,0.15), 0 4px 10px rgba(0,0,0,0.25);opacity:0;pointer-events:none;z-index:5;transition:transform .9s cubic-bezier(.3,.8,.3,1), opacity .4s}
.rl-ghost--on{opacity:1}
.rl-ghost--press{animation:rlPress .3s ease}
@keyframes rlPress{50%{box-shadow:var(--elev-2)}}
/* common fate: consequences flash together when a control is pressed */
.rl-flash{animation:rlFlash .8s ease}
@keyframes rlFlash{0%{background-color:rgba(138,98,16,0.14)}
100%{background-color:transparent}}
@media (prefers-reduced-motion:reduce){.recon button{transition:none}
.recon-badge::after{animation:none}}
.recon button{cursor:pointer}
.loom-slot .loom-facade:hover .loom-play{background:var(--accent-text)}
@media (max-width: 768px){.case-vitals > div{flex:1 1 46%;border-bottom:1px solid var(--border-strong)}
.recon-stage{padding:20px 12px}}
/* ----- Case-study screening-gate summary (2026-07-31) -----
   Browsing data shows the chance of leaving a page is highest at the very start and
   falls after, so a reader either bails in seconds or commits — two populations with
   opposite needs. This block is the skimmer's whole experience AND a pre-organised
   schema that improves what a committed reader retains from the prose below it.
   It carries three things only: the outcome in its locked canonical string, the
   constraint, and what was and was not his. No prose is deleted to make room. */
.case-gate{margin:24px 0 8px;padding:20px 24px;background:var(--surface-card);border:1px solid var(--border-strong);border-left:3px solid var(--accent-text);border-radius:var(--radius)}
.case-gate .cg-l{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--accent-text);margin:0 0 8px}
.case-gate p{font-size:var(--fs-body);color:var(--text-body);line-height:1.7;margin:0;max-width:70ch}
.case-gate b{color:var(--accent-text);font-weight:400}
@media(max-width:600px){.case-gate{padding:16px 16px}}
@media(max-width:560px){}
/* nav 320 guard — at 320px the wordmark + CTA + hamburger exceeded the viewport,
   producing 4px of two-dimensional scrolling (WCAG 1.4.10). The monogram alone
   still identifies the site and links home. */
@media(max-width:360px){#nav{padding-left:16px;padding-right:16px;gap:8px}
.nav-logo span{display:none}
.nav-cta{margin-right:8px}}
/* The method diagram needs the full column, not the 62ch text measure: at 595px the
   1280-unit viewBox downscaled to 0.465 and its labels rendered at 5.6px. */
.process-fig{margin:32px 0;width:calc(100% + 300px);margin-left:-150px;max-width:none}
/* Below ~1040px the 1280-unit viewBox downscales past the point where its labels are
   readable (act labels drop under 11px). The three acts are stated in full prose
   immediately below, so the diagram is hidden rather than shown illegibly — an
   unreadable diagram is worse than no diagram. */
@media(max-width:1040px){.process-fig{display:none}}
/* print-shared — before this, hire/index.html was the only file with print styles, so
   every case study printed a solid near-black background with the fixed nav stamped
   onto all 14 sheets. */
/* A <video> prints as a large empty rounded box with a dead 0:00 scrubber. On the
   homepage that wasted roughly two thirds of printed page 2 on a control nobody can
   press. Measured 2026-09-03 by generating the actual PDF rather than emulating print.
   The surrounding caption and the "The method, written out" link already print and say
   what the film contains, so hiding the shell loses nothing a reader can use on paper. */
@media print{.vid-frame{display:none}}
@media print{section,figure,.case-gate,.plA,.plF,.plM,.plO,.plP,.plV{page-break-inside:avoid}
a{text-decoration:underline}}
/* ============================================================================
   TYPE COMPONENTS — extracted 2026-08-02 from 471 duplicated inline styles.

   WHY: the site had 2,095 inline style attributes. Every repeated one was an
   independent fork of the same component, and several had silently drifted —
   two identically-classed <dl>s rendering differently, 16 spellings of one
   mono label, a <th> bold only because that is the UA default. Correctness
   gates (canon, contrast, case-sync) cannot see that; only structure prevents it.

   Each class below reproduces the inline declarations EXACTLY, so extraction
   changed no pixels (verified: full-page diff over 28 pages).

   RULE: a repeated component gets a class here. Never inline styles per instance.
   ============================================================================ */
/* prose */
.t-body{font-size:var(--fs-body);color:var(--text-body);line-height:1.8}
.t-body-muted{font-size:var(--fs-body);color:var(--text-muted);line-height:1.7}
.t-ui{font-size:var(--fs-ui);color:var(--text-body);line-height:1.6}
.t-ui-muted{font-size:var(--fs-ui);color:var(--text-muted);line-height:1.7}
.t-ui-muted-loose{font-size:var(--fs-ui);color:var(--text-muted);line-height:1.8}
.t-sans-ui{font-family:var(--ff-sans);font-size:var(--fs-ui);color:var(--text-body)}
.t-cap{font-size:var(--fs-caption);color:var(--text-muted)}
.t-cap-loose{font-size:var(--fs-caption);color:var(--text-muted);line-height:1.8}
/* display */
.t-hero{font-family:var(--ff-display);font-size:var(--fs-hero);font-weight:300;letter-spacing:-0.02em;color:var(--text-body)}
.t-standfirst{font-family:var(--ff-display);font-size:var(--fs-lead);font-weight:300;font-style:italic;color:var(--text-body);line-height:1.4}
/* mono labels — the three sanctioned tracks (DESIGN-SYSTEM §3): .15em eyebrow,
   .08em caption/meta, .1em nav/button/badge. Colour varies by surface, tracking does not. */
.lbl-eyebrow{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--accent-text)}
.lbl-eyebrow-500{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);font-weight:500;letter-spacing:.02em;color:var(--accent-text)}
.lbl-meta{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--text-muted)}
.lbl-ink{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);font-weight:500;letter-spacing:.02em;color:var(--text-body)}
.lbl-cap{font-family:var(--ff-mono);font-size:var(--fs-caption);letter-spacing:.02em;color:var(--text-muted)}
.lbl-cap-plain{font-family:var(--ff-mono);font-size:var(--fs-caption);letter-spacing:.08em;color:var(--text-muted)}
.lbl-badge-ink{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);font-weight:600;letter-spacing:.02em;color:var(--text-body)}
/* the wordmark beside the logo, previously an unnamed span in 27 files */
.nav-name{font-family:var(--ff-sans);font-size:14px;font-weight:600;letter-spacing:-0.5px}
.t-ui-muted-tight{font-size:var(--fs-ui);color:var(--text-muted);line-height:1.6}
.t-quote{font-family:var(--ff-display);font-size:var(--fs-card);font-style:italic;color:var(--text-body);line-height:1.6}
.t-ui-175{font-size:var(--fs-ui);color:var(--text-body);line-height:1.75}
.t-quote-sm{font-family:var(--ff-display);font-size:var(--fs-body);font-style:italic;color:var(--text-muted);line-height:1.6}
/* 0.9em is RELATIVE on purpose — inline code sits inside text of varying size (a 21px lead
   paragraph and a 16px body paragraph both host it). Substituting the fixed --fs-ui token here
   shrank it inside lead text; caught by the pixel diff, reverted. Do not "tokenise" this one. */
.t-code{font-family:var(--ff-mono);font-size:0.9em;color:var(--accent-text)}
.t-quote-cap{font-family:var(--ff-display);font-size:var(--fs-caption);font-style:italic;color:var(--text-muted);line-height:1.6}
.t-card-title{font-family:var(--ff-display);font-size:var(--fs-card);font-weight:400;color:var(--text-body)}
.t-sans-ui-muted{font-family:var(--ff-sans);font-size:var(--fs-ui);color:var(--text-muted);line-height:1.8}
.t-ui-muted-175{font-size:var(--fs-ui);color:var(--text-muted);line-height:1.75}
.t-body-muted-loose{font-size:var(--fs-body);color:var(--text-muted);line-height:1.8}
.t-sans-ui-reset{font-family:var(--ff-sans);font-size:var(--fs-ui);letter-spacing:0;text-transform:none;color:var(--text-body)}
.t-sans-ui-tight{font-family:var(--ff-sans);font-size:var(--fs-ui);color:var(--text-muted);line-height:1.45}
.lbl-cap-bold{font-family:var(--ff-mono);font-size:var(--fs-caption);font-weight:600;color:var(--text-body)}
.t-metric{font-family:var(--ff-display);font-size:var(--fs-metric);font-weight:300;color:var(--accent-text);line-height:1}
.t-serif-body-plain{font-family:var(--ff-display);font-size:var(--fs-body);color:var(--text-body)}
/* ============================================================================
   LAYOUT COMPONENTS — extracted 2026-08-02 from 263 duplicated inline styles.
   Same rule as the type components above: a repeated component gets a class.
   These names describe the ROLE (receipt row, action button, boundary note),
   because that is what a future edit is looking for.
   ============================================================================ */
.row-ic{display:flex;align-items:center;gap:12px}
.rcpt-r{display:flex;flex-wrap:wrap;align-items:center;gap:4px 24px;padding:16px 20px;border-bottom:1px solid var(--border-strong)}
.rcpt-r-tight{display:flex;flex-wrap:wrap;align-items:center;gap:4px 24px;padding:12px 20px;border-bottom:1px solid var(--border-strong)}
.rcpt-r-last{display:flex;flex-wrap:wrap;align-items:center;gap:4px 24px;padding:16px 20px}
.rcpt-r-tight-last{display:flex;flex-wrap:wrap;align-items:center;gap:4px 24px;padding:12px 20px}
.rcpt-box{display:grid;gap:0;grid-template-columns:1fr;border:1px solid var(--border-strong);border-radius:var(--radius-2)}
.btn-row{display:flex;flex-wrap:wrap;gap:16px;margin-top:48px}
.chip-row{display:flex;flex-wrap:wrap;gap:8px}
.meta-row{display:flex;flex-wrap:wrap;align-items:center;gap:16px;margin-bottom:20px}
.card-gold{margin-bottom:64px;padding:32px;border:1px solid color-mix(in srgb, var(--accent-text) 10%, transparent);border-radius:var(--radius-2)}
.card-p28{display:block;padding:24px;border:1px solid var(--border-strong);border-radius:4px}
.card-p32{display:block;padding:32px;border:1px solid var(--border-strong);border-radius:4px}
.card-seg{flex:1;padding:12px 16px;border:1px solid var(--border-strong);border-radius:2px}
.framed{border:1px solid var(--border-strong);border-radius:var(--radius-2);width:100%}
.framed-blk{display:block;margin-bottom:16px;border:1px solid var(--border-strong);border-radius:var(--radius-2);width:100%}
.framed-tight{margin:20px 0 0;border:1px solid var(--border-strong);border-radius:4px}
.note-gold{margin:40px 0 64px;padding:32px;border:1px solid var(--border-strong);border-radius:4px;border-left:3px solid var(--accent-text)}
.note-gold-b{margin-bottom:80px;padding:24px 24px;border:1px solid var(--border-strong);border-radius:4px;border-left:3px solid var(--accent-text)}
.measure-c{margin:0 auto;padding:0 24px;max-width:var(--measure)}
.measure-t{margin:64px auto 0;padding:0 0 8px;max-width:var(--measure)}
.card-wire{margin:40px 0;padding:40px;border:1px solid var(--border-strong);border-radius:8px}
.pullq{margin:24px 0;padding:32px;border:1px solid var(--border-strong);border-radius:4px;border-left:3px solid var(--accent-text)}
/* ═══ Hook objects (2026-08-04) — the "bakery box" wave ═══════════════════════
   Physical artifacts that carry canon-true numbers: receipt printer (proof act),
   Candidate Facts label (who-you'd-hire), inspection slip + stamp (errata),
   boarding pass (contact). Mimic-surfaces per DESIGN-SYSTEM "Exempt surfaces":
   own internal sizing, but contrast IS measured (audited at real pixels).
   Paper tokens are shared by all four so the family reads as one artifact set. */
:root{--obj-paper:#F7F3EC;--obj-paper-2:var(--surface-card);--obj-paper-ink:#1B1917;--obj-paper-soft:#544F44;--obj-paper-rule:rgba(27,25,23,0.35);--stamp-red:#A33B25}
.hkr-keep:hover{color:var(--accent-fill)}
@media(max-width:980px){}
@media(max-width:1100px){}
@media(max-width:900px){}
.qc.stamped .qc-stamp{transform:rotate(-8deg) scale(1);opacity:.85}
.qc.stamped .qc-void{opacity:0;transition:opacity .3s .1s}
.spec-tag:hover{transform:rotate(1.8deg) translateY(-4px)}
.spec-tag:focus-visible{outline:2px solid var(--accent-text);outline-offset:4px}
@media(max-width:1180px){}
.ccd{background:var(--surface-card);border:1px solid var(--border-hairline);box-shadow:var(--elev-2);padding:24px;position:sticky;top:104px}
.ccd-cap{font-family:var(--ff-mono);font-size:var(--fs-micro);letter-spacing:.02em;color:var(--text-muted);margin:0 0 16px;display:flex;justify-content:space-between}
.ccd-cap b{color:var(--status-positive);font-weight:500}
.ccd-ctr{border:1px solid var(--border-hairline);padding:12px 16px;font-family:var(--ff-mono);font-size:11px;line-height:1.7;margin-bottom:16px;background:var(--surface-page);color:var(--text-primary)}
.ccd-ctr b{font-weight:600}
.ccd-qs{display:flex;flex-direction:column;gap:8px;margin-bottom:16px}
.ccd-q{background:none;border:1px solid var(--accent-fill);color:var(--accent-fill);font-family:var(--ff-mono);font-size:12px;padding:12px;text-align:left;letter-spacing:.02em;cursor:pointer;transition:background .2s}
.ccd-q:hover{background:var(--act-wash)}
.ccd-q:focus-visible{outline:2px solid var(--accent-fill);outline-offset:2px}
.ccd-ans{min-height:96px;border-top:1px dashed var(--border-strong);padding-top:12px;font-size:13.5px;line-height:1.6;color:var(--text-primary)}
.ccd-idle{font-family:var(--ff-mono);font-size:11px;color:var(--text-muted)}
.ccd-tag{font-family:var(--ff-mono);font-size:var(--fs-micro);letter-spacing:.02em;display:inline-block;padding:3px 8px;margin-bottom:8px;font-weight:600}
.ccd-tag--in{color:var(--status-positive);border:1.5px solid var(--status-positive)}
.ccd-tag--out{color:var(--status-negative);border:1.5px solid var(--status-negative)}
.ccd-src{display:block;font-family:var(--ff-mono);font-size:10px;color:var(--text-muted);margin-top:8px}
.ccd-note{font-family:var(--ff-mono);font-size:10px;color:var(--text-muted);letter-spacing:.06em;margin:12px 0 0;text-align:center}
@media(max-width:1100px){
.ccd{position:static;max-width:440px;margin:8px auto 0}}
@media(max-width:1100px){}
/* — paper diagram (case pages, 2026-08-06): the cream explainer SVGs read as pasted
   rectangles on the dark pages (Arpit). They now join the paper-object family — tilted,
   shadowed, captioned like an artifact pulled from the case file, not a band of foreign UI. */
.fig-paper{margin:32px auto 8px;max-width:720px;border:none;background:none;overflow:visible;transform:rotate(-1.2deg);filter:drop-shadow(0 16px 28px rgba(0,0,0,0.5))}
.fig-paper img{display:block;width:100%;height:auto;border:1px solid rgba(32,24,12,0.2)}
.fig-paper figcaption{background:var(--obj-paper);color:var(--obj-paper-soft);border-top:1px dashed var(--obj-paper-rule);font-family:var(--ff-mono);font-size:11px;letter-spacing:.05em;text-transform:none;padding:8px 16px}
.fig-paper--r{transform:rotate(1.2deg)}
.hk-bp-link:hover{transform:translateY(-4px)}
.hk-bp-link:focus-visible{outline:2px solid var(--accent-text);outline-offset:4px}
@media(max-width:720px){}
/* ===== EXTRACTED FROM index.html (theme-swap migration; scoped body.p-home) ===== */
:where(body.p-home) .hero-demo{flex:0 1 448px;align-self:center;opacity:0;transform:translateY(20px);animation:reveal .5s var(--ease-out) .5s forwards}
:where(body.p-home,body.p-patterns) .hd-tag{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--accent-text);margin-bottom:12px}
:where(body.p-home,body.p-patterns) .hd-card{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:var(--radius-2);padding:24px 24px 20px;box-shadow:var(--elev-2)}
:where(body.p-home,body.p-patterns) .hd-diag-q{font-family:var(--ff-display);font-weight:300;font-size:21px;line-height:1.3;color:var(--text-body);margin:0 0 16px;letter-spacing:-.01em}
:where(body.p-home,body.p-patterns) .hd-presets{display:flex;flex-direction:column;gap:8px}
:where(body.p-home,body.p-patterns) .hd-preset{display:flex;align-items:center;text-align:left;background:transparent;border:1px solid var(--border-strong);border-radius:8px;padding:12px 16px;color:var(--text-body);font-family:var(--ff-sans);font-size:14px;line-height:1.35;text-decoration:none;cursor:pointer;transition:border-color .2s,color .2s,background .2s,transform .2s}
:where(body.p-home,body.p-patterns) .hd-preset:focus-visible{outline:2px solid var(--accent-text);outline-offset:3px}
:where(body.p-home,body.p-patterns) .hd-preset:hover{border-color:var(--accent-text);background:color-mix(in srgb, var(--accent-text) 6%, transparent);transform:translateX(3px);outline:none}
:where(body.p-home,body.p-patterns) .hd-preset span{font-family:var(--ff-mono);font-size:var(--fs-micro);color:var(--accent-text);margin-right:12px;flex:0 0 auto}
:where(body.p-home,body.p-patterns) .hd-preset::after{content:"→";margin-left:auto;padding-left:12px;color:var(--accent-text);opacity:.45;transition:opacity .2s,transform .2s;flex:0 0 auto}
:where(body.p-home,body.p-patterns) .hd-preset:hover::after{opacity:1;transform:translateX(2px)}
:where(body.p-home,body.p-patterns) .hd-free{margin-top:12px;display:flex;align-items:flex-end;gap:8px}
:where(body.p-home,body.p-patterns) .hd-free input:focus-visible{outline:2px solid var(--accent-text);outline-offset:2px}
:where(body.p-home,body.p-patterns) .hd-free input{flex:1 1 auto;min-width:0;width:100%;background:transparent;border:none;border-bottom:1px solid var(--border-strong);color:var(--text-body);font-family:var(--ff-display);font-style:italic;font-size:15px;padding:8px 2px}
:where(body.p-home,body.p-patterns) .hd-free input::placeholder{color:var(--text-faint)}
:where(body.p-home,body.p-patterns) .hd-free input:focus{border-color:var(--accent-text)}
:where(body.p-home,body.p-patterns) .hd-free-submit:hover{opacity:1;transform:translateX(2px)}
:where(body.p-home,body.p-patterns) .hd-free-submit:focus-visible{outline:2px solid var(--accent-text);outline-offset:2px;opacity:1}
:where(body.p-home,body.p-patterns) .hd-kicker{font-family:var(--ff-mono);font-size:var(--fs-micro);letter-spacing:.02em;color:var(--text-muted);margin:0 0 8px}
:where(body.p-home,body.p-patterns) .hd-said{font-family:var(--ff-display);font-style:italic;font-size:15px;color:var(--text-muted);margin:0;line-height:1.4}
:where(body.p-home,body.p-patterns) .hd-rule{width:44px;height:2px;background:var(--accent-text);opacity:.5;margin:16px 0}
:where(body.p-home,body.p-patterns) .hd-reframe{font-family:var(--ff-display);font-weight:300;font-size:clamp(21px,2.3vw,26px);line-height:1.28;color:var(--text-body);margin:0 0 24px;letter-spacing:-.01em}
:where(body.p-home,body.p-patterns) .hd-reframe em{font-style:italic;color:var(--accent-text)}
:where(body.p-home,body.p-patterns) .hd-reset{display:block;background:none;border:none;color:var(--text-faint);font-family:var(--ff-mono);font-size:var(--fs-micro);letter-spacing:.02em;cursor:pointer;padding:0;margin-top:16px;transition:color .2s}
:where(body.p-home,body.p-patterns) .hd-reset:hover{color:var(--accent-text)}
:where(body.p-home,body.p-patterns) #hd-answer[hidden]{display:none}
:where(body.p-home,body.p-patterns) #hd-answer{animation:reveal .4s var(--ease-out) forwards}
@media (max-width:980px){:where(body.p-home) .hero-demo{flex:1 1 100%;max-width:440px;margin-top:4px}}
@media (prefers-reduced-motion:reduce){
:where(body.p-home) .hero-demo{animation:none;opacity:1;transform:none}}
:where(body.p-home) .proof-cell:hover{opacity:.62}
:where(body.p-home) .rcpt-btn{margin-top:auto;padding:8px 12px;font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--accent-fill);background:transparent;border:1px solid var(--accent);border-radius:var(--radius);cursor:pointer;transition:background .15s,color .15s}
:where(body.p-home) .rcpt-btn:hover{background:var(--accent-text);color:var(--surface-page)}
:where(body.p-home) .rcpt-btn:focus-visible{outline:2px solid var(--accent-fill);outline-offset:2px}
:where(body.p-home) .rcpt-btn[aria-expanded="true"]{background:var(--accent-text);color:var(--surface-page);border-color:var(--accent-text)}
:where(body.p-home) .rcpt{margin-top:32px;border:1px solid var(--accent);border-radius:var(--radius);background:var(--surface-card);padding:24px 24px}
:where(body.p-home) .rcpt-h{font-family:var(--ff-display);font-weight:400;font-size:var(--fs-card);line-height:1.3;color:var(--text-body);margin:0 0 16px}
:where(body.p-home) .rcpt-h:focus{outline:none}
:where(body.p-home) .rcpt-rows{border-top:1px solid var(--border-strong)}
:where(body.p-home) .rcpt-row{display:flex;flex-wrap:wrap;gap:4px 24px;padding:12px 0;border-bottom:1px solid var(--border-strong);align-items:baseline}
:where(body.p-home) .rcpt-l{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--accent-fill);flex:0 0 200px}
:where(body.p-home) .rcpt-v{font-size:var(--fs-ui);color:var(--text-body);line-height:1.65;flex:1 1 240px}
:where(body.p-home) .beat{flex:1;height:3px;background:color-mix(in srgb, var(--accent-text) 16%, transparent);border-radius:2px}
:where(body.p-home) .beat.on{background:var(--accent-text);height:5px}
:where(body.p-home) .rcpt-more{display:inline-block;margin-top:16px;font-family:var(--ff-mono);font-size:var(--fs-caption);letter-spacing:.04em;color:var(--accent-fill);text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:2px}
@media (max-width:900px){}
@media (max-width:520px){}
:where(body.p-home) .verb{border-top:2px solid var(--text-body);padding-top:16px}
:where(body.p-home) .idea-link:hover{border-color:var(--accent-text)}
@media (max-width:640px){}
:where(body.p-home) .ai-case:hover .card-title{color:var(--accent-text)}
:where(body.p-home) .ai-case:hover .walk{color:var(--text-body)}
:where(body.p-home) .ai-case .walk{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--accent-text);flex:0 0 auto;margin:0;transition:color .3s}
:where(body.p-home) .range-strip .lbl{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--text-muted)}
:where(body.p-home) .range-strip a:hover{border-color:var(--accent-text)}
@media (max-width:860px){}
@keyframes fadeIn{from{opacity:0;transform:translateY(4px)}}
:where(body.p-home,body.p-patterns) .hd-range:active{cursor:grabbing}
:where(body.p-home,body.p-patterns) .hd-range:focus-visible{box-shadow:0 0 0 3px color-mix(in srgb, var(--accent-text) 35%, transparent)}
@media (prefers-reduced-motion:reduce){}
/* --- former hover handlers (index.html) --- */
.hv-home-2:hover{border-color:var(--accent);color:var(--text-body)}
.hv-home-3:hover{color:var(--accent-text)}
/* ===== EXTRACTED FROM 404.html (theme-swap migration; scoped body.p-404) ===== */
body:where(.p-404){--obj-paper:#F7F3EC;--p-ink:#1B1917;--p-soft:#544F44;--p-rule:rgba(27,25,23,0.35);--stamp-red:#A33B25;--fs-eyebrow:12px;--radius:4px}
:where(body.p-404) *{box-sizing:border-box;margin:0;padding:0}
html:where(:has(body.p-404)){font-size:16px;overflow-x:hidden}
body:where(.p-404){background:var(--surface-page);color:var(--text-body);font-family:var(--ff-sans);line-height:1.7;-webkit-font-smoothing:antialiased;overflow-x:hidden}
:where(body.p-404) .wrap{min-height:100vh;display:grid;grid-template-columns:minmax(0,1fr) 400px;gap:64px;align-items:center;max-width:1080px;margin:0 auto;padding:64px 32px 40px;position:relative}
:where(body.p-404) .ghost{position:absolute;top:50%;left:50%;transform:translate(-50%,-58%);font-family:var(--ff-display);font-weight:300;font-size:clamp(220px,42vw,420px);line-height:1;color:transparent;-webkit-text-stroke:1px color-mix(in srgb, var(--accent-text) 13%, transparent);text-stroke:1px color-mix(in srgb, var(--accent-text) 13%, transparent);pointer-events:none;user-select:none;z-index:0;white-space:nowrap}
:where(body.p-404) .content{position:relative;z-index:1}
:where(body.p-404) .kick{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);font-weight:500;letter-spacing:.02em;color:var(--accent-text);margin-bottom:20px}
:where(body.p-404) h1{font-family:var(--ff-display);font-weight:300;font-size:var(--fs-hero);letter-spacing:-0.02em;margin-bottom:20px}
:where(body.p-404) h1 em{font-style:italic;color:var(--accent-text)}
:where(body.p-404) .lede{font-family:var(--ff-display);font-weight:300;font-size:var(--fs-lead);color:var(--text-body);line-height:1.7;max-width:44ch;margin-bottom:24px}
:where(body.p-404) .actions{display:flex;flex-wrap:wrap;gap:12px 16px;align-items:center;margin-top:4px}
:where(body.p-404) .btn{display:inline-flex;align-items:center;gap:8px;padding:12px 24px;background:var(--accent-text);color:var(--surface-page);font-family:var(--ff-mono);font-weight:500;font-size:var(--fs-eyebrow);letter-spacing:.02em;border-radius:var(--radius);text-decoration:none;transition:background .25s,transform .2s}
:where(body.p-404) .btn:hover{background:var(--accent-text);transform:translateY(-2px)}
:where(body.p-404) .inline-links{font-size:var(--fs-ui);color:var(--text-muted)}
:where(body.p-404) .inline-links a{color:var(--accent-text);text-decoration:none;border-bottom:1px solid var(--accent-fill);padding-bottom:1px;transition:color .2s,border-color .2s}
:where(body.p-404) .inline-links a:hover{color:var(--accent-text);border-color:var(--accent-text)}
:where(body.p-404) .hand{font-family:'Caveat',cursive;font-size:20px;color:var(--accent-text);margin-top:24px}
:where(body.p-404) .meta-note{margin-top:32px;padding-top:20px;border-top:1px solid var(--border-strong);font-size:var(--fs-caption);color:var(--text-muted);line-height:1.8;max-width:54ch}
:where(body.p-404) .meta-note a{color:var(--accent-text);text-decoration:none;border-bottom:1px solid var(--accent-fill);padding-bottom:1px}
:where(body.p-404) .meta-note a:hover{color:var(--accent-text)}
:where(body.p-404) .lug{position:relative;z-index:1;background:var(--obj-paper);color:var(--p-ink);font-family:var(--ff-mono);padding:24px;transform:rotate(1.6deg);filter:drop-shadow(0 16px 28px rgba(0,0,0,0.55))}
:where(body.p-404) .lug-head{display:flex;justify-content:space-between;align-items:baseline;border-bottom:1.5px solid var(--p-ink);padding-bottom:8px;margin-bottom:12px}
:where(body.p-404) .lug-head b{font-size:12.5px;letter-spacing:.02em;font-weight:600}
:where(body.p-404) .lug-head span{font-size:10.5px;color:var(--p-soft)}
:where(body.p-404) .lug-row{display:flex;justify-content:space-between;gap:12px;font-size:12px;padding:8px 0;border-bottom:1px dashed var(--p-rule)}
:where(body.p-404) .lug-row b{font-weight:600;text-align:right}
:where(body.p-404) .lug-row--last{border-bottom:none}
:where(body.p-404) .lug-meter{height:3px;background:rgba(27,25,23,0.12);border-radius:2px;overflow:hidden;margin:8px 0 0}
:where(body.p-404) .lug-fill{height:100%;width:0;background:linear-gradient(90deg,var(--accent-fill),var(--accent-text));border-radius:2px;transition:width 1.4s cubic-bezier(.2,.7,.2,1)}
:where(body.p-404) .divert{position:absolute;left:96px;top:188px;border:2.5px solid var(--stamp-red);color:var(--stamp-red);border-radius:4px;font-size:13px;letter-spacing:.02em;font-weight:600;padding:8px 12px;transform:rotate(-9deg);opacity:.85}
:where(body.p-404) .lug-claim{font-size:11px;margin:16px 0 0;line-height:1.8}
:where(body.p-404) .lug-claim b{font-weight:600;display:block;font-size:10px;letter-spacing:.02em;color:var(--p-soft);margin-bottom:4px}
:where(body.p-404) .lug-claim .rt{text-decoration:underline;text-underline-offset:3px;color:var(--accent-fill)}
:where(body.p-404) .lug-bar{height:28px;margin-top:16px;background:repeating-linear-gradient(90deg,
    var(--p-ink) 0 2px,transparent 2px 3px,var(--p-ink) 3px 8px,transparent 8px 12px,
    var(--p-ink) 12px 16px,transparent 16px 20px)}
:where(body.p-404) footer{position:relative;z-index:1}
/* the shared footer keeps its own costume — a 404-only uppercase/mono override made the same component render two ways and wrap at 1440 (2026-09-02 sweep) */
@media (max-width:900px){:where(body.p-404) .wrap{grid-template-columns:1fr;gap:48px;align-items:start;padding-top:48px}
:where(body.p-404) .lug{max-width:360px;margin:0 auto}}
@media (prefers-reduced-motion:reduce){:where(body.p-404) .lug-fill{transition:none}}
/* ===== EXTRACTED FROM folio/index.html (theme-swap migration; scoped body.p-folio) ===== */
body:where(.p-folio){margin:0;min-height:100vh;display:flex;align-items:center;justify-content:center;background:var(--surface-page);font-family:Georgia,serif;color:var(--accent-text);font-size:15px;letter-spacing:.04em}
@media print{:where(body.p-hire) .hire-wrap{padding:0;max-width:100%}
:where(body.p-hire) a{text-decoration:none}}
/* ===== EXTRACTED FROM screen/index.html (theme-swap migration; scoped body.p-screen) ===== */
:where(body.p-screen) .scr-wrap{max-width:var(--measure);margin:0 auto;padding:128px 24px var(--section-y)}
@media (max-width:768px){:where(body.p-screen) .scr-wrap{padding-top:104px}}
:where(body.p-screen) .scr-kicker{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);font-weight:500;letter-spacing:.02em;color:var(--accent-text);margin:0 0 20px}
:where(body.p-screen) .scr-title{font-family:var(--ff-display);font-weight:300;font-size:var(--fs-hero);color:var(--text-body);margin:0 0 24px;letter-spacing:-0.02em}
:where(body.p-screen) .scr-stand{font-family:var(--ff-display);font-weight:300;font-style:italic;font-size:var(--fs-lead);line-height:1.4;color:var(--text-body);margin:0 0 64px;max-width:46ch}
:where(body.p-screen) .scr-q{margin:0 0 64px;padding-top:32px;border-top:1px solid var(--border-strong)}
:where(body.p-screen) .scr-num{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);font-weight:500;letter-spacing:.02em;color:var(--accent-text);margin:0 0 12px}
:where(body.p-screen) .scr-q h2{font-family:var(--ff-display);font-weight:400;font-size:var(--fs-title);color:var(--text-body);margin:0 0 16px;letter-spacing:-0.01em}
:where(body.p-screen) .scr-q p{font-family:var(--ff-sans);font-size:var(--fs-body);line-height:1.7;color:var(--text-muted);margin:0 0 16px}
:where(body.p-screen) .scr-q p a{color:var(--accent-text);text-decoration:none}
:where(body.p-screen) .scr-q p a:hover{text-decoration:underline;text-underline-offset:3px}
:where(body.p-screen) .scr-receipt{font-family:var(--ff-mono);font-size:var(--fs-caption);letter-spacing:.08em;color:var(--text-muted);margin:16px 0 0}
:where(body.p-screen) .scr-receipt a{color:var(--accent-text);text-decoration:none}
:where(body.p-screen) .scr-receipt a:hover{text-decoration:underline;text-underline-offset:3px}
:where(body.p-screen) .scr-close{margin-top:8px;padding:32px;background:var(--surface-card);border:1px solid var(--border-strong);border-radius:var(--radius)}
:where(body.p-screen) .scr-close-line{font-family:var(--ff-display);font-weight:400;font-size:var(--fs-title);line-height:1.3;color:var(--text-body);margin:0 0 24px;letter-spacing:-0.01em}
:where(body.p-screen) .scr-cta-row{display:flex;flex-wrap:wrap;gap:12px;align-items:center}
:where(body.p-screen) .scr-after{font-family:var(--ff-mono);font-size:var(--fs-caption);letter-spacing:.08em;line-height:1.9;color:var(--text-muted);margin:24px 0 0}
:where(body.p-screen) .scr-after a{color:var(--accent-text);text-decoration:none}
:where(body.p-screen) .scr-after a:hover{text-decoration:underline;text-underline-offset:3px}
:where(body.p-screen) .scr-print-note{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.08em;color:var(--text-muted);margin-top:24px}
@media print{:where(body.p-screen) .scr-wrap{padding:0;max-width:100%}
:where(body.p-screen) .scr-q{page-break-inside:avoid}
:where(body.p-screen) a{text-decoration:none}}
/* --- former hover handlers (screen/index.html) --- */
.hv-screen-1:hover{background:var(--accent-text);transform:translateY(-2px)}
.hv-screen-2:hover{border-color:var(--accent-text)}
/* ===== EXTRACTED FROM case-studies/adtech.html (theme-swap migration; scoped body.p-case-studies-adtech) ===== */
:where(body.p-case-studies-adtech) .case-hero{padding:100px 24px 40px;background:var(--surface-page);border-bottom:1px solid var(--border-strong)}
:where(body.p-case-studies-adtech) .case-hero__in{max-width:1180px;margin:0 auto;display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(32px,5vw,64px);align-items:center}
:where(body.p-case-studies-adtech) .case-hero__in--solo{grid-template-columns:1fr;max-width:880px}
:where(body.p-case-studies-adtech) .case-hero__kicker{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--accent-text);margin:0 0 16px}
:where(body.p-case-studies-adtech) .case-hero h1{font-family:var(--ff-display);font-size:var(--fs-hero);font-weight:300;color:var(--text-body);margin:0 0 20px;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual;letter-spacing:-.02em}
:where(body.p-case-studies-adtech) .case-hero__hook{font-family:var(--ff-display);font-size:var(--fs-lead);font-weight:300;line-height:1.5;color:var(--text-body);margin:0 0 32px;max-width:54ch;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual}
:where(body.p-case-studies-adtech) .case-stats{display:flex;flex-wrap:wrap;gap:24px 40px}
:where(body.p-case-studies-adtech) .case-stat b{display:block;font-family:var(--ff-display);font-weight:300;font-size:var(--fs-metric);line-height:1.15;color:var(--accent-text);letter-spacing:-.01em;font-optical-sizing:auto;font-variant-numeric:tabular-nums lining-nums}
:where(body.p-case-studies-adtech) .case-stat span{display:block;margin-top:8px;font-family:var(--ff-sans);font-size:var(--fs-ui);color:var(--text-muted);line-height:1.45;max-width:22ch}
:where(body.p-case-studies-adtech) .case-hero__fig{margin:0}
:where(body.p-case-studies-adtech) .case-hero__fig img{width:100%;height:auto;border-radius:10px;border:1px solid var(--border-strong);box-shadow:var(--elev-2)}
:where(body.p-case-studies-adtech) .case-hero__fig figcaption{margin-top:12px;font-family:var(--ff-mono);font-size:var(--fs-caption);letter-spacing:.02em;color:var(--text-muted);line-height:1.5}
@media(max-width:860px){:where(body.p-case-studies-adtech) .case-hero{padding:84px 20px 24px}
:where(body.p-case-studies-adtech) .case-hero__in{grid-template-columns:1fr;gap:32px}
:where(body.p-case-studies-adtech) .case-stats{gap:20px 32px}}
:where(body.p-case-studies-adtech) .plA{width:min(840px,calc(100vw - 32px));margin:32px 50% 8px;transform:translateX(-50%);border:1px solid var(--border-strong);border-radius:10px;overflow:hidden;box-shadow:0 30px 64px rgba(0,0,0,.45);font-family:var(--ff-sans)}
:where(body.p-case-studies-adtech) .plA *{box-sizing:border-box}
:where(body.p-case-studies-adtech) .plA-chrome{display:flex;align-items:center;gap:8px;padding:8px 12px;background:#22252B;border-bottom:1px solid #2E323A}
:where(body.p-case-studies-adtech) .plA-chrome i{width:9px;height:9px;border-radius:50%;background:#3A3F48;display:inline-block}
:where(body.p-case-studies-adtech) .plA-chrome span{margin-left:8px;font-family:var(--ff-mono);font-size:10px;letter-spacing:.1em;color:#8D95A3}
:where(body.p-case-studies-adtech) .plA-app{background:#F4F5F7;color:#16181D}
:where(body.p-case-studies-adtech) .plA-bar{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;background:#fff;border-bottom:1px solid #E3E6EA;flex-wrap:wrap}
:where(body.p-case-studies-adtech) .plA-brand{font-weight:600;font-size:13px;color:#16181D}
:where(body.p-case-studies-adtech) .plA-camp{font-size:13px;color:#282B31}
:where(body.p-case-studies-adtech) .plA-camp b{color:#16181D;font-weight:600}
:where(body.p-case-studies-adtech) .plA-stage{font-family:var(--ff-mono);font-size:10px;letter-spacing:.02em;color:#B63D0B;background:#FBEAE1;border-radius:3px;padding:3px 8px;white-space:nowrap}
:where(body.p-case-studies-adtech) .plA-body{display:grid;grid-template-columns:1.5fr 1fr;gap:0}
@media(max-width:700px){:where(body.p-case-studies-adtech) .plA-body{grid-template-columns:1fr}}
:where(body.p-case-studies-adtech) .plA-main{padding:16px;border-right:1px solid #E3E6EA}
@media(max-width:700px){:where(body.p-case-studies-adtech) .plA-main{border-right:none;border-bottom:1px solid #E3E6EA}}
:where(body.p-case-studies-adtech) .plA-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:4px}
:where(body.p-case-studies-adtech) .plA-head b{font-size:16px;font-weight:600;color:#16181D}
:where(body.p-case-studies-adtech) .plA-sub{font-size:11px;color:#282B31;margin-bottom:12px}
:where(body.p-case-studies-adtech) .plA-card{background:#fff;border:1px solid #E3E6EA;border-left:3px solid #E3E6EA;border-radius:6px;padding:12px 12px;margin-bottom:8px}
:where(body.p-case-studies-adtech) .plA-card.act{border-left-color:#0E7A5F}
:where(body.p-case-studies-adtech) .plA-card.rev{border-color:#C2410C;border-left:3px solid var(--accent-fill);box-shadow:0 0 0 1px #C2410C inset}
:where(body.p-case-studies-adtech) .plA-card.ign{border-left-color:#E3E6EA;opacity:.72}
:where(body.p-case-studies-adtech) .plA-ctop{display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap;margin-bottom:4px}
:where(body.p-case-studies-adtech) .plA-rec{font-size:12.5px;font-weight:600;color:#16181D}
:where(body.p-case-studies-adtech) .plA-verb{font-family:var(--ff-mono);font-size:10px;letter-spacing:.02em;border-radius:3px;padding:4px 8px;white-space:nowrap;flex:0 0 auto}
:where(body.p-case-studies-adtech) .plA-verb.act{color:#0E7A5F;background:#E6F3EE;border:1px solid #BFDFD4}
:where(body.p-case-studies-adtech) .plA-verb.rev{color:var(--accent-fill);background:#FCF2DC;border:1px solid #EAD9B0}
:where(body.p-case-studies-adtech) .plA-verb.ign{color:#282B31;background:#EFEFEC;border:1px solid #E3E6EA}
:where(body.p-case-studies-adtech) .plA-conf{font-family:var(--ff-mono);font-size:10.5px;color:#282B31;font-variant-numeric:tabular-nums}
:where(body.p-case-studies-adtech) .plA-reason{font-size:11px;color:#282B31;line-height:1.55;margin:4px 0 0}
:where(body.p-case-studies-adtech) .plA-note{font-size:10.5px;color:#282B31;font-style:italic;margin-top:4px}
:where(body.p-case-studies-adtech) .plA-btns{display:flex;gap:8px;margin-top:8px;flex-wrap:wrap}
:where(body.p-case-studies-adtech) .plA-apply{display:inline-block;font-size:11px;font-weight:600;color:#fff;background:#0E7A5F;border-radius:4px;padding:4px 12px}
:where(body.p-case-studies-adtech) .plA-quiet{display:inline-block;font-size:11px;color:#282B31;background:#fff;border:1px solid #E3E6EA;border-radius:4px;padding:4px 12px}
:where(body.p-case-studies-adtech) .plA-ovr{display:inline-block;font-family:var(--ff-mono);font-size:9.5px;letter-spacing:.05em;color:#0E7A5F;background:#E6F3EE;border-radius:3px;padding:2px 4px;margin:2px 0 8px 12px}
:where(body.p-case-studies-adtech) .plA-foot{font-family:var(--ff-mono);font-size:10px;color:#282B31;padding-top:8px;border-top:1px solid #E3E6EA;margin-top:4px}
:where(body.p-case-studies-adtech) .plA-rail{padding:16px;background:#FBFBFC}
:where(body.p-case-studies-adtech) .plA-rl{font-family:var(--ff-mono);font-size:9.5px;letter-spacing:.02em;color:#282B31;margin-bottom:8px}
:where(body.p-case-studies-adtech) .plA-w{display:flex;align-items:center;gap:8px;font-size:11px;color:#282B31;margin-bottom:4px}
:where(body.p-case-studies-adtech) .plA-w i{height:5px;border-radius:3px;background:#C2410C;display:inline-block;flex:0 0 auto}
:where(body.p-case-studies-adtech) .plA-board{background:#fff;border:1px solid #E3E6EA;border-radius:4px;padding:12px 12px;margin-top:16px}
:where(body.p-case-studies-adtech) .plA-mono{font-family:var(--ff-mono);font-size:10px;color:#282B31;margin-bottom:8px}
:where(body.p-case-studies-adtech) .plA-cmp{display:flex;align-items:center;gap:8px;font-size:11px;color:#282B31;margin-bottom:4px}
:where(body.p-case-studies-adtech) .plA-cmp i{height:8px;border-radius:2px;display:inline-block;flex:0 0 auto}
:where(body.p-case-studies-adtech) .plA-cmp .m{background:#0E7A5F}
:where(body.p-case-studies-adtech) .plA-cmp .d{background:#C6CBD2}
:where(body.p-case-studies-adtech) .plA-bcap{font-size:10.5px;color:#282B31;font-style:italic;line-height:1.55;margin-top:8px}
:where(body.p-case-studies-adtech) .plA-caption{width:min(840px,calc(100vw - 32px));margin:0 50% 24px;transform:translateX(-50%)}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-card{max-width:480px;margin:0 auto;background:var(--surface-page);border:1px solid var(--border-strong);border-radius:6px;padding:20px;transition:border-color .25s}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-card.hot{border-color:var(--accent-fill)}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-top{display:flex;justify-content:space-between;align-items:center;gap:8px;margin-bottom:12px;flex-wrap:wrap}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-kicker{font-family:var(--ff-sans);font-size:11px;letter-spacing:0;text-transform:none;color:var(--text-muted)}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-rec{font-family:var(--ff-display);font-weight:300;font-size:18px;line-height:1.45;color:var(--text-body);margin:0 0 12px}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-kpis{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 12px}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-kpi{font-family:var(--ff-sans);font-size:12px;letter-spacing:0;border:1px solid var(--border-strong);border-radius:6px;background:#FFFFFF;padding:4px 8px;color:var(--text-muted)}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-kpi b{color:var(--accent-text);font-weight:600}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-why{background:none;border:none;box-shadow:none;padding:0;font-family:var(--ff-sans);font-size:12.5px;letter-spacing:0;text-transform:none;color:var(--accent-text);text-decoration:underline;text-underline-offset:3px}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-panel{display:none;margin:12px 0 0;border-top:1px solid var(--border-strong);padding-top:12px}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-panel.open{display:block}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-sig{display:flex;align-items:center;gap:8px;margin-bottom:8px;font-size:12.5px;color:var(--text-muted)}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-bar{flex:0 0 90px;height:5px;border-radius:3px;background:var(--border-strong);position:relative;overflow:hidden}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-bar i{position:absolute;inset:0;background:var(--accent-text);transform-origin:left;display:block}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-actions{display:flex;gap:8px;margin-top:16px;flex-wrap:wrap}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-override:hover{border-color:var(--accent-fill);color:var(--accent-text)}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-logged{display:none;font-family:var(--ff-sans);font-size:12px;color:var(--acc-copper);margin-top:12px}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-card.customized .rxa-logged{display:block}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-presets{display:flex;gap:8px;justify-content:center;margin:0 0 16px;flex-wrap:wrap}
:where(body.p-case-studies-adtech) #recon-adtech .rxa-why:focus-visible{outline:2px solid var(--accent-text);outline-offset:2px}
/* --- former hover handlers (case-studies/adtech.html) --- */
.hv-case-studies-adtech-1:hover{background:var(--accent-text);transform:translateY(-2px)}
.hv-case-studies-adtech-2:hover{background:var(--accent-text)}
.hv-case-studies-adtech-3:hover{background:var(--accent-text);color:var(--surface-page)}
/* ===== EXTRACTED FROM case-studies/fintech.html (theme-swap migration; scoped body.p-case-studies-fintech) ===== */
:where(body.p-case-studies-fintech) .case-hero{padding:100px 24px 40px;background:var(--surface-page);border-bottom:1px solid var(--border-strong)}
:where(body.p-case-studies-fintech) .case-hero__in{max-width:1180px;margin:0 auto;display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(32px,5vw,64px);align-items:center}
:where(body.p-case-studies-fintech) .case-hero__in--solo{grid-template-columns:1fr;max-width:880px}
:where(body.p-case-studies-fintech) .case-hero__kicker{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--accent-text);margin:0 0 16px}
:where(body.p-case-studies-fintech) .case-hero h1{font-family:var(--ff-display);font-size:var(--fs-hero);font-weight:300;color:var(--text-body);margin:0 0 20px;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual;letter-spacing:-.02em}
:where(body.p-case-studies-fintech) .case-hero__hook{font-family:var(--ff-display);font-size:var(--fs-lead);font-weight:300;line-height:1.5;color:var(--text-body);margin:0 0 32px;max-width:54ch;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual}
:where(body.p-case-studies-fintech) .case-stats{display:flex;flex-wrap:wrap;gap:24px 40px}
:where(body.p-case-studies-fintech) .case-stat b{display:block;font-family:var(--ff-display);font-weight:300;font-size:var(--fs-metric);line-height:1.15;color:var(--accent-text);letter-spacing:-.01em;font-optical-sizing:auto;font-variant-numeric:tabular-nums lining-nums}
:where(body.p-case-studies-fintech) .case-stat span{display:block;margin-top:8px;font-family:var(--ff-sans);font-size:var(--fs-ui);color:var(--text-muted);line-height:1.45;max-width:22ch}
:where(body.p-case-studies-fintech) .case-hero__fig{margin:0}
:where(body.p-case-studies-fintech) .case-hero__fig img{width:100%;height:auto;border-radius:10px;border:1px solid var(--border-strong);box-shadow:var(--elev-2)}
:where(body.p-case-studies-fintech) .case-hero__fig figcaption{margin-top:12px;font-family:var(--ff-mono);font-size:var(--fs-caption);letter-spacing:.02em;color:var(--text-muted);line-height:1.5}
@media(max-width:860px){:where(body.p-case-studies-fintech) .case-hero{padding:84px 20px 24px}
:where(body.p-case-studies-fintech) .case-hero__in{grid-template-columns:1fr;gap:32px}
:where(body.p-case-studies-fintech) .case-stats{gap:20px 32px}}
:where(body.p-case-studies-fintech) .plF{width:min(840px,calc(100vw - 32px));margin:32px 50% 8px;transform:translateX(-50%);border:1px solid var(--border-strong);border-radius:10px;overflow:hidden;box-shadow:0 30px 64px rgba(0,0,0,.45);font-family:var(--ff-sans)}
:where(body.p-case-studies-fintech) .plF *{box-sizing:border-box}
:where(body.p-case-studies-fintech) .plF-chrome{display:flex;align-items:center;gap:8px;padding:8px 12px;background:#22252B;border-bottom:1px solid #2E323A}
:where(body.p-case-studies-fintech) .plF-chrome i{width:9px;height:9px;border-radius:50%;background:#3A3F48;display:inline-block}
:where(body.p-case-studies-fintech) .plF-chrome span{margin-left:8px;font-family:var(--ff-mono);font-size:10px;letter-spacing:.1em;color:#8D95A3}
:where(body.p-case-studies-fintech) .plF-app{background:#F4F5F7;color:#16181D}
:where(body.p-case-studies-fintech) .plF-bar{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;background:#fff;border-bottom:1px solid #E3E6EA}
:where(body.p-case-studies-fintech) .plF-brand{font-weight:600;font-size:13px;color:#16181D}
:where(body.p-case-studies-fintech) .plF-deal{font-size:13px;color:#282B31}
:where(body.p-case-studies-fintech) .plF-deal b{color:#16181D;font-weight:600}
:where(body.p-case-studies-fintech) .plF-stage{font-family:var(--ff-mono);font-size:10px;letter-spacing:.02em;color:#063127;background:#E4F1EC;border-radius:3px;padding:3px 8px}
:where(body.p-case-studies-fintech) .plF-body{display:grid;grid-template-columns:1.5fr 1fr;gap:0}
@media(max-width:700px){:where(body.p-case-studies-fintech) .plF-body{grid-template-columns:1fr}}
:where(body.p-case-studies-fintech) .plF-main{padding:16px;border-right:1px solid #E3E6EA}
@media(max-width:700px){:where(body.p-case-studies-fintech) .plF-main{border-right:none;border-bottom:1px solid #E3E6EA}}
:where(body.p-case-studies-fintech) .plF-score{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;margin-bottom:4px}
:where(body.p-case-studies-fintech) .plF-score b{font-size:40px;font-weight:600;line-height:1;font-variant-numeric:tabular-nums}
:where(body.p-case-studies-fintech) .plF-verb{font-family:var(--ff-mono);font-size:10px;letter-spacing:.02em;color:var(--accent-fill);background:#FCF2DC;border:1px solid #EAD9B0;border-radius:3px;padding:4px 8px}
:where(body.p-case-studies-fintech) .plF-sub{font-size:11px;color:#282B31;margin-bottom:12px}
:where(body.p-case-studies-fintech) .plF-sig{display:flex;align-items:center;gap:8px;padding:8px 12px;background:#fff;border:1px solid #E3E6EA;border-radius:6px;margin-bottom:8px}
:where(body.p-case-studies-fintech) .plF-sig.sel{border-color:#063127;box-shadow:0 0 0 1px #063127 inset}
:where(body.p-case-studies-fintech) .plF-sig.abst{border-style:dashed;background:#FAFAF8}
:where(body.p-case-studies-fintech) .plF-sname{flex:1 1 auto;min-width:0;font-size:12.5px;font-weight:600;color:#16181D}
:where(body.p-case-studies-fintech) .plF-sname small{display:block;font-weight:400;font-size:11px;color:#282B31;margin-top:2px}
:where(body.p-case-studies-fintech) .plF-risk{font-family:var(--ff-mono);font-size:10px;letter-spacing:.02em;padding:3px 8px;border-radius:3px;flex:0 0 auto}
:where(body.p-case-studies-fintech) .plF-risk.hi{color:#8C2B2B;background:#F9E8E8}
:where(body.p-case-studies-fintech) .plF-risk.md{color:var(--accent-fill);background:#FCF2DC}
:where(body.p-case-studies-fintech) .plF-conf{font-family:var(--ff-mono);font-size:10.5px;color:#282B31;flex:0 0 auto;font-variant-numeric:tabular-nums}
:where(body.p-case-studies-fintech) .plF-src{font-family:var(--ff-mono);font-size:10px;color:#063127;background:#E4F1EC;border-radius:3px;padding:3px 8px;white-space:nowrap;flex:0 0 auto}
:where(body.p-case-studies-fintech) .plF-ovr{display:inline-block;font-family:var(--ff-mono);font-size:9.5px;letter-spacing:.05em;color:#0E7A5F;background:#E6F3EE;border-radius:3px;padding:2px 4px;margin:2px 0 8px 12px}
:where(body.p-case-studies-fintech) .plF-foot{font-family:var(--ff-mono);font-size:10px;color:#282B31;padding-top:8px;border-top:1px solid #E3E6EA;margin-top:4px}
:where(body.p-case-studies-fintech) .plF-rail{padding:16px;background:#FBFBFC}
:where(body.p-case-studies-fintech) .plF-rl{font-family:var(--ff-mono);font-size:9.5px;letter-spacing:.02em;color:#282B31;margin-bottom:8px}
:where(body.p-case-studies-fintech) .plF-quote{background:#fff;border:1px solid #E3E6EA;border-left:3px solid #063127;border-radius:4px;padding:12px 12px;font-size:12.5px;line-height:1.6;color:#16181D;font-style:italic}
:where(body.p-case-studies-fintech) .plF-quote mark{background:#FDF0C9;font-style:italic}
:where(body.p-case-studies-fintech) .plF-cite{font-family:var(--ff-mono);font-size:10px;color:#282B31;margin:8px 0 12px}
:where(body.p-case-studies-fintech) .plF-open{display:inline-block;font-size:11.5px;font-weight:600;color:#fff;background:#063127;border-radius:4px;padding:8px 12px}
:where(body.p-case-studies-fintech) .plF-more{display:inline-block;font-size:11px;color:#063127;margin-left:8px}
:where(body.p-case-studies-fintech) .plF-weights{margin-top:16px;border-top:1px solid #E3E6EA;padding-top:12px}
:where(body.p-case-studies-fintech) .plF-w{display:flex;align-items:center;gap:8px;font-size:11px;color:#282B31;margin-bottom:4px}
:where(body.p-case-studies-fintech) .plF-w i{height:5px;border-radius:3px;background:#063127;display:inline-block}
:where(body.p-case-studies-fintech) .plF-caption{width:min(840px,calc(100vw - 32px));margin:0 50% 24px;transform:translateX(-50%)}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-card{max-width:520px;margin:0 auto;background:var(--surface-page);border:1px solid var(--border-strong);border-radius:6px;padding:20px}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-deal{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-name{font-family:var(--ff-display);font-weight:400;font-size:17px;color:var(--text-body)}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-risk{font-family:var(--ff-mono);font-size:12px;color:var(--text-muted)}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-risk b{font-size:15px;font-weight:500;color:var(--accent-text)}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-conf{font-family:var(--ff-mono);font-size:10px;letter-spacing:.02em;text-transform:none;color:var(--status-caution);border:1px solid var(--border-strong);border-radius:2px;padding:3px 8px}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-explain{background:none;border:none;padding:0;color:var(--accent-text);text-decoration:underline;text-underline-offset:3px}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-drawer{display:none;margin-top:16px;border-top:1px solid var(--border-strong);padding-top:16px}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-drawer.open{display:block}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-sig{border:1px solid var(--border-strong);border-radius:4px;padding:12px;margin-bottom:8px}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-sig.low{border-style:dashed;opacity:.85}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-sigtop{display:flex;justify-content:space-between;align-items:center;gap:8px;margin-bottom:4px;flex-wrap:wrap}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-doc{font-family:var(--ff-mono);font-size:10px;letter-spacing:.08em;text-transform:none;color:var(--text-muted)}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-bar{flex:0 0 80px;height:5px;border-radius:3px;background:var(--border-strong);position:relative;overflow:hidden}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-bar i{position:absolute;inset:0;background:var(--accent-text);transform-origin:left;display:block}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-sig.low .rxf-bar i{background:var(--text-muted)}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-claim{font-size:12.5px;color:var(--text-muted);line-height:1.6;margin:0 0 8px}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-unsure{font-family:var(--ff-mono);font-size:10px;letter-spacing:.06em;color:var(--acc-copper);margin:0 0 8px}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-weight{display:flex;align-items:center;gap:8px}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-wlabel{font-family:var(--ff-mono);font-size:9px;letter-spacing:.02em;text-transform:none;color:var(--text-muted)}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-step{width:26px;height:26px;display:inline-flex;align-items:center;justify-content:center;background:var(--surface-page);border:1px solid var(--border-strong);border-radius:2px;color:var(--text-muted);line-height:1;transition:border-color .2s,color .2s}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-step:hover{border-color:var(--accent-fill);color:var(--accent-text)}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-wval{font-family:var(--ff-mono);font-size:13px;color:var(--text-body);min-width:14px;text-align:center}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-actions{margin-top:12px}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-override{padding:8px 12px;background:transparent;border:1px solid var(--border-strong);border-radius:2px;color:var(--text-muted);transition:border-color .2s,color .2s}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-override:hover{border-color:var(--accent-fill);color:var(--accent-text)}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-logged{display:none;font-family:var(--ff-mono);font-size:11px;color:var(--acc-copper);margin:12px 0 0}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-card.overridden .rxf-logged{display:block}
:where(body.p-case-studies-fintech) #recon-fintech .rxf-explain:focus-visible,:where(body.p-case-studies-fintech) #recon-fintech .rxf-step:focus-visible,:where(body.p-case-studies-fintech) #recon-fintech .rxf-override:focus-visible{outline:2px solid var(--accent-text);outline-offset:2px}
/* --- former hover handlers (case-studies/fintech.html) --- */
.hv-case-studies-fintech-1:hover{background:var(--accent-text);transform:translateY(-2px)}
.hv-case-studies-fintech-2:hover{background:var(--accent-text)}
.hv-case-studies-fintech-3:hover{background:var(--accent-text);color:var(--surface-page)}
/* ===== EXTRACTED FROM case-studies/o2.html (theme-swap migration; scoped body.p-case-studies-o2) ===== */
:where(body.p-case-studies-o2) .case-hero{padding:100px 24px 40px;background:var(--surface-page);border-bottom:1px solid var(--border-strong)}
:where(body.p-case-studies-o2) .case-hero__in{max-width:1180px;margin:0 auto;display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(32px,5vw,64px);align-items:center}
:where(body.p-case-studies-o2) .case-hero__in--solo{grid-template-columns:1fr;max-width:880px}
:where(body.p-case-studies-o2) .case-hero__kicker{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--accent-text);margin:0 0 16px}
:where(body.p-case-studies-o2) .case-hero h1{font-family:var(--ff-display);font-size:var(--fs-hero);font-weight:300;color:var(--text-body);margin:0 0 20px;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual;letter-spacing:-.02em}
:where(body.p-case-studies-o2) .case-hero__hook{font-family:var(--ff-display);font-size:var(--fs-lead);font-weight:300;line-height:1.5;color:var(--text-body);margin:0 0 32px;max-width:54ch;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual}
:where(body.p-case-studies-o2) .case-stats{display:flex;flex-wrap:wrap;gap:24px 40px}
:where(body.p-case-studies-o2) .case-stat b{display:block;font-family:var(--ff-display);font-weight:300;font-size:var(--fs-metric);line-height:1.15;color:var(--accent-text);letter-spacing:-.01em;font-optical-sizing:auto;font-variant-numeric:tabular-nums lining-nums}
:where(body.p-case-studies-o2) .case-stat span{display:block;margin-top:8px;font-family:var(--ff-sans);font-size:var(--fs-ui);color:var(--text-muted);line-height:1.45;max-width:22ch}
:where(body.p-case-studies-o2) .case-hero__fig{margin:0}
:where(body.p-case-studies-o2) .case-hero__fig img{width:100%;height:auto;border-radius:10px;border:1px solid var(--border-strong);box-shadow:var(--elev-2)}
:where(body.p-case-studies-o2) .case-hero__fig figcaption{margin-top:12px;font-family:var(--ff-mono);font-size:var(--fs-caption);letter-spacing:.02em;color:var(--text-muted);line-height:1.5}
@media(max-width:860px){:where(body.p-case-studies-o2) .case-hero{padding:84px 20px 24px}
:where(body.p-case-studies-o2) .case-hero__in{grid-template-columns:1fr;gap:32px}
:where(body.p-case-studies-o2) .case-stats{gap:20px 32px}}
:where(body.p-case-studies-o2) .plM{width:min(840px,calc(100vw - 32px));margin:32px 50% 8px;transform:translateX(-50%);border:1px solid var(--border-strong);border-radius:10px;overflow:hidden;box-shadow:0 30px 64px rgba(0,0,0,.45);font-family:var(--ff-sans)}
:where(body.p-case-studies-o2) .plM *{box-sizing:border-box}
:where(body.p-case-studies-o2) .plM-chrome{display:flex;align-items:center;gap:8px;padding:8px 12px;background:#22252B;border-bottom:1px solid #2E323A}
:where(body.p-case-studies-o2) .plM-chrome i{width:9px;height:9px;border-radius:50%;background:#3A3F48;display:inline-block}
:where(body.p-case-studies-o2) .plM-chrome span{margin-left:8px;font-family:var(--ff-mono);font-size:10px;letter-spacing:.1em;color:#8D95A3}
:where(body.p-case-studies-o2) .plM-stage{background:#22252B;padding:24px 16px;display:grid;grid-template-columns:repeat(3,minmax(0,250px));gap:16px;justify-content:center}
@media(max-width:700px){:where(body.p-case-studies-o2) .plM-stage{grid-template-columns:minmax(0,250px)}}
:where(body.p-case-studies-o2) .plM-phone{width:100%;max-width:250px;background:#14161B;border-radius:22px;padding:8px 8px 12px;box-shadow:0 14px 30px rgba(0,0,0,.5)}
:where(body.p-case-studies-o2) .plM-ear{width:36px;height:4px;border-radius:2px;background:#2E323A;margin:2px auto 8px}
:where(body.p-case-studies-o2) .plM-screen{background:#F4F5F7;color:#16181D;border-radius:5px;overflow:hidden;display:flex;flex-direction:column;min-height:352px}
:where(body.p-case-studies-o2) .plM-status{display:flex;justify-content:space-between;padding:4px 8px;background:#16181D;color:#9BA3B0;font-family:var(--ff-mono);font-size:9px;letter-spacing:.06em}
:where(body.p-case-studies-o2) .plM-hdr{padding:12px 12px;background:#11318F;color:#fff;font-weight:600;font-size:13.5px}
:where(body.p-case-studies-o2) .plM-body{padding:12px;flex:1 1 auto}
:where(body.p-case-studies-o2) .plM-big{font-size:31px;font-weight:600;line-height:1.1;font-variant-numeric:tabular-nums;margin:4px 0 2px}
:where(body.p-case-studies-o2) .plM-sub{font-size:10.5px;color:#282B31;margin:0 0 8px}
:where(body.p-case-studies-o2) .plM-info{font-size:10.5px;line-height:1.5;color:#0019A5;background:#E6E9F8;border-radius:4px;padding:8px 8px;margin-bottom:8px}
:where(body.p-case-studies-o2) .plM-btn{display:block;width:100%;padding:12px 0;background:#11318F;border-radius:4px;color:#fff;font-weight:600;font-size:12.5px;text-align:center;margin-bottom:8px}
:where(body.p-case-studies-o2) .plM-row{display:flex;justify-content:space-between;align-items:center;gap:8px;padding:12px 8px;background:#fff;border:1px solid #E3E6EA;border-radius:4px;font-size:12px;font-weight:600;color:#16181D;margin-bottom:4px}
:where(body.p-case-studies-o2) .plM-row i{font-style:normal;color:#6A7280}
:where(body.p-case-studies-o2) .plM-nav{display:flex;border-top:1px solid #E3E6EA;background:#fff}
:where(body.p-case-studies-o2) .plM-nav b{flex:1;padding:8px 0;text-align:center;font-family:var(--ff-mono);font-size:8.5px;letter-spacing:.02em;font-weight:400;color:#6A7280}
:where(body.p-case-studies-o2) .plM-nav b.on{color:#11318F;font-weight:700;box-shadow:inset 0 2px 0 #11318F}
:where(body.p-case-studies-o2) .plM-mlabel{display:flex;justify-content:space-between;align-items:baseline;font-size:11.5px;font-weight:600;color:#16181D;margin:8px 0 4px}
:where(body.p-case-studies-o2) .plM-mlabel small{font-weight:400;font-size:10.5px;color:#282B31;font-variant-numeric:tabular-nums}
:where(body.p-case-studies-o2) .plM-track{height:8px;border-radius:4px;background:#E3E6EA;overflow:hidden}
:where(body.p-case-studies-o2) .plM-track i{display:block;height:100%;background:#11318F;border-radius:4px}
:where(body.p-case-studies-o2) .plM-track i.mut{background:#C4C9D2}
:where(body.p-case-studies-o2) .plM-msub{font-size:9.5px;color:#282B31;margin:4px 0 0}
:where(body.p-case-studies-o2) .plM-tag{display:inline-block;font-family:var(--ff-mono);font-size:9px;letter-spacing:.14em;color:#0019A5;background:#E6E9F8;border-radius:3px;padding:3px 8px;margin-bottom:8px}
:where(body.p-case-studies-o2) .plM-otitle{font-size:14.5px;font-weight:600;line-height:1.35;margin:0 0 3px}
:where(body.p-case-studies-o2) .plM-osub{font-size:10.5px;color:#282B31;margin:0 0 12px}
:where(body.p-case-studies-o2) .plM-code{border:1.5px dashed #9BA3B0;border-radius:5px;padding:12px 8px;text-align:center;background:#fff;margin-bottom:8px}
:where(body.p-case-studies-o2) .plM-code b{display:block;font-family:var(--ff-mono);font-size:15px;letter-spacing:.08em;font-weight:600;color:#16181D}
:where(body.p-case-studies-o2) .plM-code span{display:block;font-size:9.5px;color:#282B31;margin-top:4px}
:where(body.p-case-studies-o2) .plM-match{font-family:var(--ff-mono);font-size:9px;letter-spacing:.05em;color:#6A7280;padding:8px 12px;border-top:1px solid #E3E6EA;background:#fff}
:where(body.p-case-studies-o2) .plM-caption{width:min(840px,calc(100vw - 32px));margin:0 50% 24px;transform:translateX(-50%)}
:where(body.p-case-studies-o2) #recon-o2 .rx2-grid{display:grid;grid-template-columns:1fr 1fr;gap:24px;max-width:600px;margin:0 auto}
:where(body.p-case-studies-o2) #recon-o2 .rx2-phone{border:2px solid var(--border-strong);border-radius:24px;background:var(--surface-page);padding:12px 12px 12px}
:where(body.p-case-studies-o2) #recon-o2 .rx2-ear{width:38px;height:4px;border-radius:2px;background:var(--border-strong);margin:0 auto 8px}
:where(body.p-case-studies-o2) #recon-o2 .rx2-screen{border:1px solid var(--border-strong);border-radius:4px;overflow:hidden;background:var(--surface-card);min-height:236px}
:where(body.p-case-studies-o2) #recon-o2 .rx2-chin{width:20px;height:20px;border:1px solid var(--border-strong);border-radius:50%;margin:8px auto 0}
:where(body.p-case-studies-o2) #recon-o2 .rx2-appbar{display:flex;justify-content:space-between;align-items:center;padding:8px 8px;background:var(--accent-fill);color:var(--surface-page);font-family:var(--ff-sans);font-weight:600;font-size:12px}
:where(body.p-case-studies-o2) #recon-o2 .rx2-appbar.alt{background:var(--acc-copper);color:#FEFEFE}
:where(body.p-case-studies-o2) #recon-o2 .rx2-sig4{font-size:9px;letter-spacing:2px;opacity:.8}
:where(body.p-case-studies-o2) #recon-o2 .rx2-tabs{display:flex;border-bottom:1px solid var(--border-strong)}
:where(body.p-case-studies-o2) #recon-o2 .rx2-tab{flex:1;padding:8px 0;background:var(--surface-card);border:none;border-bottom:2px solid transparent;color:var(--text-muted);transition:color .2s,border-color .2s}
:where(body.p-case-studies-o2) #recon-o2 .rx2-tab[aria-pressed="true"]{color:var(--accent-text);border-bottom-color:var(--accent-text)}
:where(body.p-case-studies-o2) #recon-o2 .rx2-view{padding:16px 12px}
:where(body.p-case-studies-o2) #recon-o2 .rx2-big{font-family:var(--ff-display);font-weight:300;font-size:30px;color:var(--text-body);margin:2px 0;font-optical-sizing:auto;font-variant-numeric:tabular-nums lining-nums}
:where(body.p-case-studies-o2) #recon-o2 .rx2-sub{font-family:var(--ff-mono);font-size:10px;color:var(--text-muted);margin:0 0 12px}
:where(body.p-case-studies-o2) #recon-o2 .rx2-row{display:flex;align-items:center;gap:8px;font-family:var(--ff-mono);font-size:10px;color:var(--text-muted);margin-bottom:8px}
:where(body.p-case-studies-o2) #recon-o2 .rx2-row span:first-child{flex:0 0 36px}
:where(body.p-case-studies-o2) #recon-o2 .rx2-track{flex:1;height:5px;border-radius:3px;background:var(--border-strong);position:relative;overflow:hidden}
:where(body.p-case-studies-o2) #recon-o2 .rx2-track i{position:absolute;top:0;left:0;bottom:0;background:var(--accent-text);display:block}
:where(body.p-case-studies-o2) #recon-o2 .rx2-pay{display:block;width:100%;padding:8px 0;background:var(--accent-text);border:none;border-radius:3px;color:var(--surface-page);font-family:var(--ff-sans)}
:where(body.p-case-studies-o2) #recon-o2 .rx2-offer{padding:16px 12px}
:where(body.p-case-studies-o2) #recon-o2 .rx2-kicker{font-family:var(--ff-mono);font-size:9px;letter-spacing:.02em;text-transform:none;color:var(--text-muted);margin:0 0 8px}
:where(body.p-case-studies-o2) #recon-o2 .rx2-otitle{font-family:var(--ff-sans);font-weight:600;font-size:14px;line-height:1.4;color:var(--text-body);margin:0 0 4px}
:where(body.p-case-studies-o2) #recon-o2 .rx2-osub{font-family:var(--ff-mono);font-size:10px;color:var(--text-muted);margin:0 0 12px}
:where(body.p-case-studies-o2) #recon-o2 .rx2-use{display:block;width:100%;padding:8px 0;background:transparent;border:1px solid var(--accent-text);border-radius:3px;color:var(--accent-text);font-family:var(--ff-sans);transition:background .2s,color .2s}
:where(body.p-case-studies-o2) #recon-o2 .rx2-use:hover{background:var(--accent-text);color:var(--surface-page)}
:where(body.p-case-studies-o2) #recon-o2 .rx2-codewrap{border:1px dashed var(--accent-fill);border-radius:3px;padding:12px;text-align:center}
:where(body.p-case-studies-o2) #recon-o2 .rx2-codelabel{font-family:var(--ff-mono);font-size:9px;letter-spacing:.02em;text-transform:none;color:var(--text-muted);margin:0 0 4px}
:where(body.p-case-studies-o2) #recon-o2 .rx2-codeval{font-family:var(--ff-mono);font-size:18px;letter-spacing:.18em;color:var(--accent-text);margin:0}
:where(body.p-case-studies-o2) #recon-o2 .rx2-label{text-align:center;font-family:var(--ff-mono);font-size:9px;letter-spacing:.02em;text-transform:none;color:var(--text-muted);margin:8px 0 0}
:where(body.p-case-studies-o2) #recon-o2 .rx2-hide{display:none}
@media (max-width:768px){:where(body.p-case-studies-o2) #recon-o2 .rx2-grid{grid-template-columns:1fr;max-width:300px}}
/* --- former hover handlers (case-studies/o2.html) --- */
.hv-case-studies-o2-1:hover{background:var(--accent-text);transform:translateY(-2px)}
.hv-case-studies-o2-2:hover{background:var(--accent-text)}
.hv-case-studies-o2-3:hover{background:var(--accent-text);color:var(--surface-page)}
/* ===== EXTRACTED FROM case-studies/orgos.html (theme-swap migration; scoped body.p-case-studies-orgos) ===== */
:where(body.p-case-studies-orgos) .case-hero{padding:100px 24px 40px;background:var(--surface-page);border-bottom:1px solid var(--border-strong)}
:where(body.p-case-studies-orgos) .case-hero__in{max-width:1180px;margin:0 auto;display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(32px,5vw,64px);align-items:center}
:where(body.p-case-studies-orgos) .case-hero__in--solo{grid-template-columns:1fr;max-width:880px}
:where(body.p-case-studies-orgos) .case-hero__kicker{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--accent-text);margin:0 0 16px}
:where(body.p-case-studies-orgos) .case-hero h1{font-family:var(--ff-display);font-size:var(--fs-hero);font-weight:300;color:var(--text-body);margin:0 0 20px;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual;letter-spacing:-.02em}
:where(body.p-case-studies-orgos) .case-hero__hook{font-family:var(--ff-display);font-size:var(--fs-lead);font-weight:300;line-height:1.5;color:var(--text-body);margin:0 0 32px;max-width:54ch;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual}
:where(body.p-case-studies-orgos) .case-stats{display:flex;flex-wrap:wrap;gap:24px 40px}
:where(body.p-case-studies-orgos) .case-stat b{display:block;font-family:var(--ff-display);font-weight:300;font-size:var(--fs-metric);line-height:1.15;color:var(--accent-text);letter-spacing:-.01em;font-optical-sizing:auto;font-variant-numeric:tabular-nums lining-nums}
:where(body.p-case-studies-orgos) .case-stat span{display:block;margin-top:8px;font-family:var(--ff-sans);font-size:var(--fs-ui);color:var(--text-muted);line-height:1.45;max-width:22ch}
:where(body.p-case-studies-orgos) .case-hero__fig{margin:0}
:where(body.p-case-studies-orgos) .case-hero__fig img{width:100%;height:auto;border-radius:10px;border:1px solid var(--border-strong);box-shadow:var(--elev-2)}
:where(body.p-case-studies-orgos) .case-hero__fig figcaption{margin-top:12px;font-family:var(--ff-mono);font-size:var(--fs-caption);letter-spacing:.02em;color:var(--text-muted);line-height:1.5}
@media(max-width:860px){:where(body.p-case-studies-orgos) .case-hero{padding:84px 20px 24px}
:where(body.p-case-studies-orgos) .case-hero__in{grid-template-columns:1fr;gap:32px}
:where(body.p-case-studies-orgos) .case-stats{gap:20px 32px}}
:where(body.p-case-studies-orgos) .plO{width:min(840px,calc(100vw - 32px));margin:32px 50% 8px;transform:translateX(-50%);border:1px solid var(--border-strong);border-radius:10px;overflow:hidden;box-shadow:0 30px 64px rgba(0,0,0,.45);font-family:var(--ff-sans)}
:where(body.p-case-studies-orgos) .plO *{box-sizing:border-box}
:where(body.p-case-studies-orgos) .plO-chrome{display:flex;align-items:center;gap:8px;padding:8px 12px;background:#22252B;border-bottom:1px solid #2E323A}
:where(body.p-case-studies-orgos) .plO-chrome i{width:9px;height:9px;border-radius:50%;background:#3A3F48;display:inline-block}
:where(body.p-case-studies-orgos) .plO-chrome span{margin-left:8px;font-family:var(--ff-mono);font-size:10px;letter-spacing:.1em;color:#8D95A3}
:where(body.p-case-studies-orgos) .plO-app{background:#F4F5F7;color:#16181D}
:where(body.p-case-studies-orgos) .plO-bar{display:flex;align-items:center;gap:12px;padding:12px 16px;background:#fff;border-bottom:1px solid #E3E6EA;flex-wrap:wrap}
:where(body.p-case-studies-orgos) .plO-brand{font-weight:600;font-size:13px;color:#16181D}
:where(body.p-case-studies-orgos) .plO-tabs{display:flex;align-items:center;gap:4px;flex-wrap:wrap}
:where(body.p-case-studies-orgos) .plO-tab{font-size:11.5px;color:#282B31;padding:4px 8px;border-radius:3px}
:where(body.p-case-studies-orgos) .plO-tab.on{color:#0A6961;background:#E2F1EF;font-weight:600}
:where(body.p-case-studies-orgos) .plO-count{margin-left:auto;font-family:var(--ff-mono);font-size:10px;letter-spacing:.06em;color:#282B31;background:#F4F5F7;border:1px solid #E3E6EA;border-radius:3px;padding:3px 8px;white-space:nowrap}
:where(body.p-case-studies-orgos) .plO-body{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;padding:16px}
@media(max-width:700px){:where(body.p-case-studies-orgos) .plO-body{grid-template-columns:1fr}}
:where(body.p-case-studies-orgos) .plO-colh{font-family:var(--ff-mono);font-size:9.5px;letter-spacing:.02em;color:#282B31;margin-bottom:8px}
:where(body.p-case-studies-orgos) .plO-colh b{color:#16181D;font-weight:600}
:where(body.p-case-studies-orgos) .plO-card{background:#fff;border:1px solid #E3E6EA;border-radius:6px;padding:12px 12px;margin-bottom:8px}
:where(body.p-case-studies-orgos) .plO-ct{font-size:12.5px;font-weight:600;color:#16181D;line-height:1.45}
:where(body.p-case-studies-orgos) .plO-cx{font-size:11px;color:#282B31;line-height:1.5;margin-top:3px}
:where(body.p-case-studies-orgos) .plO-cf{display:flex;align-items:center;gap:8px;font-family:var(--ff-mono);font-size:10px;color:#282B31;margin-top:8px;padding-top:8px;border-top:1px solid #E3E6EA}
:where(body.p-case-studies-orgos) .plO-av{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;background:#E2F1EF;color:#0A6961;font-family:var(--ff-mono);font-size:9px;font-weight:600;flex:0 0 auto}
:where(body.p-case-studies-orgos) .plO-pick{display:inline-block;font-family:var(--ff-mono);font-size:9.5px;letter-spacing:.04em;color:#0E7A5F;background:#E6F3EE;border-radius:3px;padding:3px 8px;margin-top:8px}
:where(body.p-case-studies-orgos) .plO-dec{font-family:var(--ff-mono);font-size:9.5px;letter-spacing:.02em;color:var(--accent-fill);background:#FCF2DC;border-radius:3px;padding:2px 8px}
:where(body.p-case-studies-orgos) .plO-foot{font-family:var(--ff-mono);font-size:10px;letter-spacing:.04em;color:#282B31;background:#fff;border-top:1px solid #E3E6EA;padding:12px 16px;text-align:center}
:where(body.p-case-studies-orgos) .plO-caption{width:min(840px,calc(100vw - 32px));margin:0 50% 24px;transform:translateX(-50%)}
:where(body.p-case-studies-orgos) #recon-orgos .rxo-toggle{display:flex;gap:8px;margin-bottom:12px;flex-wrap:wrap}
:where(body.p-case-studies-orgos) #recon-orgos .rxo-mode{padding:8px 12px;background:var(--surface-page);border:1px solid var(--border-strong);border-radius:2px;color:var(--text-muted);transition:border-color .2s,color .2s}
:where(body.p-case-studies-orgos) #recon-orgos .rxo-mode[aria-pressed="true"]{border-color:var(--accent-text);color:var(--accent-text)}
:where(body.p-case-studies-orgos) #recon-orgos .rxo-note{min-height:18px;font-family:var(--ff-mono);font-size:11px;color:var(--acc-copper);margin:0 0 12px}
:where(body.p-case-studies-orgos) #recon-orgos .rxo-board{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}
:where(body.p-case-studies-orgos) #recon-orgos .rxo-col{border:1px solid var(--border-strong);border-radius:4px;background:var(--surface-page);padding:12px;min-height:120px}
:where(body.p-case-studies-orgos) #recon-orgos .rxo-colh{font-family:var(--ff-mono);font-size:9px;letter-spacing:.02em;text-transform:none;color:var(--text-muted);margin:0 0 8px}
:where(body.p-case-studies-orgos) #recon-orgos .rxo-chip{position:relative;display:block;width:100%;text-align:left;background:var(--surface-card);border:1px solid var(--border-strong);border-radius:4px;padding:8px 12px;margin-bottom:8px;color:var(--text-muted);line-height:1.5}
:where(body.p-case-studies-orgos) #recon-orgos button.rxo-chip{cursor:pointer;transition:border-color .2s}
:where(body.p-case-studies-orgos) #recon-orgos button.rxo-chip:not([disabled]):hover{border-color:var(--accent-fill)}
:where(body.p-case-studies-orgos) #recon-orgos .rxo-chip b{display:block;font-family:var(--ff-sans);color:var(--text-body);margin-bottom:4px}
:where(body.p-case-studies-orgos) #recon-orgos .rxo-meta{display:flex;align-items:center;gap:8px;font-family:var(--ff-mono);font-size:10px;color:var(--text-muted)}
:where(body.p-case-studies-orgos) #recon-orgos .rxo-own{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;border:1px solid var(--border-strong);font-family:var(--ff-mono);font-size:9px;color:var(--accent-text);transition:filter .2s}
:where(body.p-case-studies-orgos) #recon-orgos.rxo-locked .rxo-own{filter:blur(3px)}
:where(body.p-case-studies-orgos) #recon-orgos .rxo-lock{display:none;position:absolute;top:8px;right:10px;font-size:10px;opacity:.8}
:where(body.p-case-studies-orgos) #recon-orgos.rxo-locked .rxo-lock{display:block}
:where(body.p-case-studies-orgos) #recon-orgos .rxo-chip.rxo-moved{border-color:var(--accent-fill)}
:where(body.p-case-studies-orgos) #recon-orgos .rxo-mode:focus-visible,:where(body.p-case-studies-orgos) #recon-orgos button.rxo-chip:focus-visible{outline:2px solid var(--accent-text);outline-offset:2px}
@media (max-width:768px){:where(body.p-case-studies-orgos) #recon-orgos .rxo-board{grid-template-columns:1fr}
:where(body.p-case-studies-orgos) #recon-orgos .rxo-col{min-height:0}}
/* --- former hover handlers (case-studies/orgos.html) --- */
.hv-case-studies-orgos-1:hover{background:var(--accent-text);transform:translateY(-2px)}
.hv-case-studies-orgos-2:hover{background:var(--accent-text)}
.hv-case-studies-orgos-3:hover{background:var(--accent-text);color:var(--surface-page)}
/* ===== EXTRACTED FROM case-studies/ptc.html (theme-swap migration; scoped body.p-case-studies-ptc) ===== */
:where(body.p-case-studies-ptc) .case-hero{padding:100px 24px 40px;background:var(--surface-page);border-bottom:1px solid var(--border-strong)}
:where(body.p-case-studies-ptc) .case-hero__in{max-width:1180px;margin:0 auto;display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(32px,5vw,64px);align-items:center}
:where(body.p-case-studies-ptc) .case-hero__kicker{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--accent-text);margin:0 0 16px}
:where(body.p-case-studies-ptc) .case-hero h1{font-family:var(--ff-display);font-size:var(--fs-hero);font-weight:300;color:var(--text-body);margin:0 0 20px;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual;letter-spacing:-.02em}
:where(body.p-case-studies-ptc) .case-hero__hook{font-family:var(--ff-display);font-size:var(--fs-lead);font-weight:300;line-height:1.5;color:var(--text-body);margin:0 0 32px;max-width:48ch;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual}
:where(body.p-case-studies-ptc) .case-stats{display:flex;flex-wrap:wrap;gap:24px 40px}
:where(body.p-case-studies-ptc) .case-stat b{display:block;font-family:var(--ff-display);font-weight:300;font-size:var(--fs-metric);line-height:1.15;color:var(--accent-text);letter-spacing:-.01em;font-optical-sizing:auto;font-variant-numeric:tabular-nums lining-nums}
:where(body.p-case-studies-ptc) .case-stat span{display:block;margin-top:8px;font-family:var(--ff-sans);font-size:var(--fs-ui);color:var(--text-muted);line-height:1.45;max-width:20ch}
:where(body.p-case-studies-ptc) .case-hero__fig{margin:0}
:where(body.p-case-studies-ptc) .case-hero__fig img{width:100%;height:auto;border-radius:10px;border:1px solid var(--border-strong);box-shadow:var(--elev-2)}
:where(body.p-case-studies-ptc) .case-hero__fig figcaption{margin-top:12px;font-family:var(--ff-mono);font-size:var(--fs-caption);letter-spacing:.02em;color:var(--text-muted);line-height:1.5}
@media(max-width:860px){:where(body.p-case-studies-ptc) .case-hero{padding:84px 20px 24px}
:where(body.p-case-studies-ptc) .case-hero__in{grid-template-columns:1fr;gap:32px}
:where(body.p-case-studies-ptc) .case-stats{gap:20px 32px}}
:where(body.p-case-studies-ptc) .plP{width:min(840px,calc(100vw - 32px));margin:32px 50% 8px;transform:translateX(-50%);display:grid;grid-template-columns:1fr 1fr;gap:12px}
@media(max-width:700px){:where(body.p-case-studies-ptc) .plP{grid-template-columns:1fr}}
:where(body.p-case-studies-ptc) .plP *{box-sizing:border-box}
:where(body.p-case-studies-ptc) .plP-frame{border:1px solid var(--border-strong);border-radius:9px;overflow:hidden;box-shadow:0 22px 48px rgba(0,0,0,.4);font-family:var(--ff-sans)}
:where(body.p-case-studies-ptc) .plP-chrome{display:flex;align-items:center;gap:8px;padding:8px 12px;background:#22252B;border-bottom:1px solid #2E323A}
:where(body.p-case-studies-ptc) .plP-chrome i{width:8px;height:8px;border-radius:50%;background:#3A3F48;display:inline-block}
:where(body.p-case-studies-ptc) .plP-chrome span{margin-left:8px;font-family:var(--ff-mono);font-size:10px;letter-spacing:.04em;color:#8D95A3;text-transform:none}
:where(body.p-case-studies-ptc) .plP-win{border:1px solid var(--border-strong);border-radius:8px;overflow:hidden;box-shadow:0 12px 24px rgba(0,0,0,.35);background:#F4F5F7}
:where(body.p-case-studies-ptc) .plP-winb{display:flex;justify-content:space-between;align-items:baseline;gap:8px;padding:12px;font-size:12.5px;color:#16181D}
:where(body.p-case-studies-ptc) .plP-winb b{font-weight:600}
:where(body.p-case-studies-ptc) .plP-winb span{font-size:11px;color:#282B31;white-space:nowrap}
:where(body.p-case-studies-ptc) .plP-caption{width:min(840px,calc(100vw - 32px));margin:0 50% 40px;transform:translateX(-50%)}
:where(body.p-case-studies-ptc) #recon-ptc .rxp-toggle{display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap}
:where(body.p-case-studies-ptc) #recon-ptc .rxp-mode{padding:8px 12px;background:var(--surface-page);border:1px solid var(--border-strong);border-radius:2px;color:var(--text-muted);transition:border-color .2s,color .2s}
:where(body.p-case-studies-ptc) #recon-ptc .rxp-mode[aria-pressed="true"]{border-color:var(--accent-text);color:var(--accent-text)}
:where(body.p-case-studies-ptc) #recon-ptc .rxp-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(150px,100%),1fr));gap:8px}
:where(body.p-case-studies-ptc) #recon-ptc .rxp-tile{padding:16px 12px;background:var(--surface-page);border:1px solid var(--border-strong);border-radius:4px;transition:opacity .25s,border-color .25s}
:where(body.p-case-studies-ptc) #recon-ptc .rxp-tile b{display:block;font-family:var(--ff-display);font-weight:400;font-size:15px;color:var(--text-body);margin-bottom:4px}
:where(body.p-case-studies-ptc) #recon-ptc .rxp-tile span{font-family:var(--ff-mono);font-size:9px;letter-spacing:.02em;text-transform:none;color:var(--text-muted)}
:where(body.p-case-studies-ptc) #recon-ptc.licensed .rxp-tile[data-owned="1"]{border-color:var(--accent-fill)}
:where(body.p-case-studies-ptc) #recon-ptc.licensed .rxp-tile[data-owned="1"] span{color:var(--accent-text)}
:where(body.p-case-studies-ptc) #recon-ptc.licensed .rxp-tile[data-owned="0"]{display:none}
:where(body.p-case-studies-ptc) #recon-ptc .rxp-explore{display:none;margin-top:12px;font-family:var(--ff-mono);font-size:11px;letter-spacing:.08em;text-transform:none;color:var(--text-muted)}
:where(body.p-case-studies-ptc) #recon-ptc.licensed .rxp-explore{display:block}
/* --- former hover handlers (case-studies/ptc.html) --- */
.hv-case-studies-ptc-1:hover{background:var(--accent-text);transform:translateY(-2px)}
.hv-case-studies-ptc-2:hover{background:var(--accent-text)}
.hv-case-studies-ptc-3:hover{background:var(--accent-text);color:var(--surface-page)}
/* ===== EXTRACTED FROM case-studies/vc-diligence.html (theme-swap migration; scoped body.p-case-studies-vc-diligence) ===== */
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .case-hero{padding:100px 24px 40px;background:var(--surface-page);border-bottom:1px solid var(--border-strong)}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .case-hero__in{max-width:1180px;margin:0 auto;display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(32px,5vw,64px);align-items:center}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .case-hero__in--solo{grid-template-columns:1fr;max-width:880px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .case-hero__kicker{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--accent-text);margin:0 0 16px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .case-hero h1{font-family:var(--ff-display);font-size:var(--fs-hero);font-weight:300;color:var(--text-body);margin:0 0 20px;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual;letter-spacing:-.02em}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .case-hero__hook{font-family:var(--ff-display);font-size:var(--fs-lead);font-weight:300;line-height:1.5;color:var(--text-body);margin:0 0 32px;max-width:54ch;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .case-stats{display:flex;flex-wrap:wrap;gap:24px 40px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .case-stat b{display:block;font-family:var(--ff-display);font-weight:300;font-size:var(--fs-metric);line-height:1.15;color:var(--accent-text);letter-spacing:-.01em;font-optical-sizing:auto;font-variant-numeric:tabular-nums lining-nums}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .case-stat span{display:block;margin-top:8px;font-family:var(--ff-sans);font-size:var(--fs-ui);color:var(--text-muted);line-height:1.45;max-width:22ch}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .case-hero__fig{margin:0}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .case-hero__fig img{width:100%;height:auto;border-radius:10px;border:1px solid var(--border-strong);box-shadow:var(--elev-2)}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .case-hero__fig figcaption{margin-top:12px;font-family:var(--ff-mono);font-size:var(--fs-caption);letter-spacing:.02em;color:var(--text-muted);line-height:1.5}
@media(max-width:860px){:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .case-hero{padding:84px 20px 24px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .case-hero__in{grid-template-columns:1fr;gap:32px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .case-stats{gap:20px 32px}}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV{width:min(840px,calc(100vw - 32px));margin:32px 50% 8px;transform:translateX(-50%);border:1px solid var(--border-strong);border-radius:10px;overflow:hidden;box-shadow:0 30px 64px rgba(0,0,0,.45);font-family:var(--ff-sans)}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV *{box-sizing:border-box}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-chrome{display:flex;align-items:center;gap:8px;padding:8px 12px;background:#22252B;border-bottom:1px solid #2E323A}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-chrome i{width:9px;height:9px;border-radius:50%;background:#3A3F48;display:inline-block}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-chrome span{margin-left:8px;font-family:var(--ff-mono);font-size:10px;letter-spacing:.1em;color:#8D95A3}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-app{background:#F4F5F7;color:#16181D}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-bar{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;background:#fff;border-bottom:1px solid #E3E6EA}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-brand{font-weight:600;font-size:13px;color:#16181D}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-deal{font-size:13px;color:#464C56}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-deal b{color:#16181D;font-weight:600}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-elapsed{font-family:var(--ff-mono);font-size:10px;letter-spacing:.02em;color:#2E2570;background:#ECEAF8;border-radius:3px;padding:3px 8px;white-space:nowrap}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-body{display:grid;grid-template-columns:1.5fr 1fr;gap:0}
@media(max-width:700px){:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-body{grid-template-columns:1fr}}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-main{padding:16px;border-right:1px solid #E3E6EA}
@media(max-width:700px){:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-main{border-right:none;border-bottom:1px solid #E3E6EA}}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-vlab{font-family:var(--ff-mono);font-size:9.5px;letter-spacing:.02em;color:#464C56;margin-bottom:4px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-verdict{font-family:var(--ff-display);font-weight:300;font-size:26px;line-height:1.25;color:#16181D;margin-bottom:4px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-verdict em{font-style:normal;color:var(--accent-fill)}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-sub{font-size:11px;color:#464C56;margin-bottom:12px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-sig{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:8px 12px;background:#fff;border:1px solid #E3E6EA;border-radius:6px;margin-bottom:8px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-sig.sel{border-color:#2E2570;box-shadow:0 0 0 1px #2E2570 inset}
/* The diligence dossier at phone widths (2026-08-16). Two grid/flex min-content traps stacked:
   the .plV-body columns collapse to one track at 700px but a grid item will not shrink below its
   min-content unless min-width is 0, so .plV-main stayed 439px inside a 277px plate; and each
   signal row is a flex line that could not wrap. The plate has overflow-x:auto so the PAGE never
   scrolled — the damage was invisible to the overflow gate and showed up instead as nine phantom
   contrast failures, because the audit was sampling pixels of text clipped at the plate edge.
   Measured: 439 -> 382 (min-width) -> 277 (wrap), against a 279px plate. */
@media(max-width:700px){:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-body > *{min-width:0}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-sig{flex-wrap:wrap}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-sig > *{min-width:0}}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-sname{flex:1 1 auto;min-width:150px;/* a floor, not 0: long chips crushed rows C-09/D-05 into one-word towers (2026-09-02 sweep) */font-size:12.5px;font-weight:600;color:#16181D}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-sname small{display:block;font-weight:400;font-size:11px;color:#464C56;margin-top:2px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-st{font-family:var(--ff-mono);font-size:10px;letter-spacing:.02em;padding:3px 8px;border-radius:3px;flex:0 0 auto}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-st.clear{color:#0E7A5F;background:#E6F3EE}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-st.watch{color:var(--accent-fill);background:#FCF2DC}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-conf{font-family:var(--ff-mono);font-size:10.5px;color:#464C56;flex:0 0 auto;font-variant-numeric:tabular-nums}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-src{font-family:var(--ff-mono);font-size:10px;color:#2E2570;background:#ECEAF8;border-radius:3px;padding:3px 8px;white-space:nowrap;flex:0 0 auto}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-foot{font-family:var(--ff-mono);font-size:10px;color:#464C56;padding-top:8px;border-top:1px solid #E3E6EA;margin-top:4px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-rail{padding:16px;background:#FBFBFC}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-rl{font-family:var(--ff-mono);font-size:9.5px;letter-spacing:.02em;color:#464C56;margin-bottom:8px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-quote{background:#fff;border:1px solid #E3E6EA;border-left:3px solid #2E2570;border-radius:4px;padding:12px 12px;font-size:12.5px;line-height:1.6;color:#16181D;font-style:italic}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-quote mark{background:#FDF0C9;font-style:italic}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-cite{font-family:var(--ff-mono);font-size:10px;color:#464C56;margin:8px 0 12px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-open{display:inline-block;font-size:11.5px;font-weight:600;color:#fff;background:#2E2570;border-radius:4px;padding:8px 12px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-more{display:inline-block;font-size:11px;color:#2E2570;margin-left:8px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-signoff{margin-top:16px;border-top:1px solid #E3E6EA;padding-top:12px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-signed{display:inline-block;font-family:var(--ff-mono);font-size:10.5px;letter-spacing:.02em;color:#0E7A5F;background:#E6F3EE;border:1px solid #0E7A5F;border-radius:4px;padding:8px 12px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-cond{font-size:11px;color:#464C56;margin-top:8px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) .plV-caption{width:min(840px,calc(100vw - 32px));margin:0 50% 24px;transform:translateX(-50%)}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-card{max-width:520px;margin:0 auto;background:var(--surface-page);border:1px solid var(--border-strong);border-radius:6px;padding:20px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-vlabel{font-family:var(--ff-mono);font-size:9px;letter-spacing:.02em;text-transform:none;color:var(--text-muted);margin:0 0 4px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-vtext{font-family:var(--ff-display);font-weight:300;font-size:19px;line-height:1.4;color:var(--text-body);margin:0 0 16px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-vtext span{color:var(--accent-text)}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-row{border-top:1px solid var(--border-strong)}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-sig{display:flex;justify-content:space-between;align-items:center;gap:8px;width:100%;text-align:left;background:none;border:none;padding:12px 2px;color:var(--text-body);font-family:var(--ff-sans);transition:color .2s;line-height:1.4}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-sig:hover{color:var(--accent-text)}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-right{display:inline-flex;align-items:center;gap:8px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-st{font-family:var(--ff-mono);font-size:9px;letter-spacing:.02em;text-transform:none;color:var(--text-muted);border:1px solid var(--border-strong);border-radius:2px;padding:2px 8px;line-height:1.4}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-st.watch{color:var(--status-caution);border-color:var(--status-caution)}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-chev{font-family:var(--ff-mono);color:var(--accent-text);transition:transform .2s;display:inline-block}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-sig[aria-expanded="true"] .rxv-chev{transform:rotate(45deg)}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-trail{display:none;padding:0 2px 12px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-trail.open{display:block}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-ev{font-size:12.5px;color:var(--text-muted);line-height:1.6;margin:0 0 4px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-cite{font-family:var(--ff-mono);font-size:10px;letter-spacing:.04em;color:var(--text-muted);margin:0}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-foot{display:flex;align-items:center;gap:12px;margin-top:16px;flex-wrap:wrap;border-top:1px solid var(--border-strong);padding-top:16px}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-sign{padding:8px 16px;background:transparent;border:1px solid var(--accent-fill);border-radius:2px;color:var(--accent-text);transition:border-color .2s,color .2s}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-sign[disabled]{border-color:var(--border-strong);color:var(--text-muted);cursor:not-allowed}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-sign.rxv-signed{border-color:var(--accent-text);color:var(--accent-text);cursor:default}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-hint{font-family:var(--ff-mono);font-size:10px;letter-spacing:.06em;color:var(--text-muted);margin:0}
:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-sig:focus-visible,:where(body.p-case-studies-vc-diligence,body.p-case-studies-planit) #recon-vc .rxv-sign:focus-visible{outline:2px solid var(--accent-text);outline-offset:2px}
/* --- former hover handlers (case-studies/vc-diligence.html) --- */
.hv-case-studies-vc-diligence-1:hover{background:var(--accent-text);transform:translateY(-2px)}
.hv-case-studies-vc-diligence-2:hover{background:var(--accent-text)}
.hv-case-studies-vc-diligence-3:hover{background:var(--accent-text);color:var(--surface-page)}
/* ===== EXTRACTED FROM lab/index.html (theme-swap migration; scoped body.p-lab) ===== */
:where(body.p-lab,body.p-fit) .lab-wrap{max-width:var(--inner-max);margin:0 auto;padding:0 var(--page-x)}
:where(body.p-lab,body.p-fit) .lab-hero{padding-top:128px}
:where(body.p-lab,body.p-fit) .lab-kicker{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);font-weight:500;letter-spacing:.02em;color:var(--accent-text);margin:0 0 16px}
:where(body.p-lab,body.p-fit) .lab-lede{font-size:var(--fs-lead);line-height:1.7;color:var(--text-muted);max-width:var(--measure)}
:where(body.p-lab,body.p-fit) .lab-lede strong{color:var(--text-body);font-weight:400}
:where(body.p-lab,body.p-fit) .lab-note{border-left:2px solid var(--accent-fill);padding:12px 0 12px 20px;margin:32px 0 0;font-size:var(--fs-ui);line-height:1.7;color:var(--text-muted);max-width:var(--measure)}
:where(body.p-lab,body.p-fit) .lab-note b{color:var(--text-body);font-weight:600}
:where(body.p-lab,body.p-fit) .lab-body{font-size:var(--fs-body);line-height:1.7;color:var(--text-muted);max-width:var(--measure)}
:where(body.p-lab,body.p-fit) .lab-body p{margin:0 0 16px}
:where(body.p-lab,body.p-fit) .lab-body p:last-child{margin-bottom:0}
:where(body.p-lab,body.p-fit) .lab-body code{font-family:var(--ff-mono);font-size:0.9em;color:var(--accent-text)}
:where(body.p-lab,body.p-fit) .lab-cards{display:grid;grid-template-columns:repeat(auto-fit, minmax(min(300px,100%),1fr));gap:20px;margin-top:32px}
:where(body.p-lab,body.p-fit) .lab-card{display:flex;flex-direction:column;border:1px solid var(--border-strong);border-radius:var(--radius);background:var(--surface-card);padding:24px 24px 24px;text-decoration:none;transition:border-color .18s var(--ease-out), transform .18s var(--ease-out)}
:where(body.p-lab,body.p-fit) .lab-card:hover{border-color:var(--accent);transform:translateY(-2px)}
:where(body.p-lab,body.p-fit) .lab-card:focus-visible{outline:2px solid var(--accent-text);outline-offset:3px}
:where(body.p-lab,body.p-fit) .lab-num{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.12em;color:var(--accent-text);margin:0 0 12px}
:where(body.p-lab,body.p-fit) .lab-card h3{font-family:var(--ff-mono);font-size:var(--fs-ui);font-weight:500;color:var(--text-body);margin:0 0 8px;letter-spacing:.01em}
:where(body.p-lab,body.p-fit) .lab-card p{font-size:var(--fs-ui);line-height:1.7;color:var(--text-muted);margin:0 0 16px;flex:1}
:where(body.p-lab,body.p-fit) .lab-tags{display:flex;flex-wrap:wrap;gap:4px;margin:0 0 16px}
:where(body.p-lab,body.p-fit) .lab-tags span{font-family:var(--ff-mono);font-size:var(--fs-micro);letter-spacing:.02em;color:var(--text-muted);border:1px solid var(--border-strong);border-radius:2px;padding:4px 8px}
:where(body.p-lab,body.p-fit) .lab-go{font-family:var(--ff-mono);font-size:var(--fs-caption);color:var(--accent-text);letter-spacing:.03em}
/* ONE definition for every lab page and /fit/. This component was written out FOUR times —
   once each for p-lab/p-fit, p-lab-eval, p-lab-loop and p-lab-teardown, byte-identical — and
   p-lab-plugin was never added, so lab/plugin.html rendered the same markup as a bare
   underlined link (height 19.5px, no box) while the other four pages rendered a 31.5px
   button. A component copied per page is not a system, and the page that forgets a copy is
   the page that looks wrong. The attribute match covers every current and future p-lab-* page. */
:where(body[class*="p-lab"],body.p-fit) .lab-links{display:flex;flex-wrap:wrap;gap:12px;margin-top:24px}
:where(body[class*="p-lab"],body.p-fit) .lab-links a:not(.cta){font-family:var(--ff-mono);font-size:var(--fs-caption);letter-spacing:.04em;color:var(--accent-text);text-decoration:none;border:1px solid var(--accent-fill);border-radius:var(--radius);padding:8px 16px;transition:background .15s, color .15s, border-color .15s}
:where(body[class*="p-lab"],body.p-fit) .lab-links a:not(.cta):hover{background:var(--accent-text);color:var(--surface-page)}
@media (prefers-reduced-motion: reduce){:where(body.p-lab,body.p-fit) .lab-card{transition:none}
:where(body.p-lab,body.p-fit) .lab-card:hover{transform:none}}
:where(body.p-lab,body.p-fit) .ev-tiers{margin:16px 0 0}
:where(body.p-lab,body.p-fit) .ev-tiers dt{font-family:var(--ff-mono);font-size:12px;letter-spacing:.02em;color:var(--accent-text);margin-top:16px}
:where(body.p-lab,body.p-fit) .ev-tiers dd{margin:4px 0 0;padding-left:16px;border-left:1px solid var(--border-strong)}
/* ===== EXTRACTED FROM lab/eval.html (theme-swap migration; scoped body.p-lab-eval) ===== */
:where(body.p-lab-eval) .lab-wrap{max-width:var(--inner-max);margin:0 auto;padding:0 var(--page-x)}
:where(body.p-lab-eval) .lab-hero{padding-top:128px}
:where(body.p-lab-eval) .lab-kicker{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);font-weight:500;letter-spacing:.02em;color:var(--accent-text);margin:0 0 16px}
:where(body.p-lab-eval) .lab-lede{font-size:var(--fs-lead);line-height:1.7;color:var(--text-muted);max-width:var(--measure)}
:where(body.p-lab-eval) .lab-lede strong{color:var(--text-body);font-weight:400}
:where(body.p-lab-eval) .lab-note{border-left:2px solid var(--accent-fill);padding:12px 0 12px 20px;margin:32px 0 0;font-size:var(--fs-ui);line-height:1.7;color:var(--text-muted);max-width:var(--measure)}
:where(body.p-lab-eval) .lab-note b{color:var(--text-body);font-weight:600}
:where(body.p-lab-eval) .lint-grid{display:grid;grid-template-columns:1fr 1fr;gap:24px;margin-top:24px;align-items:start}
@media (max-width: 860px){:where(body.p-lab-eval) .lint-grid{grid-template-columns:1fr}}
:where(body.p-lab-eval) .lint-panel{border:1px solid var(--border-strong);border-radius:var(--radius);background:var(--surface-card);padding:20px 24px;min-width:0}
:where(body.p-lab-eval) .lint-panel h3{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);font-weight:500;letter-spacing:.02em;color:var(--text-muted);margin:0 0 12px}
:where(body.p-lab-eval) .lint-seg{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:12px}
:where(body.p-lab-eval) .lint-seg button{flex:1 1 auto;padding:8px 8px;font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--text-muted);background:transparent;border:1px solid var(--border-strong);border-radius:var(--radius);cursor:pointer;transition:border-color .15s, color .15s, background .15s}
:where(body.p-lab-eval) .lint-seg button:hover{border-color:var(--accent-text);color:var(--text-body)}
:where(body.p-lab-eval) .lint-seg button.on{background:var(--accent-text);color:var(--surface-page);border-color:var(--accent-text)}
:where(body.p-lab-eval) .lint-seg button:focus-visible,:where(body.p-lab-eval) #lint-input:focus-visible{outline:2px solid var(--accent-text);outline-offset:2px}
:where(body.p-lab-eval) .act-cream #lint-input,:where(body.p-lab-eval) .act-cream .lint-panel input{background:var(--surface-card)}
:where(body.p-lab-eval) #lint-input{width:100%;min-height:210px;resize:vertical;background:var(--surface-sunken);color:var(--text-body);border:1px solid var(--border-strong);border-radius:var(--radius);padding:12px 16px;font-family:var(--ff-sans);font-size:var(--fs-ui);line-height:1.65}
:where(body.p-lab-eval) .lint-hint{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--text-muted);margin:12px 0 0}
:where(body.p-lab-eval) .lint-verdict{font-family:var(--ff-display);font-style:italic;font-weight:300;font-size:32px;line-height:1.15;margin-bottom:4px;display:block}
:where(body.p-lab-eval) .lint-verdict.is-bad{color:var(--status-negative)}
:where(body.p-lab-eval) .lint-verdict.is-mid{color:var(--status-caution)}
:where(body.p-lab-eval) .lint-verdict.is-good{color:var(--status-positive)}
:where(body.p-lab-eval) .lint-verdict.is-empty{color:var(--text-muted)}
:where(body.p-lab-eval) .lint-sub{font-family:var(--ff-mono);font-size:var(--fs-caption);color:var(--text-muted);margin:0 0 16px}
:where(body.p-lab-eval) .lint-stats{display:grid;grid-template-columns:repeat(3, 1fr);gap:12px;padding:12px 0;border-top:1px solid var(--border-strong);border-bottom:1px solid var(--border-strong);margin-bottom:16px}
:where(body.p-lab-eval) .lint-stat b{display:block;font-family:var(--ff-display);font-weight:300;font-size:var(--fs-metric-sm);color:var(--accent-text);line-height:1;font-variant-numeric:tabular-nums}
:where(body.p-lab-eval) .lint-stat span{display:block;font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--text-muted);margin-top:8px}
:where(body.p-lab-eval) .lint-findings{list-style:none;padding:0;margin:0}
:where(body.p-lab-eval) .lint-findings li{padding:12px 0;border-bottom:1px solid var(--border-strong)}
:where(body.p-lab-eval) .lint-findings li:last-child{border-bottom:none}
:where(body.p-lab-eval) .lint-rule{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;display:inline-block;padding:3px 8px;border-radius:2px;margin-bottom:8px}
:where(body.p-lab-eval) .sev-high{background:var(--status-neg-bg);color:var(--status-negative)}
:where(body.p-lab-eval) .sev-medium{background:var(--status-cau-bg);color:var(--status-caution)}
:where(body.p-lab-eval) .lint-excerpt{display:block;font-family:var(--ff-mono);font-size:var(--fs-caption);line-height:1.6;color:var(--text-body);margin:0 0 4px;word-break:break-word}
:where(body.p-lab-eval) .lint-why{display:block;font-size:var(--fs-ui);line-height:1.6;color:var(--text-muted);margin:0}
:where(body.p-lab-eval) .lint-clean{font-size:var(--fs-ui);line-height:1.7;color:var(--text-muted);margin:0}
:where(body.p-lab-eval) .rule-list{list-style:none;padding:0;margin:0;display:grid;grid-template-columns:repeat(auto-fit, minmax(min(280px,100%),1fr));gap:16px 32px}
:where(body.p-lab-eval) .rule-list li{font-size:var(--fs-ui);line-height:1.7;color:var(--text-muted)}
:where(body.p-lab-eval) .rule-list code{font-family:var(--ff-mono);font-size:var(--fs-caption);color:var(--accent-text);display:block;margin-bottom:4px}
/* ===== EXTRACTED FROM lab/loop.html (theme-swap migration; scoped body.p-lab-loop) ===== */
:where(body.p-lab-loop) .lab-wrap{max-width:var(--inner-max);margin:0 auto;padding:0 var(--page-x)}
:where(body.p-lab-loop) .lab-hero{padding-top:128px}
:where(body.p-lab-loop) .lab-kicker{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);font-weight:500;letter-spacing:.02em;color:var(--accent-text);margin:0 0 16px}
:where(body.p-lab-loop) .lab-lede{font-size:var(--fs-lead);line-height:1.7;color:var(--text-muted);max-width:var(--measure)}
:where(body.p-lab-loop) .lab-lede strong{color:var(--text-body);font-weight:400}
:where(body.p-lab-loop) .lab-note{border-left:2px solid var(--accent-fill);padding:12px 0 12px 20px;margin:32px 0 0;font-size:var(--fs-ui);line-height:1.7;color:var(--text-muted);max-width:var(--measure)}
:where(body.p-lab-loop) .lab-note b{color:var(--text-body);font-weight:600}
:where(body.p-lab-loop,body.p-lab-plugin,body.p-lab) pre.lab-code{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:var(--radius);padding:16px 20px;overflow-x:auto;margin:0}
:where(body.p-lab-loop) pre.lab-code code{font-family:var(--ff-mono);font-size:var(--fs-caption);line-height:1.75;color:var(--text-body);white-space:pre}
:where(body.p-lab-loop) .lab-code .c{color:var(--text-muted)}
:where(body.p-lab-loop) .lab-code .k{color:var(--accent-text)}
:where(body.p-lab-loop) .lab-fn{border-top:1px solid var(--border-strong);padding-top:32px;margin-top:48px}
:where(body.p-lab-loop) .lab-fn:first-of-type{border-top:none;padding-top:0;margin-top:0}
:where(body.p-lab-loop) .lab-fn h3{font-family:var(--ff-mono);font-size:var(--fs-ui);font-weight:500;color:var(--accent-text);margin:0 0 4px;letter-spacing:.02em}
:where(body.p-lab-loop) .lab-fn .lab-pat{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--text-muted);margin:0 0 12px}
:where(body.p-lab-loop) .lab-fn p{font-size:var(--fs-body);line-height:1.7;color:var(--text-muted);max-width:var(--measure);margin:0 0 16px}
:where(body.p-lab-loop) .lab-fn p strong{color:var(--text-body);font-weight:400}
:where(body.p-lab-loop) .lab-play{display:grid;grid-template-columns:minmax(240px, 320px) 1fr;gap:0;border:1px solid var(--border-strong);border-radius:var(--radius);background:var(--surface-card);margin-top:24px;overflow:hidden}
:where(body.p-lab-loop) .lab-controls{padding:20px 24px;border-right:1px solid var(--border-strong)}
:where(body.p-lab-loop) .lab-out{padding:20px 24px;min-width:0}
@media (max-width: 720px){:where(body.p-lab-loop) .lab-play{grid-template-columns:1fr}
:where(body.p-lab-loop) .lab-controls{border-right:none;border-bottom:1px solid var(--border-strong)}}
:where(body.p-lab-loop) .lab-ctl{margin-bottom:16px}
:where(body.p-lab-loop) .lab-ctl:last-child{margin-bottom:0}
:where(body.p-lab-loop) .lab-ctl label.t-sans-ui-reset{display:inline;font-family:var(--ff-sans);font-size:var(--fs-ui);letter-spacing:0;text-transform:none;color:var(--text-body)}
:where(body.p-lab-loop) .lab-ctl label{display:block;font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--text-muted);margin-bottom:8px}
:where(body.p-lab-loop) .lab-ctl output{font-family:var(--ff-mono);font-size:var(--fs-ui);color:var(--accent-text);font-variant-numeric:tabular-nums}
:where(body.p-lab-loop) .lab-ctl input[type="range"]{width:100%;accent-color:var(--accent-text)}
:where(body.p-lab-loop) .act-cream .lab-ctl input[type="number"]{background:var(--surface-card)}
:where(body.p-lab-loop) .lab-ctl input[type="number"]{width:88px;background:var(--surface-sunken);color:var(--text-body);border:1px solid var(--border-strong);border-radius:var(--radius);padding:8px 8px;font-family:var(--ff-mono);font-size:var(--fs-caption)}
:where(body.p-lab-loop) .lab-ctl input[type="checkbox"]{accent-color:var(--accent-text);width:15px;height:15px;vertical-align:-2px}
:where(body.p-lab-loop) .lab-ctl .lab-inline{display:flex;align-items:center;gap:8px;font-size:var(--fs-ui);color:var(--text-body)}
:where(body.p-lab-loop) .lab-ctl input:focus-visible,:where(body.p-lab-loop) .lab-seg button:focus-visible{outline:2px solid var(--accent-text);outline-offset:2px}
:where(body.p-lab-loop) .lab-seg{display:flex;flex-wrap:wrap;gap:4px}
:where(body.p-lab-loop) .lab-seg button{flex:1 1 auto;padding:8px 8px;font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--text-muted);background:transparent;border:1px solid var(--border-strong);border-radius:var(--radius);cursor:pointer;transition:border-color .15s, color .15s, background .15s}
:where(body.p-lab-loop) .lab-seg button:hover{border-color:var(--accent-text);color:var(--text-body)}
:where(body.p-lab-loop) .lab-seg button.on{background:var(--accent-text);color:var(--surface-page);border-color:var(--accent-text)}
:where(body.p-lab-loop) .lab-verb{font-family:var(--ff-display);font-style:italic;font-weight:300;font-size:34px;line-height:1.1;color:var(--accent-text);display:block;margin-bottom:8px}
:where(body.p-lab-loop) .lab-verb.is-ok{color:var(--status-positive)}
:where(body.p-lab-loop) .lab-verb.is-warn{color:var(--status-caution)}
:where(body.p-lab-loop) .lab-verb.is-err{color:var(--status-negative)}
:where(body.p-lab-loop) .lab-explain{font-size:var(--fs-ui);line-height:1.7;color:var(--text-muted);margin:0 0 16px}
:where(body.p-lab-loop) .lab-json{font-family:var(--ff-mono);font-size:var(--fs-caption);line-height:1.7;color:var(--text-muted);white-space:pre-wrap;word-break:break-word;margin:0;padding-top:12px;border-top:1px solid var(--border-strong)}
:where(body.p-lab-loop) .lab-json b{color:var(--text-body);font-weight:500}
:where(body.p-lab-loop) .lab-bins{display:flex;align-items:flex-end;gap:4px;height:132px;margin:4px 0 8px}
:where(body.p-lab-loop) .lab-bin{flex:1;display:flex;flex-direction:row;align-items:flex-end;gap:2px;height:100%;min-width:0}
:where(body.p-lab-loop) .lab-bin i{flex:1;display:block;border-radius:1px 1px 0 0;min-height:1px}
:where(body.p-lab-loop) .lab-bin .lab-conf{background:var(--accent)}
:where(body.p-lab-loop) .lab-bin .lab-acc{background:var(--accent-text)}
:where(body.p-lab-loop) .lab-bin.is-empty{opacity:0.28}
:where(body.p-lab-loop) .lab-legend{display:flex;gap:16px;font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--text-muted)}
:where(body.p-lab-loop) .lab-legend span{display:flex;align-items:center;gap:8px}
:where(body.p-lab-loop) .lab-legend i{width:11px;height:11px;border-radius:2px;display:block}
:where(body.p-lab-loop) .lab-metrics{display:grid;grid-template-columns:repeat(auto-fit, minmax(min(96px,100%),1fr));gap:16px;padding-top:12px;border-top:1px solid var(--border-strong);margin-top:12px}
:where(body.p-lab-loop) .lab-metric b{display:block;font-family:var(--ff-display);font-weight:300;font-size:var(--fs-metric-sm);color:var(--accent-text);line-height:1;font-variant-numeric:tabular-nums}
:where(body.p-lab-loop) .lab-metric span{display:block;font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;color:var(--text-muted);margin-top:8px}
:where(body.p-lab-loop) .lab-testhead{display:flex;align-items:baseline;gap:16px;flex-wrap:wrap;margin-bottom:20px}
:where(body.p-lab-loop) .lab-tally{font-family:var(--ff-display);font-weight:300;font-size:var(--fs-metric);line-height:1;color:var(--status-positive);font-variant-numeric:tabular-nums}
:where(body.p-lab-loop) .lab-tally.is-err{color:var(--status-negative)}
:where(body.p-lab-loop) .lab-tallynote{font-family:var(--ff-mono);font-size:var(--fs-caption);color:var(--text-muted)}
:where(body.p-lab-loop) .lab-tests{list-style:none;padding:0;margin:0;columns:2;column-gap:32px}
@media (max-width: 720px){:where(body.p-lab-loop) .lab-tests{columns:1}}
:where(body.p-lab-loop) .lab-tests li{font-family:var(--ff-mono);font-size:var(--fs-caption);line-height:1.5;color:var(--text-muted);padding:4px 0 4px 20px;position:relative;break-inside:avoid}
:where(body.p-lab-loop) .lab-tests li::before{content:'✓';position:absolute;left:0;color:var(--status-positive)}
:where(body.p-lab-loop) .lab-tests li.is-fail{color:var(--status-negative)}
:where(body.p-lab-loop) .lab-tests li.is-fail::before{content:'✕';color:var(--status-negative)}
:where(body.p-lab-loop) .lab-tests .lab-err{display:block;color:var(--status-negative);padding-top:3px}
:where(body.p-lab-loop) .lab-nojs{font-family:var(--ff-mono);font-size:var(--fs-caption);color:var(--status-caution)}
/* ===== EXTRACTED FROM lab/teardown.html (theme-swap migration; scoped body.p-lab-teardown) ===== */
:where(body.p-lab-teardown) .lab-wrap{max-width:var(--inner-max);margin:0 auto;padding:0 var(--page-x)}
:where(body.p-lab-teardown) .lab-hero{padding-top:128px}
:where(body.p-lab-teardown) .lab-kicker{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);font-weight:500;letter-spacing:.02em;color:var(--accent-text);margin:0 0 16px}
:where(body.p-lab-teardown) .lab-lede{font-size:var(--fs-lead);line-height:1.7;color:var(--text-muted);max-width:var(--measure)}
:where(body.p-lab-teardown) .lab-lede strong{color:var(--text-body);font-weight:400}
:where(body.p-lab-teardown) .lab-note{border-left:2px solid var(--accent-fill);padding:12px 0 12px 20px;margin:32px 0 0;font-size:var(--fs-ui);line-height:1.7;color:var(--text-muted);max-width:var(--measure)}
:where(body.p-lab-teardown) .lab-note b{color:var(--text-body);font-weight:600}
:where(body.p-lab-teardown) .lab-body{font-size:var(--fs-body);line-height:1.7;color:var(--text-muted);max-width:var(--measure)}
:where(body.p-lab-teardown) .lab-body strong{color:var(--text-body);font-weight:400}
:where(body.p-lab-teardown) .lab-body p{margin:0 0 16px}
:where(body.p-lab-teardown) .lab-body p:last-child{margin-bottom:0}
:where(body.p-lab-teardown) .lab-body code,:where(body.p-lab-teardown) .td-inline{font-family:var(--ff-mono);font-size:0.9em;color:var(--accent-text)}
:where(body.p-lab-teardown) .td-scroll{overflow-x:auto;margin-top:24px}
:where(body.p-lab-teardown) table.td-table{width:100%;border-collapse:collapse;min-width:520px}
:where(body.p-lab-teardown) .td-table th{text-align:left;font-family:var(--ff-mono);font-size:var(--fs-eyebrow);font-weight:500;letter-spacing:.02em;color:var(--text-muted);padding:0 20px 12px 0;border-bottom:1px solid var(--border-strong)}
:where(body.p-lab-teardown) .td-table td{padding:12px 20px 12px 0;border-bottom:1px solid var(--border-strong);font-size:var(--fs-ui);line-height:1.6;color:var(--text-muted);vertical-align:top}
:where(body.p-lab-teardown) .td-table td:first-child{color:var(--text-body)}
:where(body.p-lab-teardown) .td-table td b{font-family:var(--ff-mono);color:var(--accent-text);font-weight:500;font-variant-numeric:tabular-nums}
:where(body.p-lab-teardown,body.p-lab-plugin) pre.lab-code{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:var(--radius);padding:16px 20px;overflow-x:auto;margin:24px 0 0}
:where(body.p-lab-teardown) pre.lab-code code{font-family:var(--ff-mono);font-size:var(--fs-caption);line-height:1.75;color:var(--text-body);white-space:pre}
:where(body.p-lab-teardown) .lab-code .c{color:var(--text-muted)}
:where(body.p-lab-teardown) .lab-code .k{color:var(--accent-text)}
:where(body.p-lab-teardown) .td-block{border-top:1px solid var(--border-strong);padding-top:32px;margin-top:40px}
:where(body.p-lab-teardown) .td-block:first-of-type{border-top:none;padding-top:0;margin-top:0}
:where(body.p-lab-teardown) .td-block h3{font-family:var(--ff-display);font-weight:400;font-size:var(--fs-card);line-height:1.3;color:var(--text-body);margin:0 0 12px}
:where(body.p-lab-teardown) .td-gaps{list-style:none;padding:0;margin:24px 0 0}
:where(body.p-lab-teardown) .td-gaps li{padding:16px 0 16px 32px;border-bottom:1px solid var(--border-strong);position:relative;font-size:var(--fs-ui);line-height:1.7;color:var(--text-muted);max-width:var(--measure)}
:where(body.p-lab-teardown) .td-gaps li:last-child{border-bottom:none}
:where(body.p-lab-teardown) .td-gaps li::before{content:'—';position:absolute;left:0;color:var(--status-negative);font-family:var(--ff-mono)}
:where(body.p-lab-teardown) .td-gaps li.is-fixed::before{content:'✓';color:var(--status-positive)}
:where(body.p-lab-teardown) .td-gaps b{color:var(--text-body);font-weight:600}
/* ===== EXTRACTED FROM lab/ forwarding stub (see allowlist) (theme-swap migration; scoped body.p-lab-fwd-stub) ===== */
body:where(.p-lab-fwd-stub){margin:0;min-height:100vh;display:grid;place-items:center;background:var(--surface-page);color:var(--text-primary);font-family:ui-monospace, SFMono-Regular, Menlo, monospace;font-size:14px}
:where(body.p-lab-fwd-stub) a{color:var(--accent-text)}
/* --- former hover handlers (patterns/index.html) --- */
.hv-patterns-1:hover{border-color:var(--accent-text);transform:translateY(-4px)}
.hv-patterns-2:hover{border-color:var(--accent);transform:translateY(-4px)}
.hv-patterns-3:hover{background:var(--accent-text);color:var(--surface-page)}
/* --- former hover handlers (patterns/act-review-ignore.html) --- */
.hv-patterns-act-review-ignore-1:hover{background:var(--accent-text)}
.hv-patterns-act-review-ignore-2:hover{background:var(--accent-text);color:var(--surface-page)}
/* --- former hover handlers (patterns/ai-failure-states.html) --- */
.hv-patterns-ai-failure-states-1:hover{background:var(--accent-text)}
.hv-patterns-ai-failure-states-2:hover{background:var(--accent-text);color:var(--surface-page)}
/* --- former hover handlers (patterns/calibration-track-record.html) --- */
.hv-patterns-calibration-track-record-1:hover{background:var(--accent-text)}
.hv-patterns-calibration-track-record-2:hover{background:var(--accent-text);color:var(--surface-page)}
/* --- former hover handlers (patterns/capability-contract.html) --- */
.hv-patterns-capability-contract-1:hover{background:var(--accent-text);color:var(--surface-page)}
.hv-patterns-capability-contract-2:hover{background:var(--accent-text)}
/* --- former hover handlers (patterns/confidence-scores.html) --- */
.hv-patterns-confidence-scores-1:hover{background:var(--accent-text)}
.hv-patterns-confidence-scores-2:hover{background:var(--accent-text);color:var(--surface-page)}
/* --- former hover handlers (patterns/human-in-loop.html) --- */
.hv-patterns-human-in-loop-1:hover{background:var(--accent-text)}
.hv-patterns-human-in-loop-2:hover{background:var(--accent-text);color:var(--surface-page)}
/* --- former hover handlers (patterns/ml-explainability.html) --- */
.hv-patterns-ml-explainability-1:hover{background:var(--accent-text)}
.hv-patterns-ml-explainability-2:hover{background:var(--accent-text);color:var(--surface-page)}
/* --- former hover handlers (patterns/provenance-citations.html) --- */
.hv-patterns-provenance-citations-1:hover{background:var(--accent-text)}
.hv-patterns-provenance-citations-2:hover{background:var(--accent-text);color:var(--surface-page)}
/* --- former hover handlers (patterns/reversibility-safe-to-act.html) --- */
.hv-patterns-reversibility-safe-to-act-1:hover{background:var(--accent-text)}
.hv-patterns-reversibility-safe-to-act-2:hover{background:var(--accent-text);color:var(--surface-page)}
/* --- former hover handlers (resources/index.html) --- */
.hv-resources-1:hover{border-color:var(--accent);transform:translateY(-4px)}
.hv-resources-2:hover{color:var(--accent-text)}
/* ===== EXTRACTED FROM resources/ai-design-checklist.html (theme-swap migration; scoped body.p-resources-ai-design-checklist) ===== */
@media print{:where(body.p-resources-ai-design-checklist) input.ckl{accent-color:#000}}
/* --- former hover handlers (resources/ai-design-checklist.html) --- */
.hv-resources-ai-design-checklist-1:hover{background:color-mix(in srgb, var(--accent-text) 5%, transparent)}
.hv-resources-ai-design-checklist-2:hover{color:var(--accent-text)}
/* --- former hover handlers (resources/founder-questions.html) --- */
.hv-resources-founder-questions-1:hover{color:var(--accent-text)}
/* --- former hover handlers (resources/intelligent-systems-glossary.html) --- */
.hv-resources-intelligent-systems-glossary-1:hover{color:var(--accent-text)}
/* --- former hover handlers (writing/index.html) --- */
.hv-writing-1:hover{border-color:var(--accent);transform:translateY(-4px)}
.hv-writing-2:hover{border-color:var(--accent)}
.hv-writing-3:hover{color:var(--accent-text)}
/* --- former hover handlers (writing/confidence-scoring.html) --- */
.hv-writing-confidence-scoring-1:hover{border-color:var(--accent)}
.hv-writing-confidence-scoring-2:hover{color:var(--accent-text)}
/* --- former hover handlers (writing/explainability.html) --- */
.hv-writing-explainability-1:hover{border-color:var(--accent)}
.hv-writing-explainability-2:hover{color:var(--accent-text)}
/* --- former hover handlers (writing/failure-states.html) --- */
.hv-writing-failure-states-1:hover{border-color:var(--accent)}
.hv-writing-failure-states-2:hover{color:var(--accent-text)}
/* --- former hover handlers (writing/human-in-loop.html) --- */
.hv-writing-human-in-loop-1:hover{border-color:var(--accent)}
.hv-writing-human-in-loop-2:hover{color:var(--accent-text)}
/* --- JS state classes (index.html) --- */
.nav-links a.nav-on{color:var(--accent-text)}
/* NAMED COMPONENTS — these were machine-generated labels (.xi-writing-005
   and friends) repeated once per page. A class should tell the next
   person what it is. */
/* a gold link, no underline */
.link-gold{color:var(--accent-text);text-decoration:none}
/* the handwritten aside, set 1.6deg off true */
.hand-note{font-size:21px;margin:12px 0 0;transform:rotate(-1.6deg)}
/* <main> takes the page ground */
.page-bg{background:var(--surface-page)}
/* the banded header at the top of an inner page */
.page-head{background:var(--surface-page);border-bottom:1px solid var(--border-strong);padding:104px 24px 40px}
.proof-chip:hover{background:color-mix(in srgb, var(--accent-text) 8%, transparent)}
.proof-chip:focus-visible{background:color-mix(in srgb, var(--accent-text) 8%, transparent)}
/* Case cards — hover lift + keyboard focus (was inline onmouseover) */
.case-card-v2:hover{border-color:var(--accent)}
.case-card-v2:focus-visible{border-color:var(--accent)}
.section-inner.editorial .section-body>:first-child{margin-top:0}
/* ----- Responsive: mobile (≤768px) ----- */
@media(max-width:768px){.nav-logo img{width:36px;height:36px}}
/* ----- Reduced motion ----- */
@media(prefers-reduced-motion:reduce){*{animation-duration:0.01ms;animation-iteration-count:1;transition-duration:0.01ms}}
/* print-shared — before this, hire/index.html was the only file with print styles, so
   every case study printed a solid near-black background with the fixed nav stamped
   onto all 14 sheets. */
@media print{#nav,footer,.menu-toggle,.skip-link,.dyslexia-toggle,.footer-back{display:none}
body{background:#fff;color:#111}
body::before{display:none}
.act-cream,.section,main{background:#fff}
h1,h2,h3,.section-title,.case-hero h1{color:#111}
p,li,dd,dt,td,blockquote{color:#222}
.case-gate{border-left:3px solid #8A6423;background:#faf7f0}
a{color:#111}}
@media (max-width: 768px){}
:where(body.p-home) .rcpt-btn{border-color:var(--accent-fill)}
/* --- former style attributes (index.html) --- */
.xi-home-001{display:none}
/* --- former style attributes (folio/index.html) --- */
.xi-folio-001{color:var(--accent-text)}
@media print{:where(body.p-hire) nav,:where(body.p-hire) .nav-cta,:where(body.p-hire) .menu-toggle,:where(body.p-hire) footer,:where(body.p-hire) .hire-print-note,:where(body.p-hire) .skip-link{display:none}
body:where(.p-hire){background:#fff;color:#111}}
/* --- former style attributes (hire/index.html) --- */
@media print{:where(body.p-screen) nav,:where(body.p-screen) .nav-cta,:where(body.p-screen) .menu-toggle,:where(body.p-screen) footer,:where(body.p-screen) .scr-print-note,:where(body.p-screen) .skip-link{display:none}
body:where(.p-screen){background:#fff;color:#111}
:where(body.p-screen) .scr-title,:where(body.p-screen) .scr-stand,:where(body.p-screen) .scr-q h2,:where(body.p-screen) .scr-q p,:where(body.p-screen) .scr-close-line{color:#111}
:where(body.p-screen) .scr-kicker,:where(body.p-screen) .scr-q p a,:where(body.p-screen) .scr-receipt a,:where(body.p-screen) .scr-after a{color:#8a6320}
:where(body.p-screen) .scr-num,:where(body.p-screen) .scr-receipt,:where(body.p-screen) .scr-after{color:#555}
:where(body.p-screen) .scr-close{background:#fff;border-color:#ddd}
:where(body.p-screen) .scr-q{border-color:#ddd}}
/* --- former style attributes (screen/index.html) --- */
/* ===== EXTRACTED FROM process/index.html (theme-swap migration; scoped body.p-process) ===== */
/* --- former style attributes (process/index.html) --- */
/* --- former style attributes (case-studies/adtech.html) --- */

/* --- former style attributes (case-studies/fintech.html) --- */

/* --- former style attributes (case-studies/o2.html) --- */

/* --- former style attributes (case-studies/orgos.html) --- */

/* --- former style attributes (case-studies/ptc.html) --- */

/* --- former style attributes (case-studies/vc-diligence.html) --- */
.xi-case-studies-vc-diligence-001,.xi-case-studies-planit-001{display:none}
/* --- former style attributes (lab/index.html) --- */
/* --- former style attributes (lab/eval.html) --- */
/* --- former style attributes (lab/loop.html) --- */
/* --- former style attributes (lab/teardown.html) --- */
/* ===== EXTRACTED FROM patterns/index.html (theme-swap migration; scoped body.p-patterns) ===== */
/* --- former style attributes (patterns/index.html) --- */

/* ===== EXTRACTED FROM patterns/act-review-ignore.html (theme-swap migration; scoped body.p-patterns-act-review-ignore) ===== */
/* --- former style attributes (patterns/act-review-ignore.html) --- */

/* ===== EXTRACTED FROM patterns/ai-failure-states.html (theme-swap migration; scoped body.p-patterns-ai-failure-states) ===== */
/* --- former style attributes (patterns/ai-failure-states.html) --- */

/* ===== EXTRACTED FROM patterns/calibration-track-record.html (theme-swap migration; scoped body.p-patterns-calibration-track-record) ===== */
/* --- former style attributes (patterns/calibration-track-record.html) --- */

/* ===== EXTRACTED FROM patterns/capability-contract.html (theme-swap migration; scoped body.p-patterns-capability-contract) ===== */
/* --- former style attributes (patterns/capability-contract.html) --- */

/* ===== EXTRACTED FROM patterns/confidence-scores.html (theme-swap migration; scoped body.p-patterns-confidence-scores) ===== */
/* --- former style attributes (patterns/confidence-scores.html) --- */

/* ===== EXTRACTED FROM patterns/human-in-loop.html (theme-swap migration; scoped body.p-patterns-human-in-loop) ===== */
/* --- former style attributes (patterns/human-in-loop.html) --- */

/* ===== EXTRACTED FROM patterns/ml-explainability.html (theme-swap migration; scoped body.p-patterns-ml-explainability) ===== */
/* --- former style attributes (patterns/ml-explainability.html) --- */

/* ===== EXTRACTED FROM patterns/provenance-citations.html (theme-swap migration; scoped body.p-patterns-provenance-citations) ===== */
/* --- former style attributes (patterns/provenance-citations.html) --- */

/* ===== EXTRACTED FROM patterns/reversibility-safe-to-act.html (theme-swap migration; scoped body.p-patterns-reversibility-safe-to-act) ===== */
/* --- former style attributes (patterns/reversibility-safe-to-act.html) --- */

/* ===== EXTRACTED FROM resources/index.html (theme-swap migration; scoped body.p-resources) ===== */
/* --- former style attributes (resources/index.html) --- */
/* ===== EXTRACTED FROM resources/ai-design-checklist.html (theme-swap migration; scoped body.p-resources-ai-design-checklist) ===== */
@media print{:where(body.p-resources-ai-design-checklist) nav,:where(body.p-resources-ai-design-checklist) footer,:where(body.p-resources-ai-design-checklist) #ckl-reset,:where(body.p-resources-ai-design-checklist) .skip-link{display:none}
body:where(.p-resources-ai-design-checklist){background:#fff;color:#111}
:where(body.p-resources-ai-design-checklist) main,:where(body.p-resources-ai-design-checklist) main *{color:#111;background:#fff;border-color:#ddd}
:where(body.p-resources-ai-design-checklist) h1,:where(body.p-resources-ai-design-checklist) h2{color:#000}}
/* --- former style attributes (resources/ai-design-checklist.html) --- */
/* ===== EXTRACTED FROM resources/founder-questions.html (theme-swap migration; scoped body.p-resources-founder-questions) ===== */
/* --- former style attributes (resources/founder-questions.html) --- */
/* ===== EXTRACTED FROM resources/intelligent-systems-glossary.html (theme-swap migration; scoped body.p-resources-intelligent-systems-glossary) ===== */
/* --- former style attributes (resources/intelligent-systems-glossary.html) --- */
/* ===== EXTRACTED FROM writing/index.html (theme-swap migration; scoped body.p-writing) ===== */
/* --- former style attributes (writing/index.html) --- */
/* ===== EXTRACTED FROM writing/confidence-scoring.html (theme-swap migration; scoped body.p-writing-confidence-scoring) ===== */
/* --- former style attributes (writing/confidence-scoring.html) --- */
/* ===== EXTRACTED FROM writing/explainability.html (theme-swap migration; scoped body.p-writing-explainability) ===== */
/* --- former style attributes (writing/explainability.html) --- */
/* ===== EXTRACTED FROM writing/failure-states.html (theme-swap migration; scoped body.p-writing-failure-states) ===== */
/* --- former style attributes (writing/failure-states.html) --- */
/* ===== EXTRACTED FROM writing/human-in-loop.html (theme-swap migration; scoped body.p-writing-human-in-loop) ===== */
/* --- former style attributes (writing/human-in-loop.html) --- */
/* SMALL ICON — 14px. Seventeen generated classes said `width:14px;
   height:14px` and nothing named it, so when the footer became a shared
   partial the size vanished and every footer icon jumped to .icon's 20px. */
.icon-sm{width:14px;height:14px}
/* 2026-09-10: .xi-home-095..099 and .hv-home-1 (the contact form's five
   extracted inline classes and its button hover) deleted with the form in
   direction A. Verified 0 uses across all 79 html/js files first. */

/* was 64px: a void inside a small card, not a section gap (2026-09-02 sweep) */
.xi-case-studies-adtech-056{margin:0 0 16px}
/* 2026-08-30: the base rule above is declared AFTER the earlier mobile collapses, so at 390 the 2-col won by source order — cards escaped the viewport. Collapse re-declared after the base. */
.xi-patterns-020{background:var(--surface-card);transition:border-color 0.3s,transform 0.3s;text-decoration:none;color:inherit}
/* Classic-theme base for the walkthrough video (Ember carries the full treatment). */
.vid-frame video{position:absolute;inset:0;width:100%;height:100%;border:0;background:#000;object-fit:contain}
.vid-walk{max-width:1000px;margin-left:auto;margin-right:auto}
.vid-frame video{cursor:pointer}
/* ── from ember.css ── */
/* ================================================================
   EMBER — the second design system, as a stylesheet.
   Loads AFTER styles.css on every page; every rule is guarded by
   html[data-theme="ember"], so the ENTIRE theme swap is one attribute
   on <html>. Remove the attribute -> Classic, byte-identical.
   Governed by DESIGN-SYSTEM-EMBER.md. Client-product reconstructions
   (the plates: MyO2, deal dossier, planner, OrgOS board) and the cream
   artifacts (receipt, QC slip, boarding pass, letters, candidate facts)
   are deliberately NOT reskinned — they are period/paper objects.
   ================================================================ */

/* ---------- 1 · tokens: everything that flows through vars re-themes here */
:root{--cta-grad:linear-gradient(92deg,var(--acc-copper),var(--acc-violet))}
/* ---------- 2 · base surfaces */
body{background:var(--surface-page)}
/* the classic noise overlay reads as grime on plum — replace with nothing */
body::before{display:none}
/* ---------- 3 · nav: pills + the half-second mark */
/* ...and the nav dissolves into the page instead of ending in a hard 1px line. Same call.
   Specificity note: this beats styles.css `#nav.scrolled` (1,1,1 vs 1,1,0), so it governs
   both the resting and the scrolled state — checked, not assumed. */
#nav{background:linear-gradient(180deg,color-mix(in srgb, var(--surface-page) 92%, transparent),color-mix(in srgb, var(--surface-page) 72%, transparent));backdrop-filter:blur(10px);border-bottom:0}
/*
   /fit/ was hand-written and got none, so its logo fell back to intrinsic size (45px) and
   made that one nav 1px taller than the other 42. Sized here instead, so the nav is a
   component and a new page cannot forget it. */
#nav .nav-logo img{width:40px;height:40px}
/* ...and the links declare their own line-height instead of inheriting the page's. The
   homepage body sets 1.65 and the inner pages 1.7, so the same nav computed 21.45px on
   home and 22.1px everywhere else and the bar was 0.4px shorter on one page out of 43.
   A component that inherits a critical property is a component that differs per page. */
#nav .nav-links a:not(.cta){line-height:1.7}
/* Same for the CTA pill: the homepage declared line-height:1 (44.00px tall) while the
   other 42 pages INHERITED ~1.7 (44.39px), so the bar was 0.39px shorter on one page.
   Declared once here at the value adtech computes, which is what Arpit asked every nav to
   match. Declared, not inherited — inheritance is what made them differ. */
/* the nav door composes .cta; only its lift is local to the nav */
.nav-cta:hover{transform:translateY(-2px)}
.nav-links a.nav-on{color:var(--acc-copper)}
.nav-links a:hover{color:var(--acc-copper)}
/* hero diagnostic — first-class component, ember demo-box language */
.hd-card{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:var(--radius-2);box-shadow:var(--elev-2);position:relative;overflow:hidden}
.hd-tag{color:var(--acc-copper)}
.hd-preset{border-radius:10px;border-color:var(--border-strong)}
.hd-preset:hover{border-color:var(--acc-copper);background:var(--act-wash)}
.hd-preset span{color:var(--acc-copper)}
.hd-preset::after{color:var(--acc-copper)}
.hd-rule{background:var(--acc-copper)}
.hd-reframe em{color:var(--acc-copper)}
.hd-free input:focus{border-color:var(--acc-copper)}
/* ---------- 5 · the receipts act: cream peak -> plum band with the four heats */
.act-cream{background:var(--surface-page);color:var(--text-body);position:relative}
#chip-adtech{border-top-color:var(--acc-copper)}
#chip-fintech{border-top-color:var(--acc-violet)}
#chip-ptc{border-top-color:var(--acc-amber)}
#chip-o2{border-top-color:var(--acc-rose)}
.rcpt-btn{border-radius:999px}
/* the paper receipt artifact stays cream — it is an object, not skin */

/* ---------- 6 · case index: six colour-coded lanes on the shared row markup */
#featured-case-studies{background:var(--surface-page)}
.ai-case-kick,
.ai-case-num,
.ai-case .walk{color:var(--lc)}
.ai-case .walk{grid-area:walk;white-space:nowrap}
.verbs .verb{border-top:3px solid var(--border-strong);padding-top:16px}
.verbs .verb:nth-child(1){border-top-color:var(--acc-amber)}
.verbs .verb:nth-child(1) .verb-word{color:var(--acc-amber)}
.verbs .verb:nth-child(2){border-top-color:var(--acc-violet)}
.verbs .verb:nth-child(2) .verb-word{color:var(--acc-violet)}
.verbs .verb:nth-child(3){border-top-color:var(--acc-copper)}
.verbs .verb:nth-child(3) .verb-word{color:var(--acc-copper)}
.ccd{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:var(--radius-2);position:relative;overflow:hidden}
.ccd-q{border-radius:10px}
.ccd-q:hover{border-color:var(--acc-copper)}
/* ---------- 8 · sections rhythm: lead band on bg-soft, breathing black between */
#how-i-lead{background:var(--surface-sunken);position:relative;overflow:hidden}
#contact{position:relative;overflow:hidden}
#contact > *{position:relative}
.footer-back:hover{color:var(--acc-copper)}
/* ---------- 10 · reduced motion: ember adds no new exceptions */
@media (prefers-reduced-motion:reduce){.proof-cell:hover{transform:none}
.nav-cta:hover{transform:none}}
/* ---------- 12 · the contract demo hardcodes cream-stage inks (tuned for the
   cream act, which Ember turns plum). Re-ink for the dark card. Measured by the
   pixel audit: #635848/#7E5A14/#2E6A46 on #241830 = 2.4-2.7:1. */
.ccd-cap{color:var(--text-muted)}
.ccd-cap b{color:var(--status-positive)}
.ccd-q{border-color:var(--acc-amber);color:var(--acc-amber)}
.ccd-q:hover{background:var(--act-wash)}
.ccd-q:focus-visible{outline-color:var(--acc-amber)}
.ccd-idle,
.ccd-src,
.ccd-note{color:var(--text-muted)}
.ccd-tag--in{color:var(--status-positive);border-color:var(--status-positive)}
.ccd-tag--out{color:var(--acc-rose);border-color:var(--acc-rose)}
/* ================================================================
   EMBER HOMEPAGE — the prototype's own layout + components, scoped to
   body.p-home. Arpit's call: apply the prototype LAYOUT, not a recolour
   of the classic grid. Live widgets (hero diagnostic, receipts, contract
   demo, QC stamp, contact form) keep their classic class names and are
   re-fitted after this block.
   ================================================================ */
body.p-home{--serif:var(--ff-display),Georgia,serif;--sans:var(--ff-sans);--mono:var(--ff-mono),monospace;--hand:'Caveat',cursive}
/* The prototype shipped a blanket *{margin:0;padding:0}
. Scoped to body.p-home *
   it outranks EVERY single-class rule, so each classic artifact spliced into this
   page (QC slip, receipt panels, contact form) silently lost its padding — the QC
   slip's absolutely-positioned sign-off box then overlapped its own checklist.
   Keep the typographic margin reset the prototype relies on; drop the padding
   blanket so components keep the padding they declare. (2026-08-13, measured.) */
body.p-home *{box-sizing:border-box}
body.p-home :is(h1,h2,h3,h4,h5,h6,p,figure,blockquote,dl,dd,dt,ul,ol){margin:0}
body.p-home :is(ul,ol):where(.hd-presets,.rrow){padding:0}
body.p-home{scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){body.p-home{scroll-behavior:auto}}
body.p-home{background:var(--surface-page);color:var(--text-body);font-family:var(--sans);font-size:var(--fs-body);line-height:1.7}
body.p-home a{color:inherit;text-decoration:none}
body.p-home :focus-visible{outline:2px solid var(--acc-amber);outline-offset:3px;border-radius:2px}
body.p-home .wrap{max-width:1240px;margin:0 auto;padding:0 40px}
body.p-home .k{font-family:var(--mono);font-size:12px;letter-spacing:.02em}
body.p-home .hand{font-family:var(--hand);font-weight:600}
body.p-home h1,
body.p-home h2,
body.p-home h3{font-family:var(--serif);font-weight:300;letter-spacing:-.015em}
body.p-home .grad{background:linear-gradient(92deg,var(--acc-copper),var(--acc-violet));-webkit-background-clip:text;background-clip:text;color:transparent}
body.p-home .pill:hover{transform:translateY(-2px)}
body.p-home .pill-line:hover{border-color:var(--acc-copper)}
@media (prefers-reduced-motion:reduce){body.p-home .pill:hover{transform:none}}
body.p-home .seam{height:110px;clip-path:polygon(0 62%,100% 8%,100% 100%,0 100%);margin-top:-60px;position:relative;z-index:1}
body.p-home .seam-up{clip-path:polygon(0 8%,100% 62%,100% 100%,0 100%)}
body.p-home .hero{position:relative;overflow:hidden;padding:96px 0 150px}
/* Arpit's call, 2026-08-17 (option C). The third layer used to be
   linear-gradient(160deg,#1E1022 0%,#120B14 55%,#190D10 100%) — it reached near-black by
   55% and smothered the warm radial sitting above it. It was decoration, never a contrast
   fix: on a flat ground the hero copy MEASURES BETTER, 16.31:1 -> 16.74:1 cream and
   9.93 -> 10.19 muted. The radials now carry all the colour. */
body.p-home .hero .field{position:absolute;inset:0;background:var(--glow)}
body.p-home .hero .in{position:relative;z-index:2}
body.p-home .hero .k{color:var(--acc-copper)}
/* The availability line, sitting under the identity line. Arpit would take a
   hands-on Staff IC role, and "Product & Design Leader" reads as MANAGER to an
   IC screener — the first filter applied. This states what he is open to
   rather than claiming a level, which is literally true and carries the words
   a recruiter searches for. It declares its own type rather than inheriting
   the eyebrow's: a second, different piece of information should not look like
   a second title. line-height is explicit because this wraps to two lines on a
   phone and the label floor is 1.40. */
body.p-home .hero .k-open{font-family:var(--mono);font-size:11.5px;font-weight:400;letter-spacing:.02em;line-height:1.55;color:var(--acc-amber);margin:8px 0 0}
body.p-home .hero h1{font-size:clamp(52px,7.2vw,106px);margin:24px 0 24px;max-width:13ch}
body.p-home .hero h1 .grad{font-style:italic}
/* .hero .sub retired 2026-09-11 with the paragraph it styled — 22 words whose
   two halves are both said again within 130px (act 01's eyebrow: "four
   industries"; the client strip: the four clients). Used on no other page. */
body.p-home .hero .ctas{display:flex;gap:16px;flex-wrap:wrap;margin-top:32px}
body.p-home .hero .note{position:absolute;right:6%;bottom:16%;color:var(--acc-amber);font-size:23px;transform:rotate(-3deg);z-index:2}
@media (max-width:900px){body.p-home .hero .note{display:none}}
body.p-home .receipts{background:var(--surface-sunken);position:relative;padding:0 0 84px}
body.p-home .receipts .seam{background:var(--surface-sunken)}
body.p-home .receipts .k{color:var(--acc-violet)}
body.p-home .receipts h2{font-size:clamp(30px,3.6vw,48px);margin:12px 0 8px}
body.p-home .receipts .hand{color:var(--acc-amber);font-size:22px;display:inline-block;transform:rotate(-1.5deg)}
body.p-home .rrow{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-top:40px}
body.p-home .rcell{background:var(--surface-card);border-radius:10px;padding:24px 24px;border-top:3px solid var(--rc)}
body.p-home .rcell b{display:block;font-family:var(--serif);font-weight:400;font-size:clamp(30px,3vw,46px);line-height:1;color:var(--rc)}
body.p-home .rcell span{display:block;font-family:var(--mono);font-size:11.5px;letter-spacing:.02em;color:var(--text-muted);line-height:1.9;margin-top:12px}
body.p-home .rc1{--rc:var(--acc-copper)}
body.p-home .rc2{--rc:var(--acc-violet)}
body.p-home .rc3{--rc:var(--acc-amber)}
body.p-home .rc4{--rc:var(--acc-rose)}
body.p-home .who{padding:96px 0 88px}
body.p-home .who .wrap{display:grid;grid-template-columns:1.15fr .85fr;gap:64px;align-items:center}
body.p-home .who .k{color:var(--acc-copper)}
body.p-home .who h2{font-size:clamp(28px,3vw,42px);margin:12px 0 20px}
body.p-home .who p{color:var(--text-muted);max-width:56ch;margin-bottom:16px}
body.p-home .who p a{color:var(--acc-amber);text-decoration:underline;text-underline-offset:3px}

/* THE PORTRAIT ON THE RECORD — Arpit's pick from three rendered treatments.
   The card is a document: serving size, allergen notice, a signature line. A
   photograph affixed to a document overhangs it rather than sitting inside the
   layout — half on the paper, half off.
   The ring is the card's own stock (var(--cream)); that is what stops it
   reading as a floating avatar. Its own shadow puts it above the page.
   Below 900px the card nearly fills the screen and a sideways overhang runs
   off the edge — measured, it escaped by 5px at 390. There it overhangs the
   TOP edge only and tucks inside the right margin. */
body.p-home .facts-portrait{position:absolute;top:-52px;right:-50px;width:164px;height:164px;object-fit:cover;object-position:50% 18%;border-radius:50%;border:5px solid var(--surface-page);box-shadow:var(--elev-2);z-index:2}
/* 1200, not 900. At 1024 the card sits close enough to the right gutter that
   a 38px overhang pushed 4px past the viewport and gave the whole PAGE a
   horizontal scrollbar. 390 and 1440 were both clean — the break was in
   between, which is the only reason it was found. */
@media (max-width:1300px){body.p-home .facts-portrait{width:126px;height:126px;top:-48px;right:10px}}
/* At 390 the card is only ~294px wide, so a 126px disc sitting 48px proud
   still lands on the "Serving size" line — measured against the TEXT RANGE,
   not the element box, which is the only way to see it. Smaller and higher on
   the narrowest screens so it clears the type. */
@media (max-width:480px){body.p-home .facts-portrait{width:104px;height:104px;top:-58px;right:8px}}
body.p-home .facts{position:relative;background:var(--surface-page);color:var(--text-body);border-radius:12px;padding:24px;box-shadow:var(--elev-2);transform:rotate(1.2deg)}
@media (prefers-reduced-motion:reduce){body.p-home .facts{transform:none}}
body.p-home .facts h3{font-family:var(--sans);font-weight:600;font-size:20px;letter-spacing:0}
body.p-home .facts .fs{font-size:12px;color:var(--text-muted);border-bottom:2px solid var(--text-body);padding:8px 0 8px;margin-bottom:8px}
body.p-home .facts dl{font-size:14px}
body.p-home .facts .fr{display:flex;justify-content:space-between;gap:12px;padding:8px 0;border-bottom:1px solid var(--border-hairline)}
body.p-home .facts .fr dt{font-weight:600}
body.p-home .facts .fr dd{font-family:var(--mono);font-size:13px}
body.p-home .facts .warn{font-size:11.5px;color:var(--text-muted);margin-top:12px;line-height:1.6}
body.p-home .facts .warn b{color:var(--text-body)}
body.p-home .work{background:var(--surface-sunken);padding:0 0 96px;position:relative}
body.p-home .work .seam{background:var(--surface-sunken)}
body.p-home .work .k{color:var(--acc-amber)}
body.p-home .work h2{font-size:clamp(32px,4vw,54px);margin:12px 0 16px;max-width:22ch}
body.p-home .work .lede{color:var(--text-muted);line-height:1.7}
body.p-home .contract{padding:96px 0}
body.p-home .contract .wrap{display:grid;grid-template-columns:1.05fr .95fr;gap:64px;align-items:start}
body.p-home .contract .k{color:var(--acc-violet)}
body.p-home .contract h2{font-size:clamp(28px,3.2vw,44px);margin:12px 0 16px}
body.p-home .contract p{color:var(--text-muted);margin-bottom:16px;max-width:56ch}
body.p-home .cols{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:24px}
body.p-home .col{border-top:3px solid var(--cc);padding-top:16px}
body.p-home .col .ck{font-family:var(--mono);font-size:11.5px;letter-spacing:.02em;color:var(--cc)}
body.p-home .col h3{font-size:20px;margin:8px 0 8px;font-weight:400;font-style:italic}
body.p-home .col p{font-size:13px;color:var(--text-muted);line-height:1.7}
body.p-home .co1{--cc:var(--acc-amber)}
body.p-home .co2{--cc:var(--acc-violet)}
body.p-home .co3{--cc:var(--acc-copper)}
body.p-home .demo{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:12px;padding:24px;position:relative;overflow:hidden}
body.p-home .demo .dk{display:flex;justify-content:space-between;font-family:var(--mono);font-size:11.5px;letter-spacing:.02em;color:var(--text-faint)}
body.p-home .demo .dk b{color:var(--acc-amber);font-weight:500}
body.p-home .demo .box{background:var(--surface-page);border:1px solid var(--border-strong);border-radius:8px;padding:16px 16px;margin-top:16px;font-family:var(--mono);font-size:12.5px;line-height:1.9;color:var(--text-muted)}
body.p-home .demo .box b{color:var(--text-body);font-weight:500}
body.p-home .demo .q{border:1px solid var(--accent);border-radius:8px;padding:12px 16px;margin-top:8px;font-family:var(--mono);font-size:12.5px;color:var(--acc-amber)}
body.p-home .lead{background:var(--surface-sunken);padding:0 0 90px;position:relative}
body.p-home .lead .seam{background:var(--surface-sunken)}
body.p-home .lead .k{color:var(--acc-copper)}
body.p-home .lead h2{font-size:clamp(26px,3vw,40px);max-width:34ch;line-height:1.2;margin:12px 0 40px}
body.p-home .memos{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
body.p-home .memo{background:var(--surface-card);border-radius:10px;padding:24px;border-top:3px solid var(--mc)}
body.p-home .memo .mk{font-family:var(--mono);font-size:11.5px;letter-spacing:.02em;color:var(--mc)}
body.p-home .memo h3{font-size:19px;font-weight:400;margin:8px 0 8px}
body.p-home .memo p{font-size:13.5px;color:var(--text-muted);line-height:1.7}
body.p-home .m1{--mc:var(--acc-copper)}
body.p-home .m2{--mc:var(--acc-violet)}
body.p-home .m3{--mc:var(--acc-amber)}
body.p-home .errata{margin-top:24px;border:1.5px dashed var(--acc-rose);border-radius:10px;padding:16px 24px;display:flex;gap:16px;align-items:center;flex-wrap:wrap;max-width:960px}
body.p-home .errata .ek{font-family:var(--mono);font-size:11.5px;letter-spacing:.02em;color:var(--acc-rose);border:1.5px solid var(--acc-rose);border-radius:4px;padding:4px 12px;transform:rotate(-3deg)}
@media (prefers-reduced-motion:reduce){body.p-home .errata .ek{transform:none}}
body.p-home .errata p{font-size:14px;color:var(--text-muted);max-width:66ch}
body.p-home .errata a{color:var(--acc-amber);text-decoration:underline;text-underline-offset:3px}
body.p-home .qt{background:var(--surface-card);border-radius:10px;padding:24px 24px}
body.p-home .qt blockquote{font-family:var(--serif);font-style:italic;font-size:16.5px;line-height:1.6;color:var(--text-body)}
body.p-home .qt figcaption{margin-top:16px;font-family:var(--mono);font-size:12px;color:var(--text-muted)}
body.p-home .qt figcaption b{color:var(--acc-amber);font-weight:500;display:block;font-family:var(--sans);font-size:13.5px;letter-spacing:0}
body.p-home .labrow{padding:92px 0}
body.p-home .labrow .k{color:var(--acc-amber)}
body.p-home .labrow h2{font-size:clamp(28px,3.2vw,44px);margin:12px 0 40px}
body.p-home .acts{display:grid;grid-template-columns:repeat(3,1fr);gap:32px;margin-top:48px}
body.p-home .act .ak{font-family:var(--mono);font-size:11.5px;letter-spacing:.02em;color:var(--acc-copper)}
body.p-home .act h3{font-size:19px;font-weight:400;font-style:italic;margin:8px 0 8px}
body.p-home .act p{font-size:13.5px;color:var(--text-muted);line-height:1.7}
body.p-home .close{position:relative;overflow:hidden;padding:120px 0 100px}
body.p-home .close .field{position:absolute;inset:0;background:var(--glow)}
/* DIRECTION A (2026-09-10, his pick of three): the closing section is one
   centred column — pass, then the door, then the alternates. The eyebrow,
   h2, standfirst, logistics line, signature and P.S. are GONE, not hidden:
   he asked "do I need so much of text ... or can I simply very simple
   boarding pass with supporting text and CTA and few supporting CTAs".
   Every fact they carried is either in the pass now or still stated in Act
   II (GMT+5:30 and both US coasts in #how-i-lead, remote and 4 weeks in the
   hero) — checked before deleting, not assumed.
   This is the ONE section on the homepage with no eyebrow and no visible
   h2, which breaks the section grammar in DESIGN-SYSTEM.md on purpose: at
   the moment of action the page stops narrating. Do not "restore" it. */
body.p-home .close .wrap{position:relative;z-index:2;display:block;max-width:720px;margin-inline:auto;text-align:center}
/* The primary and secondary sit as ONE object. Measured before this rule: they
   were inline-flex siblings, so the space between them was a TEXT SPACE — 3px,
   which is not a step on the 4px grid — and at 360px they wrapped and touched
   at 0px. A flex row with a declared gap fixes both, and wraps deliberately
   rather than by accident. */
body.p-home .close .door-stack{margin-top:32px;display:flex;flex-wrap:wrap;gap:16px;justify-content:center;align-items:center}
body.p-home .pass{background:var(--surface-page);color:var(--text-body);border-radius:8px;padding:24px 24px;font-family:var(--mono);box-shadow:0 30px 64px rgba(0,0,0,.55);margin-inline:auto;text-align:left}
body.p-home .pass .pk{display:flex;justify-content:space-between;font-size:10.5px;letter-spacing:.16em;color:var(--text-muted)}
body.p-home .pass .pr{display:flex;justify-content:space-between;align-items:center;margin:16px 0}
body.p-home .pass .pc{font-family:var(--serif);font-size:44px}
body.p-home .pass .arr{color:var(--acc-copper);font-size:20px}
body.p-home .pass .grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;border-top:1px dashed rgba(34,28,16,.3);padding-top:16px;font-size:10.5px;color:var(--text-muted)}
body.p-home .pass .grid b{display:block;font-size:12.5px;font-weight:500;color:var(--text-body);margin-top:2px}
body.p-home .pass .stamp{display:inline-block;margin-top:16px;font-size:11px;letter-spacing:.02em;color:var(--acc-copper);border:2px solid var(--acc-copper);border-radius:4px;padding:4px 12px;transform:rotate(-3deg)}
@media (prefers-reduced-motion:reduce){body.p-home .pass .stamp{transform:none}}
body.p-home .pass .bar{margin-top:16px;height:36px;background:repeating-linear-gradient(90deg,var(--text-body),var(--text-body) 2px,transparent 2px,transparent 5px)}
/* The pass is a 3-column ticket, and direction A gave its fields longer values
   ("Staff · Principal · Founding" where it used to say "Full-time"). Measured
   the rendered LINE COUNT of every field from 360px to 768px: at 520 and above
   only CLASS wraps, which is how it renders at 1440 too and how he approved it.
   Below 520 it falls apart — at 390, five of six fields wrap and both header
   spans go to two lines. So the ticket becomes a 2-column stub under 520px.
   520 is the measurement, not a guess; the usual 640 breakpoint is too late.
   PLACED AFTER the .pass block on purpose: my first attempt put it above, and
   `.pass .grid{grid-template-columns:repeat(3,1fr)}` 9 lines LOWER won on
   source order — a media query adds no specificity. The .pk rule appeared to
   work only because that base rule never re-declares flex-direction. */
@media (max-width:519px){body.p-home .pass .grid{grid-template-columns:repeat(2,1fr);gap:12px}
body.p-home .pass .pk{flex-direction:column;gap:4px}
body.p-home .pass .pc{font-size:36px}}
/* Small phones (360px Android, 375 SE) still wrapped CARRY-ON and STATUS at two
   columns: the values need 127px and 134px and the cell was 126px. Buying those
   8px by narrowing the ticket's own side padding beats shrinking the type — the
   pass is already the smallest text on the page. CLASS goes to two lines at
   every width including 1440, so that one is the design, not a defect. */
@media (max-width:419px){body.p-home .pass{padding-inline:16px}
body.p-home .pass .grid{gap:8px}}
body.p-home footer{border-top:1px solid var(--border-strong);padding:24px 0;font-family:var(--mono);font-size:12px;color:var(--text-faint)}
/* removed 2026-09-08: footer > .wrap does not exist on the homepage, so this
   matched nothing. The flex row comes from the footer element itself. */
@media (max-width:1000px){body.p-home .rrow{grid-template-columns:repeat(2,1fr)}
body.p-home .who .wrap{grid-template-columns:1fr}
body.p-home .contract .wrap{grid-template-columns:1fr}
body.p-home .memos{grid-template-columns:1fr}
body.p-home .acts{grid-template-columns:1fr}}
@media (max-width:640px){body.p-home .rrow{grid-template-columns:1fr}
body.p-home .cols{grid-template-columns:1fr}
body.p-home .wrap{padding:0 16px}}
/* ---------- EMBER HOMEPAGE · fitting the live widgets into the prototype layout ---------- */
/* The rail is a FIXED 340px, not .9fr. At .9fr the film took 45% of the band
   and the claim was squeezed to 55%; the film is meant to be the small object
   beside the claim, not its equal. align-items:start with the widget bottom-
   aligned puts the rail's unavoidable empty half ABOVE the film, beside the
   claim's first line, where a text column's right margin belongs. */
body.p-home .hero .wrap.hero-split{display:grid;grid-template-columns:minmax(0,1fr) clamp(260px,24vw,340px);column-gap:48px;row-gap:0;align-items:start}
body.p-home .hero .hero-widget{align-self:end;padding-bottom:4px}
/* The split now survives to 900px, not 1040. At 1040 a 1024px laptop — a very
   common width — fell to one column and the film became a 944px slab whose
   POSTER repeats the h1 verbatim in larger type than the h1 itself: the same
   sentence twice in one screen, and the client strip pushed to y1171. Below 900
   the film still stacks, but capped so it stays the small object beside the
   claim rather than a second hero. */
@media (max-width:900px){body.p-home .hero .wrap.hero-split{grid-template-columns:minmax(0,1fr);column-gap:0}
body.p-home .hero .hero-widget{align-self:auto;padding-bottom:0;margin-top:40px;max-width:520px}}
.hd-tag{font-family:var(--mono);font-size:12px;letter-spacing:.02em;color:var(--acc-copper);margin-bottom:12px}
.hd-card{background:var(--surface-card,var(--surface-card));border:1px solid var(--border-strong,var(--border-hairline));border-radius:var(--radius-2);padding:24px;box-shadow:var(--elev-2);position:relative;overflow:hidden}
.hd-diag-q{font-family:var(--serif);font-weight:300;font-size:21px;line-height:1.3;color:var(--text-body);margin:0 0 16px}
.hd-preset{border:1px solid var(--border-strong,var(--border-hairline));border-radius:10px;background:transparent;color:var(--text-body);position:relative;z-index:1}
.hd-preset:hover{border-color:var(--acc-copper);background:rgba(255,138,92,.08)}
.hd-preset span,
.hd-preset::after{color:var(--acc-copper)}
.hd-free input{color:var(--text-body);border-bottom-color:var(--border-strong,var(--border-hairline))}
.hd-free input:focus{border-color:var(--acc-copper)}
.hd-kicker{color:var(--text-muted)}
.hd-said{color:var(--text-muted)}
.hd-rule{background:var(--acc-copper)}
.hd-reframe{color:var(--text-body)}
.hd-reframe em{background:linear-gradient(92deg,var(--acc-copper),var(--acc-violet));-webkit-background-clip:text;background-clip:text;color:transparent}
.hd-reset{color:var(--text-faint)}
.hd-reset:hover{color:var(--acc-amber)}
/* receipts: the expand buttons live inside the prototype cells */
body.p-home .rcell{display:flex;flex-direction:column;align-items:flex-start}
body.p-home .rcpt-btn{margin-top:16px;background:transparent;border:1px solid var(--border-strong);border-radius:999px;color:var(--rc);font-family:var(--mono);font-size:11px;letter-spacing:.02em;padding:8px 16px;cursor:pointer}
body.p-home .rcpt-btn:hover{border-color:var(--rc)}
body.p-home .rcpt{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:12px;padding:24px;margin-top:16px}
body.p-home .rcpt h3{font-size:20px;margin-bottom:12px}
body.p-home .rcpt-l{flex:0 0 140px;font-family:var(--mono);font-size:11px;letter-spacing:.02em;color:var(--text-faint)}
body.p-home .rcpt-v{color:var(--text-muted);font-size:14px}
/* contract demo */
body.p-home .demo-slot .ccd{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:var(--radius-2);padding:24px;position:relative;overflow:hidden}
body.p-home .ccd-cap{font-family:var(--mono);font-size:11.5px;letter-spacing:.02em;color:var(--text-faint);display:flex;justify-content:space-between;margin-bottom:16px}
body.p-home .ccd-cap b{color:var(--acc-amber)}
body.p-home .ccd-ctr{background:var(--surface-page);border:1px solid var(--border-strong);border-radius:8px;color:var(--text-muted);padding:16px 16px;font-family:var(--mono);font-size:12.5px;line-height:1.9;margin-bottom:12px}
body.p-home .ccd-ctr b{color:var(--text-body)}
body.p-home .ccd-qs{display:flex;flex-direction:column;gap:8px}
body.p-home .ccd-q{background:transparent;border:1px solid var(--accent);border-radius:8px;color:var(--acc-amber);font-family:var(--mono);font-size:12.5px;padding:12px 16px;text-align:left;cursor:pointer}
body.p-home .ccd-q:hover{background:var(--act-wash)}
body.p-home .ccd-ans{margin-top:16px;color:var(--text-muted);font-size:16px;line-height:1.6}
body.p-home .ccd-idle,
body.p-home .ccd-note,
body.p-home .ccd-src{color:var(--text-faint);font-family:var(--mono);font-size:11px}
body.p-home .ccd-tag--in{color:var(--status-positive);border:1.5px solid var(--status-positive);border-radius:4px;padding:2px 8px;font-size:10px}
body.p-home .ccd-tag--out{color:var(--acc-rose);border:1.5px solid var(--acc-rose);border-radius:4px;padding:2px 8px;font-size:10px}
body.p-home .contract-links{margin-top:24px;display:flex;flex-wrap:wrap;gap:20px;font-family:var(--mono);font-size:11.5px;letter-spacing:.02em}
body.p-home .contract-links a{color:var(--acc-amber);text-decoration:underline;text-underline-offset:3px}
/* 2026-09-10: the whole .form-slot block, plus .sig (the "— Arpit"
   signature), deleted with direction A. Verified 0 uses site-wide. */
/* diagnostic list needs its own rhythm inside the prototype card */
.hd-presets{display:flex;flex-direction:column;gap:8px}
.hd-preset{display:flex;align-items:center;gap:12px;padding:12px 16px;font-size:16px;line-height:1.5;text-decoration:none}
.hd-preset span{flex:0 0 auto;font-family:var(--mono);font-size:11px}
.hd-preset::after{content:"→";margin-left:auto;padding-left:12px;opacity:.5}
.hd-preset:hover::after{opacity:1}
.hd-free{margin-top:16px;display:flex;align-items:flex-end;gap:8px}
.hd-free input{flex:1 1 auto;background:transparent;border:none;border-bottom:1px solid var(--border-strong,var(--border-hairline));font-family:var(--serif);font-style:italic;font-size:15px;padding:8px 2px}
.hd-diag > a{display:block;margin-top:16px;font-family:var(--mono);font-size:11px;letter-spacing:.02em;color:var(--text-muted)}
.hd-diag > a:hover{color:var(--acc-amber)}
/* REMOVED 2026-08-17: eleven prototype-era homepage nav rules (a.nl, .pill, .hd, .logo,
   header) that matched NOTHING on the shipped page — verified 0 matches each in the
   browser. Only `nav ul{gap:24px}
` was still live, and only because a generic element
   selector retargeted itself onto the real <ul class="nav-links">, holding the homepage
   nav at 24px while every other page sat at the system's 40px. The dead
   `body.p-home header{position:sticky}
` from the same block is what made today's banner
   wrapper a second sticky bar. The homepage now inherits .nav-links{gap:40px}
. */
/* nav CTA: the prototype pill sizing, not the classic block */
body.p-home .nav-cta{white-space:nowrap}
/* dark ink on the hot gradient: cream measured 2.21:1 */
@media (max-width:640px){/* the QC slip is a rotated cream artifact — its rotated box overflowed the
     viewport by 23px at 390 (measured in a real viewport, not headless) */
  body.p-home .qc-slot{overflow:hidden;padding:0 4px}}
/* ---------- EMBER HOMEPAGE · hero fits the viewport; receipts get their rhythm ----------
   Measured 2026-08-13 at 1200x785: hero was 942px tall against 708px of usable
   height (viewport minus the 77px sticky nav) — it overflowed by 234px, so the
   credentials line and the CTAs sat below the fold on a laptop. The h1 clamp now
   answers to viewport HEIGHT as well as width, and the band padding is fluid. */
body.p-home .hero{--navh:93px;padding:calc(var(--navh) + clamp(24px,4vh,48px)) 0 clamp(48px,8vh,120px);min-height:100svh;display:flex;align-items:center}
@media (max-width:900px){body.p-home .hero{--navh:76px}}
body.p-home .hero h1{font-size:clamp(38px,min(7.2vw,9.2vh),106px);max-width:16ch;margin:clamp(16px,2.2vh,24px) 0 clamp(16px,2.2vh,24px)}
body.p-home .hero .ctas{margin-top:clamp(20px,3.2vh,32px)}
@media (max-width:1040px){body.p-home .hero{min-height:0;display:block}}
/* the inline receipt panels use .rcpt-row / .rcpt-l / .rcpt-v — NOT the .rcpt-r*
   names I first wrote, so under Ember they inherited zero padding and read as one
   solid block. Real class names, real rhythm. */
body.p-home .rcpt{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:12px;padding:24px 32px;margin-top:16px}
body.p-home .rcpt-h{font-family:var(--serif);font-weight:400;font-size:22px;line-height:1.3;margin:0 0 16px;color:var(--text-body)}
body.p-home .rcpt-rows{display:flex;flex-direction:column}
body.p-home .rcpt-row{display:grid;grid-template-columns:132px minmax(0,1fr);gap:24px;align-items:baseline;padding:16px 0;border-bottom:1px solid var(--border-strong)}
body.p-home .rcpt-row:last-of-type{border-bottom:none}
body.p-home .rcpt-l{font-family:var(--mono);font-size:11px;letter-spacing:.02em;line-height:1.8;color:var(--text-faint)}
body.p-home .rcpt-v{font-size:14.5px;line-height:1.75;color:var(--text-muted)}
body.p-home .rcpt{position:relative}
body.p-home .rcpt-h{padding-right:110px}
/* corner reserved for .rcpt-close */
body.p-home .rcpt-close{position:absolute;top:20px;right:20px;min-width:44px;min-height:44px;font-family:var(--ff-label);font-weight:600;font-size:11px;letter-spacing:.02em;color:var(--text-faint);background:none;border:1px solid var(--border-strong);border-radius:8px;padding:0 16px;cursor:pointer}
body.p-home .rcpt-close:hover{color:var(--text-body);border-color:var(--accent)}
body.p-home .rcpt-more{display:inline-block;margin-top:16px;font-family:var(--mono);font-size:11.5px;letter-spacing:.02em;color:var(--acc-amber);text-decoration:underline;text-underline-offset:3px;border-bottom:none;padding-bottom:0}
/* classic drew a border-bottom AND ember drew
  text-decoration — two underlines. One voice: the text-decoration. */
@media (max-width:640px){body.p-home .rcpt-row{grid-template-columns:1fr;gap:4px}
body.p-home .rcpt{padding:20px 20px}}
/* ---------- EMBER HOMEPAGE · class-name collisions with the classic sheet ----------
   The prototype names its sections .lead/.work/.close etc. Classic already owns
   .lead as a TYPOGRAPHY class (font + max-width:46ch), so <section class="lead">
   inherited a 534px reading measure: the memo cards rendered 144px wide and the
   two letters 218px. Measured 2026-08-13 by walking the memo's ancestor chain.
   Six names collide (.wrap .k .hand .lead .lede .m) — reset what the prototype
   does not declare, on the homepage only. */
body.p-home main > section{max-width:none;width:auto}
body.p-home section.lead{font-family:var(--sans);font-size:16px;font-weight:400;line-height:1.7;color:var(--text-body)}
body.p-home .work .lede{max-width:none}
/* REVERTED 2026-08-16 (Arpit caught it: "on mobile button still of the old design system").
   This block used to flatten the hero CTA to a solid #FFB08E below 640px, on the strength of a
   "measured 3.51:1" reading. That reading was wrong — it came from the same contrast audit that
   was reading `color` instead of `fill` and inventing 344 phantom failures. Measured properly,
   the dark ink #1A0D08 sits at 8.18:1 on the ember stop and 7.22:1 on the violet stop: the
   gradient never had a contrast problem. So the site's primary call to action wore a different
   fill from the nav CTA on every phone, to satisfy a number that did not exist. The gradient IS
   the CTA grammar; a gate reading is not a reason to abandon it. */

/* ================================================================
   EMBER · CASE STUDIES — the prototype grammar applied to the case
   page's own components. Each case carries one heat as its identity
   (matching its lane on the homepage). The client-product
   reconstructions (.plA/.plB/.pl*, .recon, .rx*) are period artifacts
   and are deliberately NOT reskinned — same rule as the cream objects.
   ================================================================ */
body[class*="p-case-studies"]{--act:var(--acc-copper)}
body.p-case-studies-adtech{--act:var(--acc-copper)}
body.p-case-studies-fintech{--act:var(--acc-violet)}
body.p-case-studies-vc-diligence{--act:var(--acc-amber)}
body.p-case-studies-ptc{--act:var(--acc-rose)}
body.p-case-studies-o2{--act:var(--acc-violet)}
body.p-case-studies-orgos{--act:var(--acc-copper)}
/* --- hero: the gradient field, tinted by the case's heat --- */
body[class*="p-case-studies"] .case-hero{position:relative;overflow:hidden;padding:calc(93px + clamp(24px,4vh,48px)) 0 clamp(48px,8vh,96px)}
body[class*="p-case-studies"] .case-hero::before{content:"";position:absolute;inset:0;pointer-events:none;background:var(--glow)}
body[class*="p-case-studies"] .case-hero__in{position:relative;z-index:1}
body[class*="p-case-studies"] .case-hero__kicker{color:var(--act)}
body[class*="p-case-studies"] .case-hero h1{font-size:clamp(38px,min(6vw,8.4vh),82px);margin:20px 0 20px}
body[class*="p-case-studies"] .case-hero__hook{font-size:clamp(16px,1.5vw,19px);line-height:1.7;color:var(--text-muted);max-width:60ch}
body[class*="p-case-studies"] .case-hero .hand{color:var(--acc-amber)}
/* --- the stat row: heat-coded cards, the homepage receipts language --- */
/* auto-fit orphaned the third stat at mid widths (2+1 with a half-band void,
   every case hero at 768 — 2026-09-02 sweep). Stepped instead: 3-across,
   then 2-across with an odd last card spanning, then a single column. */
body[class*="p-case-studies"] .case-stats{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px;margin-top:32px}
@media (max-width:899px){body[class*="p-case-studies"] .case-stats{grid-template-columns:repeat(2,minmax(0,1fr))}
body[class*="p-case-studies"] .case-stats > *:nth-child(3):last-child{grid-column:1/-1}}
@media (max-width:560px){body[class*="p-case-studies"] .case-stats{grid-template-columns:1fr}
body[class*="p-case-studies"] .case-stats > *:nth-child(3):last-child{grid-column:auto}}
body[class*="p-case-studies"] .case-stat{background:var(--surface-card);border:none;border-top:3px solid var(--act);border-radius:var(--radius-2);padding:20px}
body[class*="p-case-studies"] .case-stat b{display:block;font-family:var(--ff-display);font-weight:400;font-size:clamp(24px,2.4vw,34px);line-height:1.15;color:var(--act)}
body[class*="p-case-studies"] .case-stat span{display:block;margin-top:8px;font-family:var(--ff-label);font-size:11.5px;letter-spacing:.02em;color:var(--text-muted);line-height:1.8}
/* --- vitals: a quiet card strip, not a bare dl --- */
body[class*="p-case-studies"] .case-vitals{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:var(--radius-2);padding:20px 24px;gap:24px 32px}
body[class*="p-case-studies"] .case-vitals dt{font-family:var(--ff-label);font-size:11px;letter-spacing:.02em;color:var(--text-faint)}
body[class*="p-case-studies"] .case-vitals dd{color:var(--text-body);margin-top:4px}
body[class*="p-case-studies"] .case-vitals .gold{color:var(--act)}
/* --- ownership + receipt blocks: bordered cards with the label column --- */
body[class*="p-case-studies"] .framed-tight,
body[class*="p-case-studies"] .framed{background:var(--surface-card);border:1px solid var(--border-strong);border-left:3px solid var(--act);border-radius:var(--radius-2);padding:8px 24px}
body[class*="p-case-studies"] :is(.rcpt-r,.rcpt-r-tight,.rcpt-r-last,.rcpt-r-tight-last){display:grid;grid-template-columns:150px minmax(0,1fr);gap:24px;align-items:baseline;padding:16px 0;border-bottom:1px solid var(--border-strong)}
body[class*="p-case-studies"] :is(.rcpt-r-last,.rcpt-r-tight-last){border-bottom:none}
body[class*="p-case-studies"] .lbl-eyebrow{color:var(--text-faint);line-height:1.8}
@media (max-width:640px){body[class*="p-case-studies"] :is(.rcpt-r,.rcpt-r-tight,.rcpt-r-last,.rcpt-r-tight-last){grid-template-columns:1fr;gap:4px}}
/* --- pull quotes: the heat rail --- */
body[class*="p-case-studies"] .t-quote,
body[class*="p-case-studies"] blockquote{border-left:3px solid var(--act);background:var(--surface-card);border-radius:0 10px 10px 0;padding:20px 24px}
/* DIAGRAMS GET THE ROOM THEY WERE DRAWN FOR (Arpit: "it feels like squeezed", 2026-08-17).
   Measured, not felt: patterns/reversibility-safe-to-act.html draws at viewBox 1280x400
   and rendered 493px wide — scale 0.385, so a 14px label painted at 5.4px. The inner
   pattern pages ran 0.38-0.41; the case studies, not boxed into the same narrow column,
   ran 0.81-0.88. The figure steps out of the measure column the way the Lab specimen
   does. Symmetric, because the column is already centred (figure spanned 473..966 in a
   1440 viewport). Below 768 it stays in column — there is no room to step into. */
@media (min-width:768px){/* Widen the FIGURE, not the svg. Widening only the svg clipped it to nothing on every
     diagram whose figure carries overflow:hidden (act-review-ignore lost its outer thirds
     to the dark page, text cut mid-word) while diagrams with overflow:visible happened to
     look fine. The container paints the cream and owns the clip, so it has to move first;
     the svg then simply fills it. */
  :is(body[class*="p-patterns"],body.p-process) figure:has(svg.art-svg){--art-w:min(1120px,calc(100vw - 128px))}
:is(body[class*="p-patterns"],body.p-process) figure:has(svg.art-svg) svg.art-svg{width:100%;height:auto;max-width:none;margin:0}}
/* (a duplicated fragment of the note above, restored as a comment on 2026-09-12 — it had lost
   its opener and the browser read it as a selector, dropping .btn-row's alignment rule)
   ) which threw the pair
   to opposite ends of a 632px column — 283px apart, so they stopped reading as a pair —
   while planit had no such class and sat them together. Two arrangements for one component
   across eight pages, which is the same complaint as the nine fills. Arpit's call: the
   two sit at the ENDS of the block — the arrangement seven of the eight already had.
   (I first normalised to flex-start, which was my preference substituted for his; the
   majority arrangement was the one to normalise TO.) Primary left, secondary right. */
body[class*="p-case-studies"] .btn-row{align-items:center;gap:16px}
/* .measure-c caps the whole case body at 595px — right for prose, wrong for the
   card components, which sat centred in a narrow column with dead space either
   side. Widen the container; give the PROSE its measure back explicitly; pin the
   client-product reconstructions to their original width so widening the column
   cannot distort a period artifact. */
body[class*="p-case-studies"] .measure-c{max-width:1100px;padding:0 24px}
body[class*="p-case-studies"] .measure-c > :is(p,h2,h3,ul,ol,blockquote,.t-quote),
body[class*="p-case-studies"] .measure-c > div > :is(p,h2,h3){max-width:66ch}
/* This rule used to do TWO things through one wildcard, and only one of them
   was intended. `[class^="pl"],[class*=" pl"]` matches every DESCENDANT of
   every mockup — 45-50 elements per case study, not the one plate.
     * max-width:640px on those descendants is LOAD-BEARING. The plate itself
       is width:max-content, so the children's cap is what actually sizes it.
       Removing it widened every plate from 642px to 862px. It stays.
     * margin-left:0 on those descendants was never intended and flattened
       every deliberate indent inside the reconstructions: .plF-more lost the
       8px that holds "2 more sources" off the button beside it (measured gap
       0px, at every width) and the "analyst override logged" chip lost its
       12px inset. That half is now scoped to the plate ROOTS, which are the
       only things that were ever meant to be pulled back to the margin.
   A generic selector quietly doing a second job is lesson 10 in a new
   costume — and this time the second job was the one worth keeping. */
body[class*="p-case-studies"] :is(.plA,.plB,.plC,.recon,.recon-stage,[class^="pl"],[class*=" pl"]){max-width:640px}
/* The ownership split, named once. Every case carrying it repeated the same
   four values as per-page .xi-* classes, so a new case had to remember all
   four or render differently. Scoped to .own-split and NOT to .framed-tight,
   because that class also wraps four other kinds of block on the AdTech pages
   — styling it would be one generic selector quietly doing a second job. */
body[class*="p-case-studies"] .own-split{overflow:hidden}
body[class*="p-case-studies"] .own-split > div:nth-child(odd){background:color-mix(in srgb, var(--accent-text) 4%, transparent)}
body[class*="p-case-studies"] .own-split > div > :first-child{flex:0 0 200px}
body[class*="p-case-studies"] .own-split > div > :last-child{flex:1 1 240px}
body[class*="p-case-studies"] :is(.plA,.plB,.plC,.plF,.plM,.plO,.plP,.plV,
  .recon,.recon-stage){margin-left:0}
body[class*="p-case-studies"] .case-hero__in{max-width:1100px;padding:0 24px;margin:0 auto}
/* widening the container cost the prose its reading measure (body copy ran to
   ~1050px). Cap the TEXT wherever it sits in the flow; inside cards let the
   card's own width govern so no card carries a dead right-hand column. */
body[class*="p-case-studies"] .measure-c :is(p,h2,h3,li,blockquote){max-width:66ch}
body[class*="p-case-studies"] :is(.framed,.framed-tight,.case-vitals,.t-quote) :is(p,h2,h3,li,div,dd,dt,blockquote){max-width:none}
body[class*="p-case-studies"] .framed{max-width:76ch}
/* GESTALT · PROXIMITY — the walk-through CTA sat in its own right-hand column.
   Measured: only 32px from the text BLOCK, but the prose wraps at 62ch, so the
   real distance from the last word to the link was ~200px of void and the two
   read as unrelated objects. The CTA now joins the text group: same column,
   directly under the hook, so one lane = one visual unit. */
/* the lane has THREE children: metric, one wrapper holding <h3>+<p>, and .go.
   A three-row template left a phantom empty 'desc' row (measured 74px between
   hook and CTA). Two rows match the real DOM. */
/* rows were centring their content, adding ~56px of slack between the hook and
   its CTA (measured 78px total). Hug the content; keep the metric column
   optically centred against the whole lane. */
/* MOBILE MENU — the prototype's `nav ul{display:flex}
` (specificity 0,3,2 once
   scoped) outranked classic's @media(max-width:1100px){.nav-links{display:none}}
(0,1,0), so the drawer was permanently open: the toggle fired correctly
   (class + aria both flipped, measured) but nothing ever hid. Restore the
   drawer behaviour at the classic breakpoint. */
@media (max-width:1100px){body.p-home .nav-links{display:none;flex-direction:column;align-items:stretch;position:fixed;top:64px;left:0;right:0;background:color-mix(in srgb, var(--surface-page) 97%, transparent);padding:32px 24px;gap:24px;border-bottom:1px solid var(--border-strong);z-index:99}
body.p-home .nav-links.nav-open{display:flex}}
/* ================================================================
   GESTALT PASS — 52 measured findings, independently re-verified,
   deduplicated to component-level fixes. Full plan + evidence:
   workflow wf_c6f0cf1b-6c2.
   Framing: ember.css only scopes p-home and p-case-studies; the other
   six page groups run classic CSS under Ember tokens. ~25 of the 52
   findings are that one gap — these are the interim patch, NOT the
   port (task #5).
   ================================================================ */

/* --- T1.1 · plate captions amputated at the window edge (126px lost at
   1440, 131px of 358 at 390). Must sit AFTER ember.css:706 [class^="pl"]
   — equal specificity, order decides. --- */
body[class*="p-case-studies"] :is(.plA,.plB,.plC,.plA-caption,.plB-caption,.plC-caption){margin-right:0;transform:none;width:auto}
/* --- T1.2 · /lab/loop.html demo inputs at 1.03:1 — the numbers driving
   abstain() were invisible --- */
body.p-lab-loop .lab-ctl input[type="number"],
body.p-lab-loop .act-cream .lab-ctl input[type="number"]{background:var(--surface-sunken);color:var(--text-body);border:1px solid var(--border-strong)}
/* --- T1.4 · "In production" badge 2.01:1, nine uses sitewide --- */
.lbl-badge-ink{color:var(--btn-fill-ink)}
body.p-writing .xi-writing-020:hover{transform:translateY(-4px)}
body.p-home .receipts .hand{margin-top:24px}
body.p-home .receipts .rrow{margin-top:20px}
body.p-home .rcell span{margin-bottom:16px}
body.p-home .rcell .rcpt-btn{margin-top:auto}
/* --- T2.8 · work lanes had no right edge (36% of each lane dissolved into
   the band) and the skew left a 12.3px staircase at 390 --- */
/* single-axis lanes: .go shares the left axis, no skew to correct */

/* --- T2.9 · demo card carried an orphaned top:104px from the classic
   layout. (The hero eyebrow alignment half of this finding is NOT applied:
   it trades two 74px slivers for one 148px void — see report.) --- */
body.p-home .demo-slot .ccd{top:auto}
/* --- T3.10 · .case-stat span: a 22ch cap re-resolved in 11.5px mono left
   half of every stat card empty --- */
body[class*="p-case-studies"] .case-stat span{max-width:none}
/* --- T3.11 · .rcpt-box was byte-identical to .framed-tight in classic;
   Ember promoted one to a rail-card and left the other bare --- */
body[class*="p-case-studies"] .rcpt-box{background:var(--surface-card);border:1px solid var(--border-strong);border-left:3px solid var(--act);border-radius:var(--radius-2);padding:8px 24px}
/* --- T3.12 · quote cards drawn twice: my rule hit both parent and child,
   giving two identical 3px rails 24px apart --- */
body[class*="p-case-studies"] :is(figure,blockquote) .t-quote{background:none;border:0;border-radius:0;padding:0;max-width:none}
/* --- T3.13 · .case-vitals: a 32px column-gap turned a contiguous strip
   into floating rules and stranded the 6th cell. Grid neutralises the
   classic flex:1 1 160px that survives Ember. --- */
body[class*="p-case-studies"] .case-vitals{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:0;padding:0}
body[class*="p-case-studies"] .case-vitals > div{padding:20px 24px;border-right:1px solid var(--border-strong)}
body[class*="p-case-studies"] .case-vitals > div:nth-child(3n),
body[class*="p-case-studies"] .case-vitals > div:last-child{border-right:0}
body[class*="p-case-studies"] .case-vitals > div:nth-child(n+4){border-top:1px solid var(--border-strong)}
@media (max-width:640px){body[class*="p-case-studies"] .case-vitals{grid-template-columns:1fr}
body[class*="p-case-studies"] .case-vitals > div{border-right:0}
body[class*="p-case-studies"] .case-vitals > div + div{border-top:1px solid var(--border-strong)}}
/* --- T3.14 · one heat per case: leftover gold rails sat 26px from heat
   rails on identical cards --- */
body[class*="p-case-studies"] :is(.case-gate,.note-gold,.note-gold-b,.pullq){border-left-color:var(--act)}
body[class*="p-case-studies"] :is(.case-gate .cg-l,.case-gate b){color:var(--act)}
/* --- T3.15/16 · .case-jump glued to the wrong card (8px above / 48px
   below); .case-gate 37% empty --- */
body[class*="p-case-studies"] .case-gate{margin-bottom:40px;max-width:688px}
body[class*="p-case-studies"] .case-jump{margin:0 0 24px}
/* --- T4.18 · /screen/ mono roles destroyed by a :where() rule (0
   specificity) — needs REAL specificity, not later order --- */
body.p-screen .scr-q p.scr-num{font-family:var(--ff-label);font-size:var(--fs-eyebrow);letter-spacing:.15em;color:var(--acc-amber);margin:0 0 8px}
body.p-screen .scr-q p.scr-receipt{font-family:var(--ff-label);font-size:var(--fs-caption);letter-spacing:.08em;line-height:1.7;color:var(--text-faint);margin:24px 0 0}
/* --- T4.19/20 · lab output tiers collapsed; one chart series below the
   WCAG floor (2.79:1) --- */
body.p-lab-loop .lab-fn .lab-explain{font-size:var(--fs-ui);line-height:1.7;max-width:none}
body.p-lab-loop .lab-fn .lab-json{font-size:var(--fs-caption);line-height:1.7;max-width:none;margin:0}
/* --- T4.21 · patterns: metadata unpinned, wireframe greys 12x apart,
   gold card not closing evenly --- */
body.p-patterns .card-p28{display:flex;flex-direction:column}
body.p-patterns .card-p28 .lbl-cap{margin-top:auto}
.card-wire .row-ic > div:first-child{background:var(--bar-track);opacity:1}
.card-wire .row-ic > div + div{background:var(--border-hairline)}
.card-gold{background:var(--surface-card);border-color:var(--border-strong);border-left:3px solid var(--acc-amber);border-radius:var(--radius-2)}
.card-gold > :last-child,
.card-gold > :last-child > :last-child{margin-bottom:0}
@media (max-width:600px){body.p-writing .xi-writing-018{letter-spacing:.1em}}
/* --- T4.24 · hire/screen remainder. .hand carries its own margin, so
   clearance comes from the FOLLOWING sibling; .xi-hire-005 forces the span
   colour, so the PARENT is muted instead. --- */
body.p-hire .hand + .hire-receipts,
body.p-screen .hand + .scr-q{margin-top:24px}
.card-seg{border-radius:8px}
body.p-home .demo-slot .ccd{margin-top:0}
/* ================================================================
   PLATE CENTERING — REGRESSION I CAUSED, NOW REVERTED
   Every reconstruction plate and caption centres itself with the same
   trick: width:min(840px,…) · margin:… 50% … · transform:translateX(-50%).
   My earlier rule set margin-left:0 and max-width:640px but LEFT THE
   TRANSFORM IN PLACE, so each plate slid half its own width to the left —
   off the viewport on PTC, and the whole case column read as left-shifted.
   The T1.1 "fix" then named .plB/.plC, which do not exist; the real classes
   are plA plF plM plO plP plV. Restore the classic centering, bounded by the
   CONTAINER (100%) rather than the viewport so the wider Ember column can
   never push a plate off-screen.
   ================================================================ */
body[class*="p-case-studies"] :is(.plA,.plF,.plM,.plO,.plP,.plV){width:min(840px,100%);max-width:none;margin:32px 50% 8px;transform:translateX(-50%)}
body[class*="p-case-studies"] :is(.plA-caption,.plF-caption,.plM-caption,.plO-caption,.plP-caption,.plV-caption){width:min(840px,100%);max-width:none;margin:0 50% 24px;transform:translateX(-50%)}
body[class*="p-case-studies"] :is(.recon,.recon-stage){max-width:none;margin-left:auto;margin-right:auto}
@media (max-width:900px){body[class*="p-case-studies"] :is(.plA,.plF,.plM,.plO,.plP,.plV,
    .plA-caption,.plF-caption,.plM-caption,.plO-caption,.plP-caption,.plV-caption){width:100%;margin-left:0;margin-right:0;transform:none}}
/* --- NEGATIVE SPACE · the boundary notes ---
   .note-gold / .note-gold-b span the full 1052px column while their prose is
   capped at 60–62ch by a page-level rule (styles.css:1855/1857) — so ~40% of
   each card was empty on the right. Cap the CARD to its content instead of
   letting it stretch. Same treatment the .framed cards already have. --- */
body[class*="p-case-studies"] :is(.note-gold,.note-gold-b){max-width:60ch}
/* 76ch still left 182px (25%) dead; the prose is pinned at
                      62ch, so the card is sized to text + padding */

/* --- FOOTER · text was touching the frame edges --- */
footer{padding:40px 48px;gap:24px}
/* 2026-09-10 — the footer's TYPOGRAPHY now applies to every page, not just the
   homepage. It was declared only on `body.p-home footer` (mono 12px, dim), so the
   other 37 footers inherited the body's sans 16px. Nothing VISIBLE differed —
   .footer-note, .footer-logo, .footer-back and .dyslexia-toggle all declare their
   own font, and I overstated this to Arpit as a visible defect before measuring;
   only .footer-tools, a wrapper holding no text of its own, drifted. But that is a
   loaded gun: the first bare text anyone adds to the footer would render mono on
   the homepage and sans on 37 others. Execution lesson 11 — declare, do not
   inherit. Padding and the border stay where they were; this is type only.
   USES --ff-mono / --ink-dim, NOT --mono / --dim. The homepage rule this copies
   spells them --mono and --dim, and those two custom properties are declared
   ONLY on `body.p-home`. In an all-pages rule they are undefined, so the
   declarations are invalid at computed-value time and fall back to inherited —
   silently. My first version did exactly that: font-size applied on all 38
   pages while family and colour applied on one, which is the same drift wearing
   a different hat. --ff-mono and --ink-dim are declared at the theme root. */
footer{font-family:var(--ff-mono),ui-monospace,monospace;font-size:12px;color:var(--text-faint)}
body.p-home footer{max-width:1240px;margin:0 auto;padding-left:40px;padding-right:40px}
@media (max-width:640px){footer{padding:32px 20px;flex-wrap:wrap}
body.p-home footer{padding-left:20px;padding-right:20px}}
/* ================================================================
   TASK #5 — THE PORT. The six page groups that carried data-theme
   ="ember" but zero Ember component rules (the Gestalt audit's
   headline finding: ~25 of 52 defects traced to this one gap).
   Same method as the case studies: Ember GRAMMAR on each group's own
   components — gradient hero field, one heat per group, card shells,
   seams, pill controls — not a DOM rebuild. The cream artifacts and
   the wireframe specimens keep their conventions.
   ================================================================ */
body.p-patterns{--act:var(--acc-amber)}
:is(body[class*="p-lab"],body.p-fit){--act:var(--acc-violet)}
body.p-screen{--act:var(--acc-rose)}
body[class*="p-writing"]{--act:var(--acc-violet)}
body[class*="p-resources"]{--act:var(--acc-copper)}
/* --- shared: every ported page gets the hero field + heat accents --- */
:is(body.p-patterns,body[class*="p-lab"],body.p-fit,body.p-hire,body.p-screen,
  body[class*="p-writing"],body[class*="p-resources"]) :is(.eyebrow,.lbl-eyebrow,.scr-kicker){color:var(--act)}
:is(body.p-patterns,body[class*="p-lab"],body.p-fit,body.p-hire,body.p-screen,
  body[class*="p-writing"],body[class*="p-resources"]) .hand{color:var(--acc-amber)}
/* --- the page header becomes a gradient field, tinted by the group's heat --- */
:is(body.p-patterns,body[class*="p-lab"],body.p-fit,body.p-hire,body.p-screen,
  body[class*="p-writing"],body[class*="p-resources"]) > header:first-of-type,
body.p-patterns main > section:first-of-type,
body:is([class*="p-lab"],.p-fit) .lab-hero,
body[class*="p-writing"] header,
body.p-hire .hire-head{position:relative;overflow:hidden;padding-top:calc(93px + clamp(24px,4vh,48px));padding-bottom:clamp(40px,6vh,80px)}
:is(body.p-patterns main > section:first-of-type,
  body[class*="p-lab"] .lab-hero, body.p-fit .lab-hero, body[class*="p-writing"] header, body.p-hire .hire-head)::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:0;background:var(--glow)}
:is(body.p-patterns main > section:first-of-type,
  body[class*="p-lab"] .lab-hero, body.p-fit .lab-hero, body[class*="p-writing"] header, body.p-hire .hire-head) > *{position:relative;z-index:1}
/* --- card shells: the Ember card, not a 4px-radius outline --- */
:is(.card-p28,.card-p32,.framed-blk,.hire-receipt,.hire-quote,.ckl){background:var(--surface-card);border:1px solid var(--border-strong);border-radius:var(--radius-2)}
:is(.card-p28,.card-p32){padding:24px}
.card-p32{padding:32px}
:is(.card-p28,.card-p32,.framed-blk):hover{border-color:var(--accent)}
.card-title{line-height:1.25}
/* the accent rail marks a card as belonging to this page's family */
:is(body.p-patterns,body[class*="p-writing"],body[class*="p-resources"])
  :is(.card-p28,.card-p32){border-left:3px solid var(--act);border-radius:0 12px 12px 0}
/* --- /screen/ : each answered question is a card, not a hairline --- */
body.p-screen .scr-q{background:var(--surface-card);border:1px solid var(--border-strong);border-left:3px solid var(--act);border-radius:var(--radius-2);padding:24px 32px;margin:0 0 20px}
body.p-screen .scr-close{background:var(--surface-sunken);border-radius:12px;padding:32px;margin-top:32px}
/* --- /lab/ : the code surfaces --- */
body:is([class*="p-lab"],.p-fit) :is(.lab-note,.lab-links,.lab-body){border-radius:var(--radius-2)}
body:is([class*="p-lab"],.p-fit) .lab-note{background:var(--surface-card);border:1px solid var(--border-strong);border-left:3px solid var(--act);border-radius:var(--radius-2);padding:20px 24px}
body:is([class*="p-lab"],.p-fit) .t-code,
body:is([class*="p-lab"],.p-fit) .td-inline{color:var(--acc-amber)}
.btn-a-ghost:hover{border-color:var(--act,var(--acc-copper))}
/* CTA (2026-09-10) — the ask is ALWAYS the filled treatment. Measured: the
   gradient reads 7.25:1 to 8.46:1 against the page, the outline it replaces
   read 2.84:1, and WCAG 1.4.11 wants 3:1 for a component's boundary. The
   --cta-ink token is the same near-black the other gradient pills already
   carry, which the pre-push pixel audit has been grading for weeks. */
/* the .cta component moved to the UNLAYERED TAIL of this file — see the end. */
/* --- section rhythm: alternate bands so a long page has acts --- */
:is(body.p-patterns,body[class*="p-writing"],body[class*="p-resources"])
  main > section:nth-of-type(even){background:var(--surface-sunken)}
/* /hire/ and /writing/ put their header INSIDE the max-width wrapper, so the
   gradient field rendered as a boxed card while every other ported page bleeds
   full width. Break it out to the viewport edges. */
:is(body.p-hire .hire-head, body[class*="p-writing"] header){margin-left:calc(50% - 50vw);margin-right:calc(50% - 50vw);padding-left:calc(50vw - 50% + 0px);padding-right:calc(50vw - 50% + 0px)}
/* stacked list-cards stretched the full column while the Gestalt line-length
   fix pins their prose at 54ch — ~45% of each card was dead on the right.
   Same remedy as the case-study boundary notes: size the CARD to its text. */
:is(body[class*="p-writing"],body[class*="p-resources"])
  :is(.card-p32,.card-p28){max-width:520px}
/* MEASURED, not computed: `ch` on
  the card resolves in a different font than the paragraph it wraps, so both
  64ch (126px dead) and calc(54ch + 64px) (94px dead) overshot. 54ch of prose
  measures 456px; + 2x32 padding = 520. */

/* ================================================================
   SCAN PATH + NEGATIVE SPACE + LINK COLOUR
   Measured 2026-08-13, at 1440:
   · lane had TWO reading axes 242px apart (metric 177 / title 419) and
     402px of dead right — six lanes = twelve horizontal saccades to read
     a list. Collapse to ONE axis: the eye drops straight down.
   · every one of the 37 paragraphs on a case page was 475px wide inside an
     1100px container: 442px (40%) dead right, on every paragraph. A capped
     column in a wide container is a decision about the leftover space —
     so narrow the READING SPINE and let objects break out of it instead.
   · links were amber, i.e. the retired gold. Violet is the other end of the
     signature gradient: unmistakably Ember, 7.4:1 on the base and 6.3:1 on
     card fill, and distinct from the amber focus ring (which stays amber
     precisely so focus never reads as "just a link").
   ================================================================ */

/* --- 1 · lanes: one reading axis on the left, the action parked top-right ---
   The text keeps a single left axis (no sideways saccade). The CTA no longer
   costs its own row: it rides the metric row at the right edge, so every lane
   loses ~34px of height and gains a second, constant anchor the eye can find
   without re-scanning. Anchoring to the metric row (fixed height) — not the
   title (variable) — keeps all six CTAs on a predictable line. */
/* Arpit 2026-08-15: "follow the grid structure — cells in the next row align
   to the previous row." ONE shared column line for all six lanes: a fixed
   200px metric cell, so every title starts on the same vertical axis and the
   eye scans straight down. CTA stays in the content column's reading axis. */
/* CTA removed 2026-08-15 (Arpit): the whole row is the link; hover carries the
   affordance (bg tint + border heat already defined on .lane:hover) */
/* phone: no room for a right-hand column — stack, action last */
/* --- 2 · the reading spine, with objects breaking out of it --- */
body[class*="p-case-studies"] .measure-c{max-width:704px;margin-left:auto;margin-right:auto;padding:0 24px}
body[class*="p-case-studies"] .measure-c :is(p,h2,h3,li,blockquote){max-width:none}
/* the hero figure lives OUTSIDE the spine — it is already full-bleed, so the
   breakout would shove it off the right edge (measured left=624 right=1664). */
body[class*="p-case-studies"] .case-hero__in{max-width:1040px}
/* the quote's rule was sitting ON the text — the extraction stripped the
   padding that used to hold it off. Declare it here, on the component. */
body[class*="p-case-studies"] blockquote.t-quote,
blockquote.t-quote{padding-left:24px}
/* the boundary/gate cards now match the spine rather than floating inside it */
body[class*="p-case-studies"] :is(.note-gold,.note-gold-b,.case-gate,.framed,.rcpt-box,.framed-tight){max-width:none}
/* The :not(.lane) guards below are inert now that .lane is gone, and they stay:
   a :not() argument carries its own specificity, so deleting one lowers these
   rules by 0,1,0 and could flip which rule wins on every link in main and
   footer. Inert is cheaper than a cascade change. */
:is(main,footer) a:not(.lane):not(.cta):hover{color:var(--link-ink-hover)}
.rfoot a,
.who p a,
.errata a,
.contract-links a{color:var(--link-ink)}
/* the single-axis lane left 548px dead on its right (the hook caps at 72ch
   inside a 1172px card). Cap the LIST to a reading width and centre it: the
   leftover space becomes symmetric page margin — read as intentional — instead
   of a void inside every card. */
/* the section is ONE 860px object — the wrap narrows, so eyebrow, headline,
   lede and lanes all share the same centred column (the per-part centering I
   tried first is exactly what the one-object rule at line ~1630 forbids) */
body.p-home .work .wrap{max-width:1040px}
body.p-home .work .lede,
body.p-home .work h2,
body.p-home .work .k{max-width:none}
/* Writing section — restored to the homepage (my prototype rebuild had dropped
   it while the nav still linked to #thoughts). Ember card grammar, purple heat
   matching the /writing/ page it leads to. */
/* --heat was #A96BFF: 4.99:1 on the card — a number that passes AA and still
   reads badly at 11px. Canon's checked violet is #E86BFF (7.4:1). Same purple
   identity, +42% contrast, and it is already the link colour sitewide. */
body.p-home #thoughts{--act:var(--acc-violet)}
body.p-home .thoughts-grid > *:hover{border-color:var(--accent);border-left-color:var(--act)}
body.p-home .thoughts-grid > *:hover .thought-title{color:var(--act)}
/* ================================================================
   SECTION SEAMS — the diagonal wedge is retired.
   It was a 110px slab with a shallow clip-path pulled up by -60px, so it
   sliced across whatever sat above it (it cut through the standfirst on the
   home hero) and read as a rendering glitch rather than a decision.
   Replaced with a seam that carries information: a hairline in the section's
   own heat colour, fading out at both ends, over a soft wash. Sections now
   separate by tone and hue, and nothing overlaps content.
   ================================================================ */
body.p-home .seam,
body.p-home .seam-up{height:1px;margin:0;clip-path:none;position:relative;z-index:0;overflow:visible;background:linear-gradient(90deg,
    transparent 0%,
    color-mix(in srgb, var(--act, var(--acc-copper)) 55%, transparent) 18%,
    color-mix(in srgb, var(--act, var(--acc-copper)) 55%, transparent) 82%,
    transparent 100%)}
/* the wash: a wide, very low-opacity bloom above the line, so the boundary
   reads as a fade rather than an edge. Sits behind content, never over it. */
body.p-home :is(.seam,.seam-up)::after{content:"";position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;background:linear-gradient(to top,
    color-mix(in srgb, var(--act, var(--acc-copper)) 9%, transparent), transparent);z-index:-1}
@media (prefers-reduced-motion:reduce){body.p-home :is(.seam,.seam-up)::after{height:64px}}
/* The retired wedge was 110px tall and doubled as the section's top spacing —
   removing it left seam-bearing sections with padding-top:0 and their first
   line of text 1px off the boundary (measured on receipts, work, how-i-lead).
   The seam now carries that space explicitly, matching the 96px top rhythm of
   every section that never had one. Space is declared, not inherited from a
   decoration's height. */
body.p-home :is(.seam,.seam-up){margin-bottom:96px}
/* --- three fixes from review, each measured before and after ---------------- */

/* 1. The pattern links sat in a 386px box inside an 875px parent, so both long
      links wrapped to two lines for no reason. Give them the width that was
      already there. */
/* The cap was a fractional 386.4px — a character-based prose measure inherited
   from the typography layer. These are navigation links, not prose: a reading
   measure has no business sizing them, and it forced two of them onto a second
   line inside an 875px parent. Declared on the component, at a specificity that
   beats the typography rule. */
body.p-home p.contract-links{display:flex;flex-wrap:wrap;gap:12px 32px}
body.p-home p.contract-links a{display:inline-block;margin-right:0}
/* nowrap only where the line actually fits. Applied unconditionally it made
   the whole contract section 397px wide inside a 390px viewport and scrolled
   the homepage sideways by 23px — a desktop fix that broke the phone. */
@media (min-width:700px){body.p-home p.contract-links a{white-space:nowrap}}
/* 3. The wordmark was amber while the monogram beside it is the ember→violet
      gradient — two different brand colours touching. The name is not an
      accent; it takes the primary ink and lets the mark carry the colour. */
/* NAV IDENTITY — Arpit's pick, direction C, 2026-09-08, chosen from four
   rendered over the real nav (prototypes/renders/nav/).
   He asked what the opinion was on the prominence of the mark and the
   supporting text. Measured: the name was 14px/600 in var(--ink) — the same
   colour as the nav links, one pixel larger and 200 weight units heavier. So
   it read as an EMPHASISED MENU ITEM rather than as identity, and the two
   objects competed instead of one leading. It also carried the one straight
   defect on the bar: letter-spacing -0.5px on UPPERCASE text, while every
   uppercase neighbour got +.08em. Uppercase needs air, not tightening; that is
   why it looked cramped against the mark.
   C separates the two by CATEGORY, not volume: the name goes quiet and
   properly tracked, tucks in close to the mark, and a hairline divides the
   identity cluster from the link row — so the name stops competing with the
   links because it is visibly not one of them. The mark keeps its 40px and
   stays the only colour in the cluster.
   Scoped to #nav (.row-ic is a generic class used on 41 pages) and to
   min-width:769px, which is exactly where `.nav-logo span{display:none}`
   stops hiding the name — below that there is no name and a hairline after a
   bare mark would be an orphan. Every property is declared on the component,
   not inherited. */
/* AND THE NAME CAME BACK UP — 2026-09-09, Arpit: "the logo and the links are no
   longer looking prominent and their placement doesn't look symmetric". Both
   true, and both mine: direction C above made the name quiet ON THE BASIS that
   it was uppercase and tracked .11em, and hours later the site-wide uppercase
   sweep removed exactly that. The name ended up smaller, dimmer AND lowercase
   at once — measured 13px/500 at 0.76 alpha against links at 13px/400 at full
   ink, so his own name read QUIETER than his menu. Option 2 of four rendered
   over the real nav (prototypes/renders/nav2/): the name leads on size and
   weight instead of on capitals, which is what keeps this inside the no-caps
   decision rather than reversing it. */
#nav .nav-name{font-family:var(--ff-sans);font-size:15px;font-weight:600;letter-spacing:.01em;color:var(--text-body);white-space:nowrap}
@media (min-width:769px){#nav .nav-logo .row-ic{gap:8px}
#nav .nav-logo{padding-right:20px;margin-right:4px;border-right:1px solid var(--border-hairline)}}
/* THREE ZONES, SO THE MENU CANNOT DRIFT — the bar was justify-content:space-between
   with FOUR children (logo, links, CTA and the hamburger), so the link row landed
   in whatever room was left over rather than at the centre: measured 46px left of
   centre at 1101, 62px at 1200, 102px at 1440. It got worse the wider the screen,
   which is why it read as asymmetric on a large display and not on a laptop.
   A 1fr auto 1fr grid puts the links dead centre by construction, whatever the
   logo and CTA measure, so there is no arithmetic left to drift.
   THE BOUNDARY IS 1101px, NOT A ROUND NUMBER, and that matters: styles.css hides
   .nav-links below 1100px, so the prototype's min-width:1000px would have hidden
   the hamburger across 1000-1100px and left that band with NO navigation at all.
   The hamburger is redundant above 1100 — every link and the CTA are already on
   screen, nothing lives only in the drawer there, and as the last item in the row
   it made the eye finish on a menu button instead of the booking button. */
@media (min-width:1101px){#nav{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;justify-content:initial}
#nav .nav-logo{grid-column:1;justify-self:start}
#nav .nav-links{grid-column:2;justify-self:center;gap:32px}
#nav .nav-links a:not(.cta){font-size:14px;font-weight:500;color:var(--text-body)}
#nav .nav-cta{grid-column:3;justify-self:end}}
/* --- Writing section on the standard grammar ------------------------------
   The heading was a classic-theme numeral pattern (.section-numeral) that no
   other homepage section uses, and its aria-labelledby pointed at an id that
   did not exist. Now eyebrow + h2 + lede like every other section. */
body.p-home #thoughts .wr-more{margin-top:16px}
body.p-home #thoughts .wr-more a{font-family:var(--ff-label);font-size:11.5px;letter-spacing:.02em;color:var(--act);white-space:nowrap;border-bottom:1px solid color-mix(in srgb, var(--act) 45%, transparent);padding-bottom:3px;text-decoration:none}
body.p-home #thoughts .wr-more a:hover{border-bottom-color:var(--act)}
/* PHONE: plate internals have fixed track widths, so at 390px the fintech and
   vc plates pushed their content past the edge (measured right=413 and 491).
   Give the plate its own horizontal scroll rather than letting it drag the
   page sideways — wide content scrolls inside its own container. */
@media (max-width:700px){body[class*="p-case-studies"] .measure-c
    :is(.plA,.plF,.plM,.plO,.plP,.plV){-webkit-overflow-scrolling:touch}}
/* 404: the decorative ghost numeral is absolutely positioned and centred by a
   transform, which put its edge 3px past the viewport at 390px. */
body.p-404 .ghost{max-width:calc(100vw - 32px)}
/* ================================================================
   LOPSIDED WHITESPACE — the reading column was capped narrower than its
   container and then left-aligned inside it, so every unused pixel piled up
   on ONE side: 457px on /lab/, 593px on /patterns/, 209px on the homepage.
   The containers were already centred; the text inside them was not. Capped
   text now centres within the space it occupies. Guarded by
   tools/balance-check.py, which ignores genuine two-column bands (prose
   beside an artifact) and only fails on space with nothing in it.
   ================================================================ */
/* descendant, not child: on /patterns/ the prose sits inside an <a> card and on
   /lab/teardown/ inside nested sections, so a child selector missed both.
   Where the text is NOT capped this is a no-op — auto margins only do work
   when there is leftover width to distribute. */
:is(.lab-wrap,.section-inner) :is(p,h1,h2,h3,dl,ul,ol,.lab-note,.lab-body){margin-left:auto;margin-right:auto}
/* homepage: every section EXCEPT the hero, whose left-aligned column is a
   deliberate pairing with the diagnostic card on its right. */
/* Auto-centring applies ONLY to a single-column band, where a capped element
   floats in the full page width. Inside a grid COLUMN (who, patterns) the same
   rule gave eyebrow/body/headline three different left edges (measured
   254/186/140 in one column) — in a column, everything sits flush left. */
body.p-home main > section:not(.hero) .wrap > :is(p,h2,h3){margin-left:auto;margin-right:auto}
body.p-home main > section:not(.hero) .wrap > div > :is(p,h2,h3){margin-left:0;margin-right:0}
/* /lab/ ran TWO prose measures in one column — .lab-lede at 781px and
   .t-body-muted at 1052px — so the column's edge moved as you read down it and
   the leftover space swapped sides. One measure for body text; wide artifacts
   (code, demos, tables) are exempt because they are not prose. */
.lab-wrap :is(p,dl,ul,ol):not(:has(pre)):not(.lab-note){max-width:781px}
/* the "Prefer email?" line under the contact form — restored 2026-08-13 after the
   homepage rebuild dropped #em-l, which both crashed the page script (TypeError,
   stopping every script after it) and removed the public email — a canon
   requirement (recruiters don't fill forms). */
/* the compressed "read first" line — the three alternatives that used to
   occupy 196px ABOVE the form now sit under it as one sentence. Nothing
   was removed; it stopped standing between a reader and the ask. */
body.p-home .contact-read{font-size:14px;line-height:1.6;margin:16px 0 0;color:var(--text-muted)}
/* ---- video evidence on the named case (talon) --------------------------- */
.vid-frame{position:relative;aspect-ratio:16/9;background:var(--surface-card);border:1px solid var(--border-strong);border-radius:12px;overflow:hidden}
.vid-frame iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
.vid-main{margin:32px 0 24px}
.vid-main figcaption,
.vid-card figcaption{display:flex;flex-direction:column;gap:4px;margin-top:12px}
.vid-note{margin:16px 0 32px}
/* ============================================================================
   LEADING — DECLARED ONCE PER COMPONENT (2026-08-18, Arpit's picks)
   Arpit pointed at the hero and a section heading and said the line height
   looked tight. Measured: the hero was 1.01 — 38px type with 38.4px of
   leading, solid-set, wrapping to three lines on a phone with descenders
   running at the next line's ascenders.
   The audit found 78 breaches across 25 pages, and the real fault underneath:
   ELEVEN separate declarations of heading leading, so the same component was
   set at 1.01/1.04/1.10 (h1) and 1.03/1.12/1.15/1.20 (h2) depending on which
   page you were on. Those eleven are now deleted; this is the single source.
   Lesson 11 exactly: a component must DECLARE its critical properties.
   Unitless on purpose — every heading here is on a clamp() size ramp, and a
   px leading would go tight as the type grows.
   Floors that must hold (tools/line-height-check.py):
     >=40px 1.05 · 24-40px 1.15 · 18-24px 1.25 · <18px 1.40
   ============================================================================ */
:is(h1,h2,.section-title,.section-title--lg,.t-hero,.scr-title){line-height:1.15}
h3{line-height:1.30}
/* dd carries prose but sits denser than a paragraph by design; 1.30 put it
   under the body floor while wrapping to three lines. */
dd{line-height:1.5}
/* the stragglers the audit named, each set on its own component rather than
   left to inherit whatever block it happened to sit in */
a.hd-preset{line-height:1.5}
button.footer-back{line-height:1.4}
/* the label wraps to two lines only in a narrow band around 1024 — leading
   that is invisible at 390 and 1440 and tight in between. Testing two
   breakpoints is not testing the range between them (lesson 7). */
.dyslexia-toggle span{line-height:1.45}
/* ---- the site's two wide tables ------------------------------------------
   .ba-table  the before/after conversation on the AdTech case
   .td-table  the measured teardown on /lab/teardown.html
   Above 860px both are real tables in their own scroll container. Below it
   they reflow to cards (see the media block further down) — the scroll
   container was hiding the third column on a phone entirely, which is how
   this ever got noticed. */
:is(.ba-wrap,.td-scroll){overflow-x:auto;-webkit-overflow-scrolling:touch;margin:24px 0 8px}
.ba-table{width:100%;min-width:0;border-collapse:collapse;font-size:14px;line-height:1.5}
.ba-table th{font-family:var(--ff-label);font-size:11.5px;letter-spacing:.02em;color:var(--acc-copper);text-align:left;padding:12px 16px;border-bottom:1px solid var(--accent)}
.ba-table td{padding:12px 16px;border-bottom:1px solid var(--border-strong);color:var(--text-body);vertical-align:top}
.ba-table td:nth-child(2){color:var(--text-faint)}
.ba-table td:nth-child(3){color:var(--text-body)}
.ba-table td:first-child{font-weight:600;min-width:180px}
/* TABLET + MOBILE: the same six comparisons, as stacked cards -------------
   The 3-column grid needs ~640px; the case column is 632px at desktop and
   294px on a phone. Scrolling it sideways (what it used to do) hid the
   "After" column entirely — a before/after table where you can only see the
   before is not a comparison, it is half an argument (Arpit, 2026-08-17).
   Below 860px each ROW becomes the unit: the question, then Before, then
   After, each labelled in place.
   The markup stays a real <table>. Chrome's AX tree keeps table/row/cell
   through the display:block flip (measured, both widths) but Safari has
   historically dropped them — and Safari is exactly the browser this
   breakpoint is for — so the markup also carries explicit ARIA roles. */
@media (max-width:860px){:is(.ba-wrap,.td-scroll){overflow-x:visible;margin:20px 0 8px}
/* min-width is the whole defect in one declaration: .ba-table demanded 640px
     and .td-table 520px, inside columns of 294px. Release it here. */
  :is(.ba-table,.td-table){display:block;min-width:0}
/* thead is dropped from view, not from the tree — every cell below now
     carries its own visible label, so the column heads would only repeat. */
  :is(.ba-table,.td-table) thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}
:is(.ba-table,.td-table) tbody{display:block}
:is(.ba-table,.td-table) tbody tr{display:block;background:var(--surface-card);border:1px solid var(--border-strong);border-radius:12px;padding:20px;margin:0 0 16px}
:is(.ba-table,.td-table) tbody tr:last-child{margin-bottom:0}
:is(.ba-table,.td-table) td{display:block;padding:0;border-bottom:0}
/* the question heads the card */
  :is(.ba-table,.td-table) td:first-child{min-width:0;font-size:15px;line-height:1.45;color:var(--text-body);padding-bottom:12px;margin-bottom:12px;border-bottom:1px solid var(--border-strong)}
:is(.ba-table,.td-table) td[data-label]{padding-left:12px;border-left:2px solid var(--border-strong)}
:is(.ba-table,.td-table) td[data-label]:nth-child(3){border-left-color:var(--accent);margin-top:12px}
:is(.ba-table,.td-table) td[data-label]::before{content:attr(data-label);display:block;margin-bottom:3px;font-family:var(--ff-label);font-size:11.5px;font-weight:600;letter-spacing:.02em}
:is(.ba-table,.td-table) td[data-label]:nth-child(2)::before{color:var(--text-muted)}
:is(.ba-table,.td-table) td[data-label]:nth-child(3)::before{color:var(--acc-copper)}}
/* ================================================================
   /lab/ — ONE READING AXIS (2026-08-14)
   The balance pass centred each capped element as a block; different widths
   (781/613/453) meant eyebrow, body and title each started at a different x —
   three axes measured at 330 / 424 / 494. Balanced is not aligned: the column
   is capped ONCE and every text element sits flush to its left edge.
   ================================================================ */
.lab-wrap{max-width:781px;margin-left:auto;margin-right:auto}
.lab-wrap :is(p,h1,h2,h3,dl,ul,ol,.lab-note,.lab-body){margin-left:0;margin-right:0;max-width:none}
/* the artifact cards earn more width than prose: break out of the spine, centred */
.lab-wrap .lab-cards{width:min(1100px,calc(100vw - 48px));max-width:none;margin-left:50%;margin-right:0;transform:translateX(-50%)}
@media (max-width:1160px){.lab-wrap .lab-cards{width:100%;margin-left:0;transform:none}}
/* Section rhythm — measured, not assumed. The first attempt ADDED 96px on top
   of the padding lab sections already carried, ballooning ink-to-ink gaps to
   424/302px against the homepage's ~180-250. Sections keep their own padding;
   the oversized boundaries are brought DOWN to the house cadence. */
/* /fit/ is built in the Lab's page grammar, so it takes the Lab's section rhythm too.
   It was on the generic .section padding (133/60) against the Lab's 96/88 — the same
   "new page never joined the scope" trap that shipped lab/plugin.html unstyled. The hero
   is a <header> there (a11y: the page had no banner landmark), so the selector names both
   element types rather than assuming every hero is a <section>. */
:is([class*="p-lab"],.p-fit) main > :is(section,header).section{padding-top:88px;padding-bottom:88px}
:is([class*="p-lab"],.p-fit) main > :is(section,header).section:first-child{padding-top:96px}
/* the hero's closing note carried ~150px of leftover internal space that made
   the first boundary half again larger than the second — equalized here */
:is([class*="p-lab"],.p-fit) main > :is(section,header).section:first-child .lab-note{margin-bottom:0}
:is([class*="p-lab"],.p-fit) .lab-cards{margin-bottom:0}
/* /lab/ foot links join the sitewide CTA grammar (they were 13px lowercase with
   a GOLD hairline under violet text — every colour a legal token, which is
   exactly why the colour gate passed them; the grammar was the defect). */
/* The lab link/button, declared WHOLE. This rule used to change only the bottom border and
   padding-bottom, on top of the bordered pill styles.css sets — a PARTIAL override, which
   left two defects visible on 26 buttons across five pages:
     * padding computed to 8px top / 2px bottom, so the label sat 6px BELOW centre
       (10.5px of space above the glyphs, 4.5px below). Arpit spotted it by eye.
     * three sides gold, the fourth violet, because only border-bottom was recoloured.
   A component must declare its own critical properties rather than inherit half of them
   from the treatment it is replacing. Padding is symmetric and on the 8px grid; the border
   is one colour on all four sides, the violet this rule always intended. */
.lab-links a:not(.cta){font-family:var(--ff-label);font-size:11.5px;font-weight:500;letter-spacing:.02em;color:var(--link-ink);text-decoration:none;border:1px solid color-mix(in srgb, var(--link-ink) 58%, transparent);border-radius:var(--radius);padding:8px 16px}
.lab-links a:not(.cta):hover{color:var(--link-ink-hover);border-color:var(--link-ink);background:transparent}
/* ================================================================
   SIMILARITY PASS (Playwright Gestalt audit, 2026-08-14)
   Four classes rendered at arbitrary different sizes/weights for the SAME
   role. Cause in every case: a relative size (em) or an inherited alpha, so
   the component's look depended on where it was dropped rather than on what
   it is. A component declares its own type.
   ================================================================ */
/* inline code: was 18.9 / 14.4 / 12.6px on one page — 1.05em of whatever
   paragraph it landed in. One token, one size. */
:is(.t-code,.td-inline){line-height:1.5}
/* the handwriting annotation: 22px/600 on home, 21px/400 on hire. One voice.
   In the `emphasis` layer because per-page extracted classes (.xi-*) set these inline-derived
   sizes at page level — the component must out-declare them. */
/* A ROTATED BLOCK MUST SHRINK-WRAP. On /patterns/ this <p> was display:block, so its box
   ran the full 1180px column while the handwriting inside it was 271px. rotate(-1.6deg)
   then swung the empty right-hand end of that box 16px DOWN, straight through the caption
   below — the layout box said 28px tall, the rotated bbox was 60px. Shrink-wrapped, the
   same rotation swings 8px and clears. The homepage instance already had inline-block,
   which is exactly why it never collided. Found by tools/overlap-check.py, 2026-08-17,
   after Arpit spotted it and five other gates could not see it. */
.hand{display:inline-block;max-width:100%}
/* ============================================================================
   TYPE — Stack 1 role corrections (2026-08-14)
   Monospace now means CODE. Labels, eyebrows, CTAs and meta lines take the
   label face: same size, same tracking, but a humanist sans at 600 instead of
   a fixed-width face — the change that makes 34 elements a page scannable.
   Tracking drops from .12-.15em to .08em: uppercase sans needs less letter-
   spacing than uppercase mono to breathe, and more than it needs looks shouted.
   ============================================================================ */
:is(.k,.eyebrow,.lbl-eyebrow,.ck,.mk,.lab-kicker,.opt-n,
  .thought-tag,.case-hero__kicker,.lbl-cap,.lbl-meta,.lbl-badge-gold,
  .go,.lab-go,.rcpt-btn,.contract-links a,.wr-more a,.contact-alt a,.lab-links a):not(.cta){font-family:var(--ff-label);font-weight:600;letter-spacing:.08em}
/* code keeps the mono, and keeps its own tracking */
:is(code,pre,.t-code,.td-inline,.lab-code,.plA-stage,.plF-stage){font-family:var(--ff-mono);letter-spacing:0}
/* CODE BLOCKS WRAP; THEY DO NOT SCROLL (2026-08-17, Arpit's pick) ----------
   pre.lab-code was overflow-x:auto with white-space:pre, so the longest line
   ran off the right edge at EVERY width — at 1440 the payoff line read
   "…safe to act, with an" and simply stopped; at 390, 439px was hidden.
   The Lab is the page that answers "is he actually technical", and its code
   was cut off mid-sentence on every screen anyone would read it on.
   Declared ONCE on the component, not per page: the four lab pages carry four
   different body classes (p-lab, p-lab-loop, p-lab-teardown, p-lab-plugin) and
   only two of them styled `code` at all, which is how they drifted. */
pre.lab-code{overflow-x:visible}
pre.lab-code code{white-space:pre-wrap;overflow-wrap:break-word;word-break:normal}
/* THE FINTECH MOCKUP SCALES; IT DOES NOT SLICE (2026-08-17, Arpit's pick) --
   .plF is a picture of a product, so on a phone it shrinks whole rather than
   losing its right-hand edge. It was 358px of interface inside a 292px box —
   the evidence quote, the source citations and the score bars all lost their
   ends behind an inner scroll.
   358 is a flexbox min-content floor (.plF-main is min-width:auto and .plF-src
   is nowrap), so it cannot be squeezed; it has to be scaled. The factor is
   fluid, not stepped: the parent becomes a query container, and zoom divides
   its width by the mockup's design width. min(1, …) means this can only ever
   shrink — above ~480px the mockup is already at its natural size and the
   rule stops applying itself. Verified: calc() length division resolves here
   (0.768421 at 390px, painting 292px exactly). */
@media (max-width:480px){body.p-case-studies-fintech .plF-hold{container-type:inline-size}
/* This sits in the `emphasis` layer, and not by habit: the case-study breakout rules above
     set `width:100%` on every plate inside .measure-c from a winning layer, so a plain
     declaration loses and the mockup lays out at 342px — narrower than its
     358px min-content, which is the slicing all over again, just smaller. */
  body.p-case-studies-fintech .measure-c .plF-hold .plF{zoom:min(1, calc(100cqw / 380px));overflow:hidden}}
/* Label roles move to the sans; the RECEIPT FAMILY keeps monospace on purpose.
   .rcpt-l / .rcell spans / .rfoot / .fr / .stamp / the boarding pass are a
   printed-docket metaphor — fixed-width IS the point there, the way a till
   receipt or a boarding pass is set. Flattening those would cost meaning to
   satisfy a rule, the same mistake as flattening the semantic hues.
   emphasis layer: these classes carry per-page extracted rules that outrank a
   plain component selector. */
body.p-home :is(.k,.go,.ck,.mk,.ek,.lk,.ak,.meta,
  .rcpt-btn,.rcpt-more,.ccd-q,.ccd-idle,.ccd-note,.thought-tag,.lede,.errata-l){font-weight:600;letter-spacing:.08em}
/* body-sized label text should not be semibold — only the uppercase micro-labels are */
body.p-home :is(.meta,.ccd-q,.ccd-idle,.ccd-note,.lede){font-weight:400;letter-spacing:0}
/* the remaining label classes on inner pages — same treatment, same exemptions */
:is(.cg-l,.lbl-pill-gold,.lbl-eyebrow-500,
  .hire-role,.hire-print-note,.lab-num,.ev-tiers dt,figcaption .lbl-eyebrow){font-weight:600;letter-spacing:.08em}
/* case-study prose at 82 characters: pull the spine in to the reading band */
body[class*="p-case-studies"] .measure-c{max-width:680px}
/* ============================================================================
   PAPER GROUNDS KEEP A PAPER GOLD — regression fixed 2026-08-14
   The ember gold tokens (--goldA #FFC46B / --goldA-dk #C98F3F) are correct on
   the dark ground and WRONG on the light plate mockups: #C98F3F measures
   2.52:1 on the cream #FCF2DC used inside the reconstructions — 22 contrast
   failures across five case studies, all introduced by my own tokenisation
   earlier today. A token that changes with the theme must also change with the
   GROUND it lands on. Inside any paper artifact the gold reverts to the dark
   values that were legal there all along:
     --goldA-dk #7A5410 → 6.08:1 on cream, 6.77:1 on white
     --goldA    #7E5A14 → 5.62:1 on cream, 6.25:1 on white
   ============================================================================ */
:is(.plA,.plF,.plM,.plO,.plP,.plV,.fig-paper,.recon,
  .pass,.plA-app,.plF-app,.plM-app,.plO-app,.plP-app,.plV-app,[class*="-paper"]){--accent-text:#7E5A14;--accent-fill:#7A5410;--accent-text:#7E5A14;--accent-fill:#7A5410}
/* Phone safety: a long unbreakable token (a URL, a code identifier) pushed
   patterns/ml-explainability 4px past the edge with no single offending box —
   the classic signature of a word that cannot wrap. */
@media (max-width:640px){main :is(p,li,dd,dt,h1,h2,h3,figcaption){overflow-wrap:break-word}}
/* A wide comparison table on patterns/ml-explainability pushes 4px past the
   edge at 390. `display:block` on <table> was tried and made it WORSE (broke
   two other pages' tables), so the table keeps its display and the cells wrap
   instead — measured, not assumed.
   word-break:break-word REMOVED 2026-09-12. It breaks at any character to
   minimise width, so words that FITTED were split anyway: a phone walk of the
   site found 24 of them across six pages — "Act|ion", "Revi|ew", "Ign|ore",
   "Confid|ence", "Underst|andabil|ity" — and word-break inherits, so the split
   reached <strong> and <i> inside the cells too. overflow-wrap:break-word is
   the property that was doing the real work: it breaks a word only when the
   word cannot fit its column at all, which is the case this rule was written
   for. The 4px it was added beside is unaffected — the ceiling comes from
   table-layout:fixed, and the note at the foot of this file records that
   word-break made no difference to it when it was tried. */
@media (max-width:640px){main table{table-layout:fixed;width:100%}
main :is(td,th){overflow-wrap:break-word}}
/* ============================================================================
   /patterns/ FEATURE CARDS — my call, per Arpit "you decide".
   The two lead cards are 1180px wide while their content used ~430px, leaving
   683px of void on the right. I am NOT narrowing them: they are the page's
   two feature objects (the rule, and the rule as running code) and their width
   is what marks them as bigger than the eight pattern cards below.
   Instead the space gets a content role — the card becomes two columns: the
   argument on the left at a reading measure, its provenance and CTA on the
   right rail. Same principle as the case-study plates: fill designed space
   with content, do not shrink the object to hide the gap.
   ============================================================================ */
@media (min-width:900px){/* emphasis layer: the extracted class also sets display:block */
  body[class*="p-patterns"] .section-inner > a:has(> p){grid-template-columns:minmax(0,1fr) 300px;column-gap:64px;align-items:start}
body[class*="p-patterns"] .section-inner > a:has(> p)
    > :is(.eyebrow,.section-title,.t-ui-muted-175,p){grid-column:1}
/* the CTA + date/provenance row becomes the right rail, top-aligned */
  /* grid-row 1/-1 spans EVERY row so the rail sits beside the whole text stack.
     `2 / span 3` put it below the prose (measured railTop 592px inside the card)
     because the two cards do not have the same number of children. */
  body[class*="p-patterns"] .section-inner > a:has(> p)
    /* `1 / -1` spans only the EXPLICIT grid, which is one row here (all rows are
       implicit), so the rail was 251px tall in a 511px card. span 20 covers any
       child count these two cards will ever have. */
    > :last-child{grid-column:2;grid-row:1 / span 20;align-self:stretch;border-left:1px solid var(--border-strong);padding-left:24px;display:flex;flex-direction:column;gap:8px;align-items:flex-start}
body[class*="p-patterns"] .section-inner > a:has(> p)
    > :is(.section-title,.t-ui-muted-175){max-width:none}}
/* /patterns/ prose blocks (not cards): the text was capped at ~430px inside a
   1112px band, so the leftover sat entirely on the right. Cap the BLOCK to a
   reading measure and centre the block — the leftover becomes a symmetric
   margin. Same reading-spine pattern the case studies use. */
@media (min-width:900px){body[class*="p-patterns"] .section-inner > div:not(.philosophy-cards):not([class*="grid"]){max-width:760px;margin-left:auto;margin-right:auto}
body[class*="p-patterns"] .section-inner > div:not(.philosophy-cards) > :is(p,h2,h3){max-width:none}}
/* ============================================================================
   TAP TARGETS — WCAG 2.5.8 (AA) requires 24x24 CSS px for a pointer target.
   The case-study jump nav measured 22px tall (padding 0 0 2px) on six pages:
   a standalone nav row, on a phone, two pixels short. Inline links inside a
   sentence are exempt from 2.5.8 and are deliberately NOT touched here.
   ============================================================================ */
.case-jump a{padding:8px 0;min-height:24px;display:inline-flex;align-items:center}
@media (max-width:640px){/* phones get a comfortable target, not merely a legal one */
  .case-jump{gap:4px 20px}
/* 12px (grid) + the 20px line box = 44px, the comfortable phone target */
  .case-jump a{padding:12px 0;min-height:44px}}
body[class*="p-case-studies"] :is(.case-jump a,.ba-table th){font-size:12px;font-weight:600}
/* The jump nav is NAVIGATION, not a reading line — but it sits inside .measure-c,
   so the 68ch prose cap added on 2026-09-06 (a 680px box, 632px of content) became
   its width too. That is too narrow for a 7- or 8-entry table of contents: five of
   the eight case studies wrapped with a single orphaned link alone on a second
   row, and two of them (adtech at 8 entries, planit needing 634px against 632)
   already did before 2026-09-07 added the sections the nav had been missing.
   It goes on the axis THIS PAGE ALREADY HAS rather than a new one. Every plate,
   .case-vitals and .recon on a case page is width:min(1040px, 100vw - 48px),
   auto-centred — left edge 200px at 1440. My first attempt invented 940px, which
   put the nav 50px inside the plates and 154px outside the prose: aligned to
   nothing, centred in leftover space, which is the exact defect the layout rule
   here names. Applied at EVERY width, exactly like `.measure-c figure` — the
   plates sit at L24 from 390 to 1024 and at L200 at 1440, so following them adds
   no new condition, and gating this at 1100px left the orphan standing at 1024 on
   five pages (two of which had it before today). At 390 the two axes converge. */
body[class*="p-case-studies"] .measure-c > .case-jump{width:min(1040px, calc(100vw - 48px));/* the house breakout, verbatim from the plates rule below: auto margins do
       NOT centre a block wider than its containing block — they resolve to 0 and
       the nav ran 4px past the viewport. */margin-left:50%;margin-right:0;transform:translateX(-50%);/* 16px, not 20px: eight entries need more run than a 1100px window gives at
       20px. Each link carries its own underline, so the gap is not what separates
       them. (14px measured better still and is what I reached for first — but the
       spacing scale is 4·8·12·16·20·24·32·40·48·64·80, and inline-style-check is
       right that a value off it needs a reason, not a preference.) */column-gap:16px}
/* Between 768 and 1099 the long navs are ONE ROW PLUS A TAIL, which is the actual
   defect — adtech's eight entries need 842px of run against 720, and ptc's seven
   need 748, so both orphaned a single link on a row of its own. :has() counts the
   children, so from seven entries up the nav becomes four aligned columns (4+4,
   4+3) — a deliberate two-row contents list instead of a wrap that ran out of
   room. It is applied by COUNT, not by which pages happen to overflow today:
   o2 and adtech-anonymous fit on one row at 768 by 10px and 65px, and a rule that
   exempted them would make the next added entry a silent orphan. Six-entry navs
   keep their single row. Below 560 every nav is already a multi-row list and a
   ragged last row is what a list looks like — not an orphan. */
@media (min-width:560px) and (max-width:1099px){body[class*="p-case-studies"] .case-jump:has(> a:nth-child(7)){display:grid;grid-template-columns:repeat(4,minmax(0,1fr));row-gap:4px}}
body[class*="p-case-studies"] :is(.fig-paper figcaption,
  figure figcaption > span:last-child){font-size:12px;font-weight:400;text-transform:none}
/* ============================================================================
   F3 · "THE ARGUMENT" COMPONENTS (2026-08-14, Arpit's pick)
   Every case study opens on a thesis plate — the one stealable principle the
   case exists to prove — and keeps the strongest objection in a counter block.
   Six cases, six different principles: the portfolio as a system of ideas.
   ============================================================================ */
.thesis{border:1px solid var(--accent);border-radius:12px;padding:40px;margin:40px 0;background:linear-gradient(160deg,var(--act-wash),var(--ink-wash));text-align:center}
.thesis .t-l{font-family:var(--ff-label);font-weight:600;font-size:11.5px;letter-spacing:.02em;color:var(--acc-amber);display:block;margin-bottom:16px}
.thesis p{font-family:var(--ff-display);font-weight:300;font-size:clamp(21px,2.4vw,28px);line-height:1.25;letter-spacing:-.01em;color:var(--text-body);max-width:30ch;margin:0 auto}
.thesis p em{font-style:italic;color:var(--acc-violet)}
.counter{border-left:3px solid var(--acc-rose);padding:20px 24px;margin:32px 0;background:color-mix(in srgb, var(--acc-rose) 6%, transparent);border-radius:0 8px 8px 0}
.counter .c-l{font-family:var(--ff-label);font-weight:600;font-size:11px;letter-spacing:.02em;color:var(--acc-rose);display:block;margin-bottom:8px}
.loopfig{margin:32px 0;border:1px solid var(--border-hairline);border-radius:12px;padding:32px;background:var(--surface-page);overflow-x:auto}
.loopfig figcaption{font-family:var(--ff-sans);font-size:12px;color:var(--text-faint);margin-top:16px;line-height:1.6}
/* ============================================================================
   RECEIPT CHIP — show the TRANSITION, not just the endpoint (2026-08-14)
   "3 hrs" alone means nothing; the whole claim is the distance travelled.
   Arpit's pick (2026-08-15, option B of four rendered): ONE voice, one line —
   the pair at a single size with the ember arrow as the only color, so it
   reads as a single fact. The chip's b is clamped smaller than its siblings
   because the journey is longer than a lone number; nowrap keeps it one line.
   ============================================================================ */
body.p-home #chip-adtech b{letter-spacing:-.01em;white-space:nowrap}
/* the visible pair lives in a span INSIDE b; .rcell span (11.5px mono uppercase,
   the descriptor rule) was capturing it — the bug Arpit rejected. Redeclare. */
body.p-home .rcell b>span{display:inline;font-family:inherit;font-size:inherit;font-weight:inherit;letter-spacing:inherit;text-transform:none;color:inherit;margin:0}
body.p-home .rcell b .was{font-style:normal}
body.p-home .rcell b .to{font-style:normal;color:var(--acc-copper);margin:0 .3em;font-size:.85em}
/* ============================================================================
   TESTIMONIALS — four VANTAGE POINTS, not four compliments (2026-08-14)
   Canon lists five confirmed testimonials and places four on the homepage; the
   homepage rebuild had silently dropped two of them. Restored — and the layout
   now carries the argument canon already makes about Ananda ("the only
   ENGINEERING voice; answers the 'can a designer ship?' doubt the design voices
   cannot"). Each card is labelled by the writer's RELATIONSHIP, because four
   angles on the same person is triangulation; four compliments is noise.
   ============================================================================ */
body.p-home .qt{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:12px;border-top:3px solid var(--act,var(--acc-copper));padding:24px 24px 20px;display:flex;flex-direction:column;height:100%}
body.p-home .qt blockquote{flex:1 1 auto;margin:0}
body.p-home .qt figcaption{margin-top:20px;padding-top:16px;border-top:1px solid var(--border-strong)}
/* the trust loop as wrapping HTML chips — the SVG version forced a 640px
   min-width, which is a horizontal scrollbar on every phone. Chips wrap. */
.loop-steps{display:flex;flex-wrap:wrap;align-items:stretch;gap:12px}
.lstep{flex:1 1 140px;min-width:140px;background:color-mix(in srgb, var(--surface-card) 80%, transparent);border:1px solid var(--border-hairline);border-radius:8px;padding:12px 16px}
.lstep b{display:block;font-family:var(--ff-sans);font-weight:600;font-size:13px;color:var(--text-body);margin-bottom:4px}
.lstep span{font-size:11.5px;color:var(--text-faint);line-height:1.5}
.lstep-hot{border-color:var(--acc-violet)}
.larr{align-self:center;color:var(--text-disabled);font-size:16px}
.lback{flex-basis:100%;font-size:11.5px;color:var(--acc-violet);border-top:1px dashed color-mix(in srgb, var(--acc-violet) 60%, transparent);padding-top:12px;margin-top:4px}
/* the arrows only mean something on ONE line: from 640-849 the row wrapped 3+1
   with a dangling third arrow (2026-09-02 sweep) — below the single-line width
   the tiles carry the sequence on their own */
@media (max-width:849px){.larr{display:none}}
/* #voices joins the homepage section cadence (it was born with zero padding —
   exactly the boundary-collision defect the overflow gate checks for).
   2026-08-15: it was ALSO born outside the section type grammar — h2 at browser
   size, kicker with no accent, lede undimmed. Declared here to match siblings. */
/* Second-half act rhythm (2026-08-15): lead and voices sat on the SAME soft
   band, then lab and thoughts both sat on base — alternation died after the
   fold. Voices returns to base; #lab takes the band, restoring band/base/band. */
body.p-home .voices{padding:96px 0;background:none}
body.p-home .voices h2{font-size:clamp(28px,3.2vw,44px);margin:12px 0 16px}
body.p-home .voices .lede{color:var(--text-muted);margin-bottom:40px}
/* product-page link cards (replacing the two business-video embeds) */
.prod-links{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(280px,100%),1fr));gap:16px;width:min(1040px,calc(100vw - 48px));margin:24px 0 24px 50%;transform:translateX(-50%)}
@media (max-width:1100px){.prod-links{width:100%;margin-left:0;transform:none}}
.prod-links a{display:block;background:var(--surface-card);border:1px solid var(--border-strong);border-radius:12px;padding:20px 24px;text-decoration:none;color:var(--text-body)}
.prod-links a:hover{border-color:var(--accent)}
.prod-links b{display:block;font-family:var(--ff-label);font-weight:600;font-size:12px;letter-spacing:.02em;color:var(--link-ink);margin-bottom:8px}
.prod-links span{font-size:13.5px;line-height:1.6;color:var(--text-muted)}
/* ============================================================================
   FRAMED ROWS — the tint must reach the frame's edges (2026-08-14)
   The frame owned the horizontal padding (8px 24px) while the rows had none,
   so every tinted row stopped 27px short on the left and 25px on the right —
   a band floating inside its own container instead of striping it. And 8px of
   vertical frame padding left the first row's text almost touching the border.
   Ownership flips: the FRAME holds no inset, each ROW holds its own 24px, and
   the frame clips so the tint can't square off its rounded corners.
   Used on 7 pages, so this fixes the component everywhere at once.
   ============================================================================ */
:is(.framed-tight,.framed,.rcpt-box){overflow:hidden}
/* ============================================================================
   MENU BUTTON — a mark, not three bars (2026-08-14)
   The bars now sit in a bordered tap target that meets 44px, carry the ember
   gradient, and cross into an X on open. Motion is transform-only (compositor)
   and respects prefers-reduced-motion.
   ============================================================================ */
.menu-toggle{width:44px;height:44px;align-items:center;justify-content:center;gap:0;border:1px solid var(--border-strong);border-radius:10px;background:var(--surface-card);padding:0;margin:0;position:relative;transition:border-color .2s,background .2s}
.menu-toggle:hover{border-color:var(--accent)}
.menu-toggle span{position:absolute;left:13px;width:18px;height:2px;border-radius:2px;background:var(--cta-grad);transition:transform .28s cubic-bezier(.2,.9,.3,1),opacity .18s}
.menu-toggle span:nth-child(1){transform:translateY(-6px)}
.menu-toggle span:nth-child(3){transform:translateY(6px)}
.menu-toggle[aria-expanded="true"] span:nth-child(1){transform:rotate(45deg)}
.menu-toggle[aria-expanded="true"] span:nth-child(2){opacity:0}
.menu-toggle[aria-expanded="true"] span:nth-child(3){transform:rotate(-45deg)}
@media (prefers-reduced-motion:reduce){.menu-toggle span{transition:none}}
/* ============================================================================
   PATTERNS HUB — the two feature cards held a 431px paragraph against an
   844px void (balance gate RED, 683px one-sided). Recomposed: the meta/CTA
   block becomes a right rail with a role; the prose gets a real measure.
   ============================================================================ */
body[class*="p-patterns"] :is(.xi-patterns-012,.xi-patterns-018){display:grid;grid-template-columns:minmax(0,66ch) 300px;justify-content:space-between;column-gap:48px;align-items:start;grid-template-areas:"img img" "eye eye" "ttl ttl" "body meta"}
body[class*="p-patterns"] :is(.xi-patterns-012,.xi-patterns-018) .framed-blk{grid-area:img}
body[class*="p-patterns"] :is(.xi-patterns-012,.xi-patterns-018) .eyebrow{grid-area:eye}
body[class*="p-patterns"] :is(.xi-patterns-012,.xi-patterns-018) :is(.section-title,.card-title){grid-area:ttl}
body[class*="p-patterns"] .xi-patterns-016{grid-area:body}
body[class*="p-patterns"] .xi-patterns-017{grid-area:meta;align-self:center;display:flex;flex-direction:column;gap:8px;border-left:1px solid var(--border-strong);padding-left:24px}
@media (max-width:900px){body[class*="p-patterns"] :is(.xi-patterns-012,.xi-patterns-018){grid-template-columns:1fr}
body[class*="p-patterns"] :is(.xi-patterns-016,.xi-patterns-017){grid-column:1}
body[class*="p-patterns"] .xi-patterns-017{border-left:none;padding-left:0}}
/* patterns colophon — prior-art prose left, citation rail right (was three
   lonely 431px paragraphs against an 846px void; balance gate RED) */
body[class*="p-patterns"] .xi-patterns-022{display:grid;grid-template-columns:minmax(0,1fr) 380px;column-gap:48px;align-items:start}
body[class*="p-patterns"] .xi-patterns-023{grid-column:1;grid-row:1/span 3}
/* the citation rail owns its column: hairline + vertical centering against the prose,
   the same meta-rail grammar the rule band uses (was three short blocks over a void) */
body[class*="p-patterns"] .pat-cite{grid-column:2;grid-row:1/span 3;align-self:stretch;display:flex;flex-direction:column;justify-content:center;gap:16px;border-left:1px solid var(--border-strong);padding-left:24px}
@media (max-width:900px){body[class*="p-patterns"] .pat-cite{grid-column:1;grid-row:auto;border-left:none;padding-left:0;margin-top:8px}}
@media (max-width:900px){body[class*="p-patterns"] .xi-patterns-022{grid-template-columns:1fr}}
/* ARTIFACT TOKENS — REMOVED 2026-08-15. The recolouring they drove shipped
   invisible text: the map was incomplete, so any colour it did not know kept
   its original lightness while its text was remapped. Two failure shapes
   (cream-on-cream, dark-on-dark) reached production. Artifacts now render in
   their designed palette; only the brand fonts and per-artifact style scoping
   are applied. See tools/artifact-ember.py. */

/* ============================================================================
   SECOND-HALF SECTION GRAMMARS (2026-08-15, Arpit approved all four from the
   rendered prototype): after How-I-Lead the page ran four card grids in a row.
   Each section now carries its own layout DNA —
   memos → ledger rows · voices → anchor quote + chorus · lab → terminal
   listing · writing → editorial index. Prototype: prototypes/secondhalf.css.
   ============================================================================ */
/* PROTOTYPE — second-half section grammars, 2026-08-15. Each section gets its own layout DNA. */

/* 1 · HOW I LEAD — memo cards become a ledger: label rail | content, hairline rows */
body.p-home .lead .wrap{max-width:1000px}
body.p-home .memos{border-top:1px solid var(--border-hairline)}
body.p-home .memo{grid-template-columns:200px minmax(0,1fr);column-gap:48px}
body.p-home .memo h3{grid-column:2}
body.p-home .memo p:not(.mk){grid-column:2;max-width:none}
body.p-home .memo .mk{grid-column:1;grid-row:1/span 2}
/* the single-anchor .qt:first-child grammar retired 2026-09-02 — it was matching
   the first child of BOTH the new anchors band and the chorus, placing the CTO
   quote diagonally. The anchors band carries its own grammar below. */
body.p-home .qt:not(:first-child) blockquote{font-size:13.5px;line-height:1.6}
/* The card is a full-width row because its TITLE is — 966px of serif at 1440 — but
   the excerpt under it is capped at 75ch for reading, which left 638px of the band
   (55% of the row) empty on the right, 422px at 1024. Whitespace has to be
   designed: the tag is the only truthful element the card owns, so it moves from
   beside the title to the END of the excerpt's row, bottom-aligned with its last
   line. The band is now bracketed by content on both sides instead of trailing
   off. NOTE, Arpit: this MOVES your tag from top-right to bottom-right — one line
   to put back if you want it where it was.
   align-items is `start`, not `baseline`: baseline snaps to a box's FIRST line, so
   a two-line title (card 2 at 768 and every card at 390) stranded the tag against
   the wrong line. Matching baselines here was never the typographic intent. */
body.p-home .thought-card{grid-template-columns:minmax(0,1fr) auto;column-gap:32px;align-items:start}
/* phone: one column means one column — the children's explicit grid-column:2
   placements must be reset too, or grid auto-creates an implicit second track
   (measured: "89px 220px" where 1fr was expected) */
@media(max-width:860px){body.p-home .memo{grid-template-columns:1fr;row-gap:4px}
body.p-home .thought-card{grid-template-columns:1fr}}
/* KNOWN, MEASURED, UNFIXED (2026-08-15): patterns/ml-explainability.html
   scrolls 5px horizontally at 390px. Bisected to <abbr>LIME/SHAP</abbr> in the
   checklist — hiding it or shrinking it fixes the 5px, but NO wrapping rule
   does, including *{overflow-wrap:anywhere}
, word-break, and text-wrap. So it
   is not a wrap problem and I did not ship a rule pretending otherwise.
   Impact: 5px of horizontal scroll on one page, one breakpoint. */

/* Inlined artifacts fill their figure — was a repeated inline style on 41 SVGs
   until the pre-push inline-style gate caught it (2026-08-15). Named, not stamped. */
.art-svg{width:100%;height:auto;display:block}
/* ============================================================================
   404 — MISSED IN THE PORT (found 2026-08-15 by Arpit). The page carried
   data-theme="ember" and loaded ember.css, so it LOOKED ported; in fact
   styles.css held 40 rules for it and ember.css held one. It rendered in the
   classic palette on a site that had moved on. Attribute ≠ theme.
   ============================================================================ */
body.p-404{background:var(--surface-page);color:var(--text-body)}
/* the page was built as a standalone card with no nav; now that it carries the
   house nav and footer it needs the same top offset every other page has */
body.p-404 .wrap{padding-top:120px}
body.p-404 footer{margin-top:64px}
body.p-404 .ghost{color:var(--ink-wash);font-family:var(--serif)}
body.p-404 .kick{font-family:var(--ff-label);font-weight:600;font-size:12px;letter-spacing:.02em;color:var(--acc-copper)}
body.p-404 h1{font-family:var(--serif);font-weight:300;font-size:clamp(32px,4.4vw,56px);color:var(--text-body);margin:12px 0 16px}
body.p-404 h1 em{font-style:italic;background:linear-gradient(92deg,var(--acc-copper),var(--acc-violet));-webkit-background-clip:text;background-clip:text;color:transparent}
body.p-404 .lede{color:var(--text-muted);max-width:60ch;line-height:1.7}
body.p-404 .btn{background:var(--cta-grad);color:var(--btn-fill-ink);border:none;border-radius:999px;padding:12px 20px;font-family:var(--ff-label);font-weight:600;font-size:12px;letter-spacing:.02em;text-decoration:none}
body.p-404 .btn:hover{filter:brightness(1.06);transform:translateY(-1px)}
body.p-404 .inline-links{color:var(--text-faint);font-size:13.5px}
body.p-404 .inline-links a{color:var(--link-ink);border-bottom:1px solid var(--accent)}
body.p-404 .hand{font-family:'Caveat',cursive;font-size:20px;color:var(--acc-amber)}
body.p-404 .meta-note{color:var(--text-faint);font-size:13.5px;line-height:1.7}
body.p-404 .meta-note a{color:var(--link-ink)}
/* the claim ticket stays PAPER on purpose — it is a printed artifact in a dark room,
   the same grammar the case studies use for document exhibits */
body.p-404 .lug{background:#F5EDE6;color:#241830;border-radius:10px;box-shadow:0 24px 60px rgba(0,0,0,.45)}
body.p-404 .lug-head b,
body.p-404 .lug-row b{color:#241830}
body.p-404 .lug-row span,
body.p-404 .lug-head span{color:rgba(36,24,48,.72)}
body.p-404 .lug-fill{background:var(--acc-copper)}
body.p-404 .divert{color:#B84A1F;border-color:rgba(184,74,31,.5)}
body.p-404 .lug-claim{color:rgba(36,24,48,.75)}
body.p-404 .lug-claim .rt{color:#B84A1F}
body.p-404 footer{color:var(--text-disabled);border-top:1px solid var(--border-strong)}
/* ── PlanIt: the mascot row ──────────────────────────────────────────────
   The character is the case's argument, so it gets a component, not inline
   styles. Two things it must declare for itself: its WIDTH (the page-level
   `.fig-paper img{width:100%}
` would otherwise blow a 116px mascot up to the
   full column) and its GROUND (the artwork is dark-featured line work drawn
   for PlanIt's warm light identity — on the #120B14 page the eyes and mouth
   disappear entirely, which is what shipped). Paper ground, as the system
   says for anything that represents a real printed/product surface. */
body.p-case-studies-planit .mascot-row{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px;margin:0}
@media (max-width:640px){body.p-case-studies-planit .mascot-row{grid-template-columns:repeat(2,minmax(0,1fr))}}
/* Same trap as figure.vid-card above: .mascot is a <figure> inside .measure-c,
   so the spine's breakout force-widens it to 1040px and translates it -520.
   The ROW breaks out as one object; the plates inside obey their tracks. */
body.p-case-studies-planit .mascot-row .mascot{min-width:0;display:flex;flex-direction:column;align-items:center;gap:12px;background:#FFF6E9;border:1px solid var(--border-hairline);border-radius:16px;padding:20px 16px 12px}
body.p-case-studies-planit .mascot-row .mascot img{width:116px;height:auto;border:0;display:block}
body.p-case-studies-planit .mascot-row .mascot span{font-family:var(--ff-label);font-size:11px;font-weight:600;letter-spacing:.02em;color:rgba(32,24,12,.62);text-align:center;margin:0}
/* Headings sat almost on top of their first paragraph — the base
   .section-title carries no bottom margin because elsewhere a kicker or grid
   supplies the gap. On this page nothing does. */
body.p-case-studies-planit .section-title{margin-bottom:20px}
body.p-case-studies-planit section > .t-body + .t-body{margin-top:20px}
/* PlanIt product shots. Same breakout discipline as .mascot: the wrappers are
   divs (not <figure>) precisely so the spine's figure-breakout can't claim
   them, and the tracks are minmax(0,1fr) so an image can never force the grid
   wider than its container. */
body.p-case-studies-planit .phone-row{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:24px;justify-items:center;margin:0}
body.p-case-studies-planit .phone-row--one{grid-template-columns:minmax(0,1fr)}
body.p-case-studies-planit .phone-row .shot{display:flex;flex-direction:column;align-items:center;gap:12px;width:100%;max-width:340px}
body.p-case-studies-planit .phone-row .shot img{width:100%;height:auto;display:block;border:1px solid var(--border-hairline);border-radius:12px}
body.p-case-studies-planit .phone-row .shot span{font-family:var(--ff-label);font-size:11px;font-weight:600;letter-spacing:.02em;color:var(--text-faint)}
@media (max-width:640px){body.p-case-studies-planit .phone-row{grid-template-columns:minmax(0,1fr)}}
/* The single-phone figures: a 340px screenshot centred in a 1040px band left a
   ~350px void down each side. The space gets a content role — an annotation
   rail reading the screen — rather than being left over. */
body.p-case-studies-planit .phone-row--one{grid-template-columns:300px minmax(0,1fr);gap:48px;justify-items:start;align-items:start}
body.p-case-studies-planit .phone-row--one .shot{max-width:300px}
body.p-case-studies-planit .shot-rail{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:40px;padding-top:8px}
body.p-case-studies-planit .shot-rail li{font-family:var(--ff-sans);font-size:15px;line-height:1.7;color:var(--text-muted);padding-left:16px;border-left:2px solid rgba(255,138,92,.45)}
body.p-case-studies-planit .shot-rail b{color:var(--text-body);font-weight:600}
@media (max-width:860px){body.p-case-studies-planit .phone-row--one{grid-template-columns:minmax(0,1fr);justify-items:center}
body.p-case-studies-planit .shot-rail{max-width:520px}}
/* ============================================================================
   FIGURE CAPTIONS — the last classic-theme remnant (2026-08-16, Arpit caught it)
   styles.css paints .fig-paper figcaption as a cream band (background:--obj-paper,
   ink:--obj-paper-soft, dashed top rule) — the classic theme's taped-photo look.
   Ember never restyled the BAND, only its font, so every case study carried a
   full-bleed cream strip under its figures: a second, competing surface that
   belongs to no Ember grammar and reads as a highlighter smear on the dark
   page. Captions are captions — house label face, dim ink, page ground.
   ============================================================================ */
body[class*="p-case-studies"] .fig-paper figcaption{background:none;border-top:0;color:var(--text-faint);padding:0;margin:16px 0 0;max-width:70ch;text-align:left;line-height:1.6}
/* The single-phone figure as ONE grid object: the phone holds the left column
   across both rows; the annotation rail sits top-right; the caption drops into
   the space beneath it. Composed this way the figure has no leftover corner —
   previously the caption sat under the phone and the bottom-right ~400px was
   an unstructured void. */
@media (min-width:861px){body.p-case-studies-planit figure.fig-paper:has(.phone-row--one){display:grid;grid-template-columns:300px minmax(0,1fr);grid-template-rows:auto 1fr;column-gap:48px;row-gap:24px;align-items:start}
body.p-case-studies-planit figure.fig-paper:has(.phone-row--one) .phone-row--one{display:contents}
body.p-case-studies-planit figure.fig-paper:has(.phone-row--one) .shot{grid-column:1;grid-row:1 / span 2}
body.p-case-studies-planit figure.fig-paper:has(.phone-row--one) .shot-rail{grid-column:2;grid-row:1;padding-top:8px}
body.p-case-studies-planit figure.fig-paper:has(.phone-row--one) figcaption{grid-column:2;grid-row:2;margin:0;align-self:end}
@media (max-width:860px){body.p-case-studies-planit figure.fig-paper:has(.phone-row--one){display:block}
body.p-case-studies-planit figure.fig-paper:has(.phone-row--one) .phone-row--one{display:grid}}}
/* The bottom button row. Every other case study carries a per-page extracted
   class whose sole declaration is justify-content:space-between; planit was
   authored without one, so its two buttons bunched left at a 16px gap while
   the other six push to the column edges. Declared by name rather than by
   cloning another page's xi- class — those numbers are page-specific. */
/* planit pushed its pair apart with space-between; the row is one object and
   reads as one on every other case. Removed 2026-08-17. */

/* Below 860 the figure stops being a two-column object: the 300px phone track
   was surviving into the narrow layout and squeezing the screenshot to ~120px
   — legible in a geometry check, useless to a human. Caught at 768, which is
   neither declared breakpoint. */
@media (max-width:860px){body.p-case-studies-planit .phone-row--one{grid-template-columns:minmax(0,1fr);justify-items:center;gap:32px}
body.p-case-studies-planit .phone-row--one .shot{max-width:340px}
body.p-case-studies-planit .mascot-row{grid-template-columns:repeat(2,minmax(0,1fr))}
body[class*="p-case-studies"] .fig-paper figcaption{text-align:left}}
/* CORRECTED 2026-08-17, twice — the second time by the instrument that measures PIXELS.
   Three rules here painted this eyebrow the paper gold #7E5A14. I removed all three after a
   DOM probe walked up the tree reading backgroundColor and reported the ground as #120B14 at
   seven widths. It was wrong: contrast-audit, which samples the pixels actually painted under
   the glyph, reads #F4ECDA. The cream does not come from any ancestor's backgroundColor, so a
   style-based walk cannot see it — the exact failure mode noted for gradient and noise overlays.
   Removing the rule put a call to action at 1.33:1. Restored.
   Two of the original three selectors (.pat-card, [class*="-paper"]) stay deleted: they match
   no element on any page carrying body.p-patterns and were dead the day they were written.
   The survivor is keyed on a class that NAMES THE SURFACE rather than on an extracted id, so
   the theme-remnant gate can see it is paper too (its exempt list already matches "paper"). */
/* RETIRED 2026-08-30. The rule above was correct when written: above 861px the pixels under
   this glyph really were cream #F4ECDA, so the label needed the paper gold. That premise has
   since expired — .is-paper on this card is now a 4% gold tint
   (color(srgb 0.494 0.353 0.078 / 0.04)) over the dark page, so the painted ground is #160E14
   at EVERY width. Measured at 390/768/860/861/1024/1280/1440: below 861 the amber #FFC46B
   gives 12.07:1; at and above it the paper gold gave 3.03:1 against a 4.5 floor.
   Deleting the override restores the amber everywhere, re-measured at 12.07:1.
   Why nobody saw it: this label sits below the fold, and until today contrast-audit measured
   only the first screenful — 33 of 231 nodes on the homepage — so the whole lower page was
   reported as "UNKNOWN, not passing" beside a "0 failures" verdict.
   The lesson from 2026-08-17 still stands, with a date on it: a correction is only as good as
   the ground it was measured against, and grounds change. */
body.p-lab #design-system .lab-code{margin-top:20px}
/* ============================================================================
   LAB · DESIGN SYSTEM SPECIMEN (2026-08-17)
   Lives inside the #design-system band, between the three properties and the install
   block: claim -> properties -> SEE IT -> take it. Every value below is painted by this
   same stylesheet and the contrast figures are measured on load, so the specimen cannot
   drift from the system the way a screenshot of a Figma page would.
   ============================================================================ */
/* No max-width of its own: it sits in the Lab's 653px measure and must wrap on the same
   line-length as the paragraphs above it. A second measure in one column reads as a mistake. */
body.p-lab #design-system .dsg-cap{max-width:none;color:var(--text-muted);margin:24px 0 0;font-size:15px;line-height:1.65}
/* In the Lab the default is ONE column: the essay measure is 653px, and auto-fit put two cards
   up and orphaned the third against an empty half-row — leftover space, not designed space. */
body.p-lab #design-system .dsg-grid{display:grid;grid-template-columns:1fr;gap:20px;margin:20px 0 32px}
/* Wide enough to hold three: the specimen steps OUT of the essay column, the way a case-study
   figure steps out of the spine. Symmetric because the column is already centred on the page,
   so no transform is needed and there is nothing to un-do at the next breakpoint down. */
@media (min-width:1024px){body.p-lab #design-system .dsg-grid{--dsg-w:min(1040px,calc(100vw - 128px));width:var(--dsg-w);margin-left:calc((100% - var(--dsg-w))/2);margin-right:calc((100% - var(--dsg-w))/2);grid-template-columns:repeat(3,1fr)}}
/* The grid equalises card heights, so the shorter cards ended with dead space under the last
   row — leftover, not designed. Each card is a column that distributes its own content instead. */
body.p-lab .dsg-card{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:12px;padding:24px;display:flex;flex-direction:column}
body.p-lab .dsg-card > ul{flex:1 1 auto;align-content:space-between}
/* ...except the spacing ramp: it wraps onto two lines but it is ONE continuous scale, so
   distributing its rows pulls 40 away from 48. The ramp stays tight; the note takes the floor. */
body.p-lab .dsg-card > .dsg-steps{flex:0 0 auto;align-content:normal}
body.p-lab .dsg-k{font-family:var(--ff-label);font-size:11px;font-weight:600;letter-spacing:.02em;color:var(--text-faint);margin:0 0 20px}
body.p-lab .dsg-heats{list-style:none;margin:0;padding:0;display:grid;gap:12px}
body.p-lab .dsg-heats li{display:flex;align-items:center;gap:12px}
body.p-lab .dsg-heats i{width:32px;height:32px;border-radius:8px;flex:0 0 auto}
body.p-lab .dsg-heats b{font-size:14px;font-weight:600;color:var(--text-body)}
body.p-lab .dsg-heats em{font-style:normal;font-size:12px;color:var(--text-faint);display:block;margin-top:2px}
body.p-lab .dsg-heats span{margin-left:auto;font-family:var(--ff-mono);font-size:12px;color:var(--status-positive);white-space:nowrap}
body.p-lab .dsg-type{list-style:none;margin:0;padding:0;display:grid;gap:16px}
/* baseline, because this is a TYPE SPECIMEN: the demo word set in the face,
   with the face name annotating it. Centring put an 11px label 5.0px below
   the baseline of the 24px word it describes, and the four rows are four
   different sizes, so nothing lined up down the card. A specimen reads as a
   table only when the labels sit on the same line as the specimens.
   Every row here is single-line, so there is no wrap to strand. */
body.p-lab .dsg-type li{display:flex;align-items:baseline;gap:12px;justify-content:space-between}
body.p-lab .dsg-type b{font-family:var(--ff-label);font-size:11px;font-weight:600;letter-spacing:.06em;color:var(--text-faint);text-align:right;flex:0 0 auto}
body.p-lab .dsg-serif{font-family:var(--ff-display);font-weight:300;font-size:24px;color:var(--text-body)}
body.p-lab .dsg-sans{font-size:16px;color:var(--text-body)}
body.p-lab .dsg-label{font-family:var(--ff-label);font-weight:600;font-size:12px;letter-spacing:.02em;color:var(--acc-amber)}
body.p-lab .dsg-mono{font-family:var(--ff-mono);font-size:14px;color:var(--text-body)}
body.p-lab .dsg-steps{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:12px;align-items:flex-end}
body.p-lab .dsg-steps li{text-align:center}
body.p-lab .dsg-steps i{display:block;height:20px;border-radius:3px;background:var(--cta-grad)}
body.p-lab .dsg-steps span{display:block;margin-top:8px;font-family:var(--ff-mono);font-size:11px;color:var(--text-faint)}
body.p-lab .dsg-note{margin-top:auto;padding-top:20px;font-size:12.5px;color:var(--text-faint);max-width:none}
/* ============================================================================
   /fit/ · THE FIT CHECK (2026-08-17)
   Built in the Lab's page grammar (it joins :where(body.p-lab,body.p-fit) in styles.css
   rather than re-declaring wrap/hero/kicker), so only the components that are genuinely
   new live here. Every one declares its own ink ON ITS OWN GROUND: three of these sit on
   the cream act, where an inherited colour would be invisible.
   ============================================================================ */

/* --- the capability contract, before the input --- */
/* can vs cannot is a COMPARISON — it has to sit side by side to read as one. At 320px the
   pair needed 660 and the Lab measure is 653, so auto-fit silently stacked them. */
body.p-fit .fit-contract{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(272px,100%),1fr));gap:20px;margin:32px 0 0}
body.p-fit .fit-col{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:var(--radius-2);padding:24px}
body.p-fit .fit-col-k{font-family:var(--ff-label);font-size:11px;font-weight:600;letter-spacing:.02em;margin:0 0 16px}
body.p-fit .fit-can .fit-col-k{color:var(--status-positive)}
body.p-fit .fit-cannot .fit-col-k{color:var(--status-negative)}
body.p-fit .fit-col ul{list-style:none;margin:0;padding:0;display:grid;gap:12px}
body.p-fit .fit-col li{position:relative;padding-left:24px;font-size:15px;line-height:1.7;color:var(--text-body)}
body.p-fit .fit-col li::before{position:absolute;left:0;top:0;font-family:var(--ff-mono);font-size:13px}
body.p-fit .fit-can li::before{content:"+";color:var(--status-positive)}
body.p-fit .fit-cannot li::before{content:"\2212";color:var(--status-negative)}
body.p-fit .fit-constraints-k{font-family:var(--ff-label);font-size:11px;font-weight:600;letter-spacing:.02em;color:var(--text-faint);margin:40px 0 0}
/* --- the input --- */
body.p-fit .fit-form{margin-top:32px}
body.p-fit .fit-label{display:block;font-family:var(--ff-label);font-size:11px;font-weight:600;letter-spacing:.02em;color:var(--text-faint);margin-bottom:12px}
body.p-fit .fit-jd{width:100%;box-sizing:border-box;background:var(--surface-card);color:var(--text-body);border:1px solid var(--border-strong);border-radius:12px;padding:16px 20px;font-family:var(--ff-mono);font-size:13.5px;line-height:1.7;resize:vertical;min-height:220px}
body.p-fit .fit-jd::placeholder{color:var(--text-faint)}
body.p-fit .fit-jd:focus{outline:2px solid var(--acc-amber);outline-offset:2px;border-color:transparent}
body.p-fit .fit-actions{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin-top:20px}
/* The empty-submit status, beside the buttons it answers. Full ink, not muted: this is the
   one line telling someone why nothing happened, and a quiet grey is the wrong place to
   save contrast. Empty until the JS writes it, so it takes no space in the normal flow. */
body.p-fit .fit-status{margin-top:12px;font-size:15px;color:var(--text-body)}
body.p-fit .fit-status:empty{margin-top:0}
body.p-fit .btn-primary{font-family:var(--ff-label);font-size:12px;font-weight:600;letter-spacing:.02em;color:var(--btn-fill-ink);background:var(--cta-grad);border:1px solid transparent;border-radius:999px;padding:16px 24px;cursor:pointer}
body.p-fit .btn-ghost{font-family:var(--ff-label);font-size:12px;font-weight:600;letter-spacing:.02em;color:var(--text-muted);background:none;border:1px solid var(--accent);border-radius:999px;padding:16px 24px;cursor:pointer}
body.p-fit .btn-ghost:hover{color:var(--text-body);border-color:var(--acc-amber)}
/* --- the read --- */
body.p-fit .fit-count{font-family:var(--ff-mono);font-size:13px;color:var(--text-faint);margin:12px 0 0}
body.p-fit .fit-group{margin-top:40px}
body.p-fit .fit-group-h{display:flex;align-items:center;gap:12px;margin:0;font-family:var(--ff-display);font-weight:300;font-size:24px;line-height:1.3;color:var(--text-body)}
body.p-fit .fit-group-n{font-family:var(--ff-mono);font-size:12px;font-weight:400;letter-spacing:.04em;padding:4px 12px;border-radius:999px;flex:0 0 auto}
body.p-fit .fit-group-b{max-width:68ch;color:var(--text-muted);font-size:15px;line-height:1.65;margin:12px 0 0}
/* one hue per verdict, each stated on the page ground it actually sits on */
body.p-fit .fit-group--doc   .fit-group-n{color:var(--status-positive);background:rgba(127,207,158,.12)}
body.p-fit .fit-group--thin  .fit-group-n{color:var(--acc-amber);background:rgba(255,199,110,.12)}
body.p-fit .fit-group--none  .fit-group-n{color:var(--text-muted);background:var(--ink-wash)}
body.p-fit .fit-group--block .fit-group-n{color:var(--status-negative);background:rgba(255,159,138,.13)}
body.p-fit .fit-list{list-style:none;margin:20px 0 0;padding:0;display:grid;gap:16px}
body.p-fit .fit-item{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:12px;padding:24px}
body.p-fit .fit-group--block .fit-item{border-color:rgba(255,159,138,.35)}
body.p-fit .fit-item-h{font-size:15px;font-weight:600;color:var(--text-body);margin:0}
body.p-fit .fit-item-c{margin:8px 0 0;font-size:15px;line-height:1.65;color:var(--text-muted)}
body.p-fit .fit-cites,
body.p-fit .fit-terms{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:16px 0 0}
body.p-fit :is(.fit-cites-k,.fit-terms-k,.fit-more){font-family:var(--ff-label);font-size:10px;font-weight:600;letter-spacing:.02em;color:var(--text-faint)}
body.p-fit .fit-cites a{font-family:var(--ff-mono);font-size:12px;color:var(--acc-amber);text-decoration:none;border-bottom:1px solid rgba(255,199,110,.4);padding-bottom:1px}
body.p-fit .fit-cites a:hover{color:var(--text-body);border-bottom-color:var(--text-body)}
body.p-fit .fit-chip{font-family:var(--ff-mono);font-size:11.5px;color:var(--text-muted);background:rgba(255,255,255,.06);border-radius:6px;padding:3px 8px}
body.p-fit .fit-item--chips{display:flex;flex-wrap:wrap;gap:12px;padding:20px}
body.p-fit .fit-item--chips .fit-chip{font-size:12.5px;padding:4px 12px}
body.p-fit .fit-blocker-note{margin:16px 0 0}
body.p-fit .fit-blocker-line{margin:8px 0 0;font-size:14px;line-height:1.6;color:var(--text-muted);max-width:72ch}
body.p-fit .fit-blocker-line b{color:var(--text-body)}
body.p-fit .fit-empty{margin:20px 0 0;max-width:70ch;font-size:15px;line-height:1.7;color:var(--text-muted)}
body.p-fit .fit-empty a{color:var(--acc-amber)}
body.p-fit .fit-close{margin-top:48px;padding-top:32px;border-top:1px solid var(--border-strong)}
body.p-fit .fit-close-p{max-width:70ch;font-size:15px;line-height:1.7;color:var(--text-muted);margin:0}
body.p-fit .fit-close-p b{color:var(--text-body)}
body.p-fit .fit-close .lab-links{margin-top:20px}
[data-cta="see-work"][data-location="hero"]:hover{border-color:var(--acc-copper);color:var(--text-body)}
/* DIAGRAMS GET THE ROOM THEY WERE DRAWN FOR (Arpit: "it feels like squeezed", 2026-08-17).
   Measured, not felt: patterns/reversibility-safe-to-act.html draws at viewBox 1280x400
   and rendered 493px wide — scale 0.385, so a 14px label painted at 5.4px. The inner
   pattern pages ran 0.38-0.41; the case studies, not boxed into the same narrow column,
   ran 0.81-0.88. The figure steps out of the measure column the way the Lab specimen
   does. Symmetric, because the column is already centred (figure spanned 473..966 in a
   1440 viewport). Below 768 it stays in column — there is no room to step into. */
@media (min-width:768px){/* Widen the FIGURE, not the svg. Widening only the svg clipped it to nothing on every
     diagram whose figure carries overflow:hidden (act-review-ignore lost its outer thirds
     to the dark page, text cut mid-word) while diagrams with overflow:visible happened to
     look fine. The container paints the cream and owns the clip, so it has to move first;
     the svg then simply fills it. */
  :is(body[class*="p-patterns"],body.p-process) figure:has(svg.art-svg){width:var(--art-w);max-width:none;margin-left:calc((100% - var(--art-w))/2);margin-right:calc((100% - var(--art-w))/2)}}
/* One row, one arrangement. Seven case studies carried their own extracted class
   (.xi-case-studies-*-0NN{justify-content:space-between}
) which threw the pair
   to opposite ends of a 632px column — 283px apart, so they stopped reading as a pair —
   while planit had no such class and sat them together. Two arrangements for one component
   across eight pages, which is the same complaint as the nine fills. Arpit's call: the
   two sit at the ENDS of the block — the arrangement seven of the eight already had.
   (I first normalised to flex-start, which was my preference substituted for his; the
   majority arrangement was the one to normalise TO.) Primary left, secondary right. */
body[class*="p-case-studies"] .btn-row{justify-content:space-between}
/* The "Design Patterns Demonstrated" cards were still the CLASSIC card: border-radius 4px
   and a gold wash (color-mix(--goldA 3%) on a 10% gold border), set by the
   extracted inline classes. Every other card under Ember is --bg-card on --border at 12px:
   .dsg-card, .fit-item, .lab-card all agree. Four of them, on four case studies, sitting
   next to Ember cards on the same page. Named .case-card in the markup so this is one rule
   about a component rather than four rules about four ids. It sits in `emphasis` because that is what
   it is overriding — not a preference. Found by Arpit, 2026-08-17. */
body[class*="p-case-studies"] .case-card{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:12px;padding:32px}
body.p-writing .xi-writing-020:hover{border-color:var(--accent)}
/* 2026-09-10: T2.6 (the contact submit re-skinned into the Ember language)
   and the .form-slot input radii went with the form itself. */
body[class*="p-case-studies"] blockquote[class*="xi-case-studies-"]{border-left:3px solid var(--act)}
body.p-lab-loop .lab-bin .lab-conf,
body.p-lab-loop .lab-legend i.xi-lab-loop-008{background:var(--acc-violet)}
/* --- T4.22 · a box inside an identical box (51% empty, borders 33px
   apart). Deleting the redundant frame rather than building a grid around
   emptiness — flagged as my call, reversible. --- */
body.p-patterns .xi-patterns-023{border:0;padding:0;margin:0 0 32px}
/* --- T4.23 · writing/resources one-liners. Using .1em (not the plan's
   .06em, which breaks the .15em eyebrow token) — measured below. --- */
body.p-resources .card-p32 > p:last-child{margin-bottom:0}
body.p-writing .card-p32 p,
body.p-resources .card-p32 p{max-width:54ch}
body.p-writing .lead{max-width:46ch}
body.p-writing header.xi-writing-003{border-bottom:0}
/* CTA removed 2026-08-15 (Arpit): the whole row is the link; hover carries the
   affordance (bg tint + border heat already defined on .lane:hover) */
/* Objects that earn the full width break the spine, centred on it.
   THIS BREAKOUT NEEDS BOTH margin-left AND transform TO LAND TOGETHER. The
   extracted per-page classes (.xi-*) carry `margin:…`, which killed
   margin-left while transform still applied — throwing figures 520px off the
   left edge on every case study. Both declarations sit in `emphasis` so the pair
   can never half-apply again. Guarded by tools/overflow-sweep.py. */
body[class*="p-case-studies"] :is(.plA,.plF,.plM,.plO,.plP,.plV,
  .plA-caption,.plF-caption,.plM-caption,.plO-caption,.plP-caption,.plV-caption,
  .case-vitals,.recon,.measure-c figure){width:min(1040px,calc(100vw - 48px));max-width:none;margin-left:50%;margin-right:0;transform:translateX(-50%)}
body[class*="p-case-studies"] .case-hero figure{width:100%;margin-left:0;margin-right:0;transform:none}
/* Below 1100 this used to collapse the breakout to width:100%, which dropped every figure
   into the 680px reading column: 632px of content for a 1280-unit viewBox, a scale of 0.49.
   An 11px annotation then PAINTED AT 5.4px, and that is the whole of the five contrast
   failures on fintech/ptc/vc-diligence — they were only ever failures at <=1024. The
   authored type was never the problem; enlarging it would have distorted the diagrams at
   1440 to fix something that does not happen there. So the width keeps scaling itself
   instead of giving up: min() already guarantees it fits, at every width down to a phone.
   Measured after: no figure escapes the viewport at 1024/900/768/640/390. 2026-08-17. */
@media (max-width:1100px){body[class*="p-case-studies"] :is(.plA,.plF,.plM,.plO,.plP,.plV,
    .plA-caption,.plF-caption,.plM-caption,.plO-caption,.plP-caption,.plV-caption,
    .case-vitals,.recon,.measure-c figure){width:min(1040px,calc(100vw - 48px));margin-left:50%;margin-right:0;transform:translateX(-50%)}}
:is(main,footer) a:not(.lane):not(.labc):not(.hd-preset):not(.rcpt-btn):not(.card-p28):not(.card-p32):not(.nav-cta):not(.cta):not(.fit-cite){color:var(--link-ink)}
/* --- three fixes from review, each measured before and after ---------------- */

/* 1. The pattern links sat in a 386px box inside an 875px parent, so both long
      links wrapped to two lines for no reason. Give them the width that was
      already there. */
/* The cap was a fractional 386.4px — a character-based prose measure inherited
   from the typography layer. These are navigation links, not prose: a reading
   measure has no business sizing them, and it forced two of them onto a second
   line inside an 875px parent. Declared on the component, at a specificity that
   beats the typography rule. */
body.p-home p.contract-links{max-width:none;width:auto}
/* Plates were forced to the full 1040px breakout even when their content is
   narrower — the O2 phone plate used 640px of a 1040px box and left a 399px
   void hard against its right edge. A box wider than its content is leftover
   space, not designed space. Plates now take their content's width and stay
   centred on the reading spine; only genuinely wide artifacts reach 1040. */
/* NOTE the .measure-c in the selector: the breakout rule above uses :is(),
   which takes the specificity of its MOST specific argument (.measure-c figure).
   Without matching that, this rule loses despite sitting in a later layer. */
body[class*="p-case-studies"] .measure-c :is(.plA,.plF,.plM,.plO,.plP,.plV){/* fit-content collapsed them to 328px — the stage tracks are minmax(0,…)
     and gave up all their width. Size to the stage's natural extent instead
     (3 × 250px + gaps ≈ 780) so the box matches its content and the leftover
     space becomes a symmetric margin, not a void on one side. *//* max-content, not fit-content: fit-content collapsed the minmax(0,…)
     tracks to 328px, and a fixed 800px left an identical 159px void on
     every plate (their content caps at ~641). max-content sizes the box
     to what the plate actually draws, then the breakout centres it. */width:max-content;max-width:min(1040px,calc(100vw - 48px))}
@media (max-width:1100px){body[class*="p-case-studies"] .measure-c :is(.plA,.plF,.plM,.plO,.plP,.plV){width:100%}}
/* The plate stages left-aligned their tracks inside the box, so whatever width
   the content did not use piled up on ONE side (measured 159px right, 1px
   left). Centre the tracks: leftover space becomes a symmetric margin around
   the artifact instead of a void hard against its right edge. */
body[class*="p-case-studies"] .measure-c
  :is(.plA,.plF,.plM,.plO,.plP,.plV) > :is([class$="-stage"],[class$="-body"],[class$="-grid"]){justify-content:center}
/* PHONE: plate internals have fixed track widths, so at 390px the fintech and
   vc plates pushed their content past the edge (measured right=413 and 491).
   Give the plate its own horizontal scroll rather than letting it drag the
   page sideways — wide content scrolls inside its own container. */
@media (max-width:700px){body[class*="p-case-studies"] .measure-c
    :is(.plA,.plF,.plM,.plO,.plP,.plV){overflow-x:auto}}
/* ================================================================
   SIMILARITY PASS (Playwright Gestalt audit, 2026-08-14)
   Four classes rendered at arbitrary different sizes/weights for the SAME
   role. Cause in every case: a relative size (em) or an inherited alpha, so
   the component's look depended on where it was dropped rather than on what
   it is. A component declares its own type.
   ================================================================ */
/* inline code: was 18.9 / 14.4 / 12.6px on one page — 1.05em of whatever
   paragraph it landed in. One token, one size. */
:is(.t-code,.td-inline){font-size:13px}
/* the handwriting annotation: 22px/600 on home, 21px/400 on hire. One voice.
   In the `emphasis` layer because per-page extracted classes (.xi-*) set these inline-derived
   sizes at page level — the component must out-declare them. */
/* A ROTATED BLOCK MUST SHRINK-WRAP. On /patterns/ this <p> was display:block, so its box
   ran the full 1180px column while the handwriting inside it was 271px. rotate(-1.6deg)
   then swung the empty right-hand end of that box 16px DOWN, straight through the caption
   below — the layout box said 28px tall, the rotated bbox was 60px. Shrink-wrapped, the
   same rotation swings 8px and clears. The homepage instance already had inline-block,
   which is exactly why it never collided. Found by tools/overlap-check.py, 2026-08-17,
   after Arpit spotted it and five other gates could not see it. */
.hand{font-size:22px;font-weight:600}
/* the sign-off is a DIFFERENT component that happens to share the hand face —
   it declares its own size rather than inheriting a one-off override. */
.sig.hand{font-size:26px;font-weight:600}
/* the pattern-link row: one instance inherited 0.76 alpha ink, the other full */
.contract-links,
p.contract-links{color:var(--text-body)}
/* ================================================================
   GESTALT AUDIT FIXES (Playwright, 2026-08-14) — Arpit's calls
   ================================================================ */
/* CLOSURE — NOT A DEFECT, recorded so it is not "fixed" again. The audit read
   .ccd as clipping 70px (clientHeight 508 vs scrollHeight 578). Measured: the
   last child sits 41px INSIDE the card; the 70px is exactly the decorative
   ::after glow (190px tall at bottom:-70px). A pseudo-element counts toward
   scrollHeight, so a card clipping its own decoration looks identical to a card
   cropping content. overflow:hidden here is doing precisely its job. */

/* PROXIMITY — a heading sat 12px under its eyebrow but 27-40px above its own
   body, so Gestalt read it as belonging to the label above rather than
   introducing the content below. Arpit's call: TIGHTEN below (keep the
   eyebrow-heading pairing, close the gap to the body). In `emphasis` because the
   40px came from a page-level rule that outranks a section-scoped one. */
body.p-home main > section :is(h2,h3){margin-bottom:16px}
body.p-home main > section :is(h2,h3) + *{margin-top:0}
/* /fit/ joins this too: without it every heading sat FLUSH against its body copy (gap 0,
   against the Lab's 16) — the same complaint the planit case drew. Scope, again. */
:is([class*="p-lab"],.p-fit) .lab-wrap :is(h1,h2){margin-bottom:16px}
:is([class*="p-lab"],.p-fit) .lab-wrap :is(h1,h2) + *{margin-top:0}
/* THE FINTECH MOCKUP SCALES; IT DOES NOT SLICE (2026-08-17, Arpit's pick) --
   .plF is a picture of a product, so on a phone it shrinks whole rather than
   losing its right-hand edge. It was 358px of interface inside a 292px box —
   the evidence quote, the source citations and the score bars all lost their
   ends behind an inner scroll.
   358 is a flexbox min-content floor (.plF-main is min-width:auto and .plF-src
   is nowrap), so it cannot be squeezed; it has to be scaled. The factor is
   fluid, not stepped: the parent becomes a query container, and zoom divides
   its width by the mockup's design width. min(1, …) means this can only ever
   shrink — above ~480px the mockup is already at its natural size and the
   rule stops applying itself. Verified: calc() length division resolves here
   (0.768421 at 390px, painting 292px exactly). */
@media (max-width:480px){/* This sits in the `emphasis` layer, and not by habit: the case-study breakout rules above
     set `width:100%` on every plate inside .measure-c from a winning layer, so a plain
     declaration loses and the mockup lays out at 342px — narrower than its
     358px min-content, which is the slicing all over again, just smaller. */
  body.p-case-studies-fintech .measure-c .plF-hold .plF{width:380px;max-width:none;margin:32px auto 8px;transform:none}}
/* Label roles move to the sans; the RECEIPT FAMILY keeps monospace on purpose.
   .rcpt-l / .rcell spans / .rfoot / .fr / .stamp / the boarding pass are a
   printed-docket metaphor — fixed-width IS the point there, the way a till
   receipt or a boarding pass is set. Flattening those would cost meaning to
   satisfy a rule, the same mistake as flattening the semantic hues.
   emphasis layer: these classes carry per-page extracted rules that outrank a
   plain component selector. */
body.p-home :is(.k,.go,.ck,.mk,.ek,.lk,.ak,.meta,
  .rcpt-btn,.rcpt-more,.ccd-q,.ccd-idle,.ccd-note,.thought-tag,.lede,.errata-l){font-family:var(--ff-label)}
/* the remaining label classes on inner pages — same treatment, same exemptions */
:is(.cg-l,.lbl-pill-gold,.lbl-eyebrow-500,
  .hire-role,.hire-print-note,.lab-num,.ev-tiers dt,figcaption .lbl-eyebrow){font-family:var(--ff-label)}
/* One tracking for every CTA. The type change left three components on the old
   .12em (correct for uppercase MONO, too loose for uppercase sans) and /hire/'s
   primary CTA still on the mono face. Caught by tools/cta-grammar-check.py. */
:is(.wr-more a,.contact-alt a,.lab-links a,.contract-links a,
  .go,.rcpt-btn,.rcpt-more,.lbl-badge-gold,.nav-cta):not(.cta){font-family:var(--ff-label);letter-spacing:.08em}
/* OPEN, 5px: patterns/ml-explainability's comparison table runs 5px past 390px.
   Tried and REJECTED, each re-measured: display:block on the table (broke two
   other pages' tables), table-layout:fixed + word-break (no change), reduced
   cell padding (no change). The 5px does not scroll the page in a real browser
   and no text is cut, so it is logged rather than chased further. Next person:
   the cells carry padding from the extraction, so the constraint is
   probably a min-content width on a column, not the padding. */

/* ============================================================================
   ONE AXIS PER SECTION (2026-08-14) — the last habitat of "balanced ≠ aligned"
   #how-i-lead's heading carries a ch-based max-width, so the auto-centring rule
   centred it: eyebrow at x=140, heading at x=395, a 255px indent inside one
   stack. Three other sections had body text drifting 24-27px off their eyebrow
   for the same reason. An eyebrow, its headline and its body are ONE object and
   share one left edge; only whole sections get centred, never their parts.
   ============================================================================ */
body.p-home main > section:not(.hero) .wrap > :is(p,h2,h3),
body.p-home main > section:not(.hero) .wrap > div > :is(p,h2,h3){margin-left:0;margin-right:0}
/* ============================================================================
   /patterns/ FEATURE CARDS — my call, per Arpit "you decide".
   The two lead cards are 1180px wide while their content used ~430px, leaving
   683px of void on the right. I am NOT narrowing them: they are the page's
   two feature objects (the rule, and the rule as running code) and their width
   is what marks them as bigger than the eight pattern cards below.
   Instead the space gets a content role — the card becomes two columns: the
   argument on the left at a reading measure, its provenance and CTA on the
   right rail. Same principle as the case-study plates: fill designed space
   with content, do not shrink the object to hide the gap.
   ============================================================================ */
@media (min-width:900px){/* emphasis layer: the extracted class also sets display:block */
  body[class*="p-patterns"] .section-inner > a:has(> p){display:grid}}
/* ============================================================================
   CASE-STUDY LABEL ROLES — the last monospace holdouts (2026-08-14)
   Found while readying talon.html for the swap, but every case study has them:
   the jump nav (7 links), figure captions, and testimonial attributions were
   still set in monospace at a tracking that belongs to mono, not sans.
   House label grammar is Source Sans 3 / 12px / .08em / 600 — matched exactly
   so a reader cannot tell which page a label came from.
   ============================================================================ */
body[class*="p-case-studies"] :is(
  .case-jump a,
  .fig-paper figcaption,
  figure figcaption > span:last-child,
  .ba-table th){font-family:var(--ff-label);letter-spacing:.08em}
/* ============================================================================
   FRAMED ROWS — the tint must reach the frame's edges (2026-08-14)
   The frame owned the horizontal padding (8px 24px) while the rows had none,
   so every tinted row stopped 27px short on the left and 25px on the right —
   a band floating inside its own container instead of striping it. And 8px of
   vertical frame padding left the first row's text almost touching the border.
   Ownership flips: the FRAME holds no inset, each ROW holds its own 24px, and
   the frame clips so the tint can't square off its rounded corners.
   Used on 7 pages, so this fixes the component everywhere at once.
   ============================================================================ */
:is(.framed-tight,.framed,.rcpt-box){padding:0}
:is(.rcpt-r,.rcpt-r-tight,.rcpt-r-last,.rcpt-r-tight-last){padding:20px 24px;margin:0}
@media (max-width:640px){:is(.rcpt-r,.rcpt-r-tight,.rcpt-r-last,.rcpt-r-tight-last){padding:16px}}
body[class*="p-patterns"] .xi-patterns-016{max-width:none}
body[class*="p-patterns"] .xi-patterns-023 p{max-width:none}
body[class*="p-patterns"] .xi-patterns-022 .xi-patterns-029{max-width:none}
/* 2026-08-30: this reset was losing to the col-2 pin above by specificity —
   (0,3,1) vs (0,4,1) — so an IMPLICIT second column survived at 390 and pushed
   'Cite this library' off the viewport. Matched with :is() to the pin's weight. */
@media (max-width:900px){body[class*="p-patterns"] .xi-patterns-022>:is(*,.xi-patterns-021){grid-column:1;grid-row:auto}}
/* THREE COLUMNS, 2026-09-03. Keeps the list treatment chosen on 2026-08-30 — a rule above
   each item, no card chrome — and arranges the three items across the row instead of down it.
   The cards are NOT coming back; only the axis changes.
   Why: each memo body was a single unwrapped 912px line, 137 characters to track in one
   sweep, with the kicker column mostly empty beside it. Measured alternatives, all rejected:
   a max-width on the paragraph had NO effect (it is a grid item and the cap never bit);
   narrowing the band to 780px reached 80ch but emptied the right half and broke alignment
   with the errata box below; two columns reached 46ch but left the third item dangling
   beside a void — three items never fill two columns.
   Three columns is the only arrangement with no orphan and no dead space: 54ch at 1440,
   43ch at 1024, and the block drops from 444px to 198px. The kicker moves above the title,
   which is what removes the empty left gutter that caused the wide measure to begin with. */
body.p-home .memos{display:grid;grid-template-columns:repeat(3,1fr);column-gap:40px}
body.p-home .memo{display:block;background:none;border:none;border-top:1px solid var(--border-hairline);border-radius:0;padding:20px 0 0}
/* Each item now carries its own rule, so the container's would double up above column one. */
body.p-home .memos{border-top:none}
/* The ladder, measured at every step. Collapsing straight from three columns to one left a
   103ch line at 768 and 123ch at 900 — the original defect, back again in the middle of
   the range. Two columns there reads 49-59ch. It does leave the last row half filled,
   because three items never fill two columns; at tablet that gap is ~350px and far less
   costly than a 123-character line. A third candidate — one column with the kicker beside
   the body — was rejected on measurement: 23ch at 768, unreadably narrow, and still 97ch
   at 900.
   Result across the range: 54ch at 1440+, 43ch at 1024, 49-59ch at 768-900, 54ch at 390. */
@media (max-width:1000px) and (min-width:601px){body.p-home .memos{grid-template-columns:repeat(2,1fr)}}
@media (max-width:600px){body.p-home .memos{grid-template-columns:1fr}}
/* the kicker's cap line must sit ON the title's cap line — the two columns of one
   row align to each other, not merely inside the row (lesson 7, 2026-09-01) */
body.p-home .memo .mk{margin:12px 0 0}
body.p-home .memo h3{margin:0 0 8px}
body.p-home .thought-card{display:grid;background:none;border:none;border-bottom:1px solid var(--border-hairline);border-radius:0;padding:24px 0}
/* phone: one column means one column — the children's explicit grid-column:2
   placements must be reset too, or grid auto-creates an implicit second track
   (measured: "89px 220px" where 1fr was expected) */
/* the reset must match the heaviest pin it undoes — p:not(.mk) carries (class+element),
   so a bare * reset loses and the paragraph keeps an implicit second track */
@media(max-width:860px){body.p-home .memo{grid-template-columns:1fr;row-gap:4px}
body.p-home .memo>:is(*,p:not(.mk)){grid-column:1;grid-row:auto}
body.p-home .memo .mk{margin:0 0 4px}
/* stacked: the cap-alignment offset has no partner column */
body.p-home .thought-card>*{grid-column:1;grid-row:auto}}
/* Same trap as figure.vid-card above: .mascot is a <figure> inside .measure-c,
   so the spine's breakout force-widens it to 1040px and translates it -520.
   The ROW breaks out as one object; the plates inside obey their tracks. */
body.p-case-studies-planit .mascot-row .mascot{width:auto;max-width:none;margin:0;transform:none}
/* The first thing a keyboard reader meets on every page. It declared
   color:var(--bg) in styles.css, but an ember link rule outranked it and
   painted cream on gold at 1.36:1 — and the focus ring was gold on gold,
   i.e. invisible. Same disease as the CTA: a component that does not
   declare its own ink at a specificity that holds. */
.skip-link{background:var(--cta-grad);color:var(--btn-fill-ink);outline-color:var(--btn-fill-ink);outline-offset:2px}
/* DYSLEXIA MODE — the toggle set body.dyslexia-mode{font-family:'Lexend'} in
   styles.css, and html[data-theme="ember"] body.p-home{font-family:var(--sans)}
   outranked it on every ember page. Measured: clicking the control changed
   letter-spacing and word-spacing and left the TYPEFACE untouched — the half
   of the feature that matters most silently did nothing. Lexend was never
   loaded either, so even winning the cascade would have fallen back.
   This belongs in emphasis because a reader's accessibility choice must beat
   every page-level and component-level font declaration on the site, and
   components here deliberately declare their own family rather than inherit.
   Code keeps its monospace: distinguishing l/1/O/0 is the whole point there. */
body.dyslexia-mode,
body.dyslexia-mode *:not(code):not(pre):not(kbd):not(samp):not(code *):not(pre *){font-family:'Atkinson Hyperlegible','Source Sans 3',sans-serif;letter-spacing:.03em;word-spacing:.1em}
/* .section-title rendered at 1.15 on 139 elements and 1.30 on 54 — the 1.30
   coming from per-page .xi-* classes in @layer utilities, which outrank the
   design system in @layer base. Arpit's call: 1.15, the system's own answer.
   Stated here rather than by editing 54 extracted classes, because the next
   extraction would reintroduce it. One component, one leading. */
.section-title{line-height:1.15}
/* The homepage opted OUT of the site's own responsive spacing scale. styles.css already
   ramps --section-y 90px -> 64px (<=900) -> 48px (<=600), and every other page follows it,
   so a case study tightens on a phone. The homepage hard-codes 96px per section instead,
   which is a desktop value held at every width: measured at 390 that is a 188px gap — 23%
   of the viewport — at each of nine section joins, on a page already 15,906px tall.
   These sections now read the same token as the rest of the site. The bookends (.hero and
   .close) keep their deliberate asymmetry and are untouched. */
@media (max-width:900px){body.p-home :is(.receipts,.work,.who,.whoband,.contract,.labrow,.voices){padding-top:var(--section-y);padding-bottom:var(--section-y)}}
/* The standalone arrow-CTA link row, off the homepage. Its grammar — 11.5px, uppercase,
   .12em — lived ONLY on `body.p-home .contract-links`, so the same component on any other
   page fell back to 16px body text in sentence case. process/index.html therefore shipped
   three CTAs at 12px built out of .lbl-eyebrow (an EYEBROW class doing a CTA's job), which
   cta-grammar-check flagged as off-grammar. That gate could never run without someone
   manually starting a server on :8000, so nobody saw it.
   The grammar now belongs to the component, not to one page. Layout (gap, margin) stays
   per-page: a row under a rule and a row inside the hero want different spacing. */
.contract-links{font-family:var(--mono);font-size:11.5px;letter-spacing:.02em}}
@layer utilities{/* ----- Responsive: mobile (≤768px) ----- */
@media(max-width:768px){.xi-patterns-019{grid-template-columns:1fr}}
/* ===== CASCADE REPAIR (must stay LAST) =====
   The base sheet collapses two-column inline grids to one column on small screens.
   Production keyed that rule on the style attribute itself; the attribute is gone,
   and the xi class it became carries — so this repair must sit AFTER
   every extraction section to win the tie, as the original attribute
   rule won against inline styles. */
@media(max-width:768px){.xi-patterns-019{grid-template-columns:1fr}}
.xi-home-020{display:block;margin-top:12px;text-decoration:none;color:var(--text-muted);font-family:var(--ff-mono);font-size:11px;letter-spacing:.02em}
.xi-home-021{width:12px;height:12px}

.xi-process-004{max-width:var(--measure);margin:0 auto}
.xi-process-005{margin-bottom:16px}
.xi-process-006{font-family:var(--ff-display);font-weight:300;font-size:var(--fs-hero);color:var(--text-body);margin:0 0 20px;letter-spacing:-.02em}
.xi-process-007{font-style:italic;color:var(--text-muted);margin:0;max-width:56ch}
.xi-process-010{width:100%;height:auto;border:1px solid var(--border-strong);border-radius:8px;background:var(--surface-page)}
.xi-process-011{margin-top:12px}
.xi-process-012{margin-bottom:64px}
.xi-process-013{margin-bottom:12px}
.xi-process-014{margin:0 0 16px;max-width:none}
.xi-process-015{margin:0 0 16px}
.xi-process-016{color:var(--text-body)}
.xi-process-017{margin:0}
.xi-process-018{border-top:1px solid var(--border-strong);border-bottom:1px solid var(--border-strong);padding:32px 0;margin-bottom:64px}
.xi-process-019{font-style:italic;color:var(--text-body);margin:0;max-width:56ch}
.xi-process-020{color:var(--accent-text)}
.xi-process-021{margin:0 0 24px}
.xi-process-023{display:flex;flex-wrap:wrap;gap:20px 32px;border-top:1px solid var(--border-strong);padding-top:24px}
.xi-case-studies-adtech-004{padding-bottom:64px}
.xi-case-studies-adtech-005{font-size:21px;margin:12px 0 20px;transform:rotate(-1.6deg)}
.xi-case-studies-adtech-006{background:var(--surface-page);padding-top:48px}
.xi-case-studies-adtech-007{margin-bottom:32px}
.xi-case-studies-adtech-008{overflow:hidden}
.xi-case-studies-adtech-009{background:color-mix(in srgb, var(--accent-text) 4%, transparent)}
.xi-case-studies-adtech-010{flex:0 0 200px}
.xi-case-studies-adtech-011{flex:1 1 240px}


.xi-case-studies-adtech-014{margin-bottom:80px;padding-top:40px;border-top:1px solid var(--border-strong);scroll-margin-top:80px}
.xi-case-studies-adtech-015{margin:0 0 24px;max-width:none;line-height:1.3}
.xi-case-studies-adtech-016{margin-bottom:20px}
.xi-case-studies-adtech-017{margin:24px 0;padding:24px 32px;background:var(--surface-card);border:1px solid var(--border-strong);border-left:3px solid var(--accent-text);border-radius:4px}
.xi-case-studies-adtech-018{margin:0;font-family:var(--ff-display);font-size:var(--fs-card);font-style:italic;line-height:1.55;color:var(--text-body)}
.xi-case-studies-adtech-019{margin-bottom:80px;padding-top:40px;border-top:1px solid var(--border-strong)}
.xi-case-studies-adtech-020{margin-top:8px;margin-bottom:32px}
.xi-case-studies-adtech-021{display:block;width:100%;height:auto}

.xi-case-studies-adtech-023{width:58%}
.xi-case-studies-adtech-024{width:44%}
.xi-case-studies-adtech-025{width:31%}
.xi-case-studies-adtech-026{margin-bottom:4px}
.xi-case-studies-adtech-027{width:72%}
.xi-case-studies-adtech-028{width:47%}
.xi-case-studies-adtech-029{display:block;margin-bottom:4px}
.xi-case-studies-adtech-030{display:block}
.xi-case-studies-adtech-031{transform:scaleX(.85)}
.xi-case-studies-adtech-032{transform:scaleX(.6)}
.xi-case-studies-adtech-033{transform:scaleX(.35)}
.xi-case-studies-adtech-034{overflow:hidden;margin-bottom:24px}
.xi-case-studies-adtech-035{margin:0 0 8px;max-width:none;line-height:1.3}
.xi-case-studies-adtech-036{margin:32px 0 12px}
.xi-case-studies-adtech-037{margin:12px 0 0}
.xi-case-studies-adtech-038{background:var(--surface-card)}

.xi-case-studies-adtech-040{margin:0 0 8px}
.xi-case-studies-adtech-041{margin:0;max-width:62ch}
.xi-case-studies-adtech-042{margin:0 0 12px 0}
.xi-case-studies-adtech-043{margin:0 0 24px 0;max-width:60ch}


.xi-case-studies-adtech-046{margin-top:0;margin-bottom:64px;padding:32px;background:var(--surface-card);border:1px solid var(--border-strong);border-radius:4px}
.xi-case-studies-adtech-047{width:24px;height:24px;color:var(--accent-text);opacity:.55;margin-bottom:16px}
.xi-case-studies-adtech-048{margin:0 0 20px 0}
.xi-case-studies-adtech-049{border-top:1px solid var(--border-strong);padding-top:16px}
.xi-case-studies-adtech-050{display:block;font-family:var(--ff-mono);font-size:var(--fs-caption);letter-spacing:.05em;color:var(--text-muted);margin-top:4px}
.xi-case-studies-adtech-051{padding:32px;background:color-mix(in srgb, var(--accent-text) 3%, transparent);border:1px solid color-mix(in srgb, var(--accent-text) 10%, transparent);border-radius:4px;margin-bottom:80px}
.xi-case-studies-adtech-052{margin-bottom:16px;padding-left:24px}

.xi-case-studies-adtech-055{margin:0 0 16px 0}
.xi-case-studies-adtech-057{justify-content:space-between}


















.xi-case-studies-fintech-021{color:#282B31;background:#EFEFEC}
.xi-case-studies-fintech-022{width:64%}
.xi-case-studies-fintech-023{width:41%}
.xi-case-studies-fintech-024{width:33%}


.xi-case-studies-fintech-027{margin-bottom:24px}
.xi-case-studies-fintech-028{transform:scaleX(.82)}
.xi-case-studies-fintech-029{transform:scaleX(.65)}
.xi-case-studies-fintech-030{transform:scaleX(.28)}












.xi-case-studies-fintech-044{margin:0 0 64px 0}

















.xi-case-studies-o2-017{margin-top:2px}
.xi-case-studies-o2-018{width:52%}

.xi-case-studies-o2-020{width:100%}




.xi-case-studies-o2-025{width:74%}
.xi-case-studies-o2-026{width:88%}
.xi-case-studies-o2-027{font-family:var(--ff-mono);font-size:11px;letter-spacing:.06em;color:var(--acc-copper);margin:8px 0 0}
.xi-case-studies-o2-028{margin-top:32px}

.xi-case-studies-o2-030{margin:0 0 16px;max-width:none;line-height:1.3}
.xi-case-studies-o2-031{max-width:66ch;margin-bottom:24px}
.xi-case-studies-o2-032{margin-top:0;margin-bottom:0}
.xi-case-studies-o2-033{width:100%;max-width:860px;height:auto;border:1px solid var(--border-strong);border-radius:8px;background:var(--surface-card)}
.xi-case-studies-o2-034{margin-top:12px;text-transform:none;letter-spacing:.02em}
.xi-case-studies-o2-035{max-width:66ch;margin:48px 0 24px}
.xi-case-studies-o2-036{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(280px,100%),1fr));gap:16px}
.xi-case-studies-o2-037{width:100%;height:auto;border:1px solid var(--border-strong);border-radius:8px;display:block}
























.xi-case-studies-orgos-015{font-family:var(--ff-display);font-size:var(--fs-lead);font-weight:300;font-style:italic;color:var(--text-body);line-height:1.7;margin-bottom:32px}









.xi-case-studies-orgos-025{display:flex;flex-wrap:wrap;gap:24px 40px;margin-bottom:24px}
.xi-case-studies-orgos-026{display:block;font-variant-numeric:tabular-nums lining-nums}
.xi-case-studies-orgos-027{display:block;margin-top:8px;max-width:22ch}



























.xi-case-studies-ptc-020{margin:0 0 20px;max-width:62ch}

.xi-case-studies-ptc-022{border:none;box-shadow:none;overflow:visible;display:flex;flex-direction:column;gap:8px;justify-content:center}
.xi-case-studies-ptc-023{margin-right:24px}
.xi-case-studies-ptc-024{margin-left:16px;margin-right:8px}
.xi-case-studies-ptc-025{margin-right:32px}
.xi-case-studies-ptc-026{margin-left:24px}
.xi-case-studies-ptc-027{margin-right:16px;margin-left:8px}
.xi-case-studies-ptc-028{text-align:center;font-family:var(--ff-mono);font-size:11px;letter-spacing:.04em;color:var(--text-muted);padding-top:4px}
.xi-case-studies-ptc-029{display:flex;flex-direction:column}
.xi-case-studies-ptc-030{display:block;width:100%;height:100%;object-fit:cover;object-position:top}
.xi-case-studies-ptc-031{display:block;margin-bottom:4px;font-family:var(--ff-mono);font-size:12px;letter-spacing:.04em;color:var(--accent-text)}
.xi-case-studies-ptc-032{display:block;font-family:var(--ff-mono);font-size:var(--fs-caption);color:var(--text-muted);line-height:1.6}



.xi-case-studies-ptc-036{margin-top:40px;margin-bottom:40px;text-align:center}
.xi-case-studies-ptc-037{height:auto}









.xi-case-studies-ptc-048{margin-top:0;margin-bottom:80px;padding:32px;background:var(--surface-card);border:1px solid var(--border-strong);border-radius:4px}










.xi-case-studies-vc-diligence-002,.xi-case-studies-vc-diligence-003,.xi-case-studies-vc-diligence-004{font-size:21px;margin:12px 0 20px;transform:rotate(-1.6deg)}















.xi-case-studies-vc-diligence-020{margin:16px 0 0;padding-top:12px;border-top:1px solid var(--border-strong)}











.xi-case-studies-vc-diligence-032{padding:32px;background:color-mix(in srgb, var(--accent-text) 3%, transparent);border:1px solid color-mix(in srgb, var(--accent-text) 10%, transparent);border-radius:4px;margin-bottom:64px}
.xi-case-studies-vc-diligence-033{margin:0;padding-left:24px}






.xi-case-studies-vc-diligence-041,.xi-lab-003{max-width:26ch}

.xi-lab-006{max-width:24ch}
.xi-lab-eval-003{max-width:20ch}
.xi-lab-eval-005{margin:0 0 8px;display:block}




.xi-lab-loop-006{margin-bottom:40px}

.xi-lab-loop-008{background:var(--accent)}
.xi-lab-loop-009{background:var(--accent-text)}
.xi-lab-loop-010{overflow:hidden;margin-bottom:48px}

.xi-lab-loop-012{flex:0 0 220px}

.xi-lab-loop-014{background:transparent}
.xi-lab-loop-015{max-width:none}








.xi-patterns-004{padding:90px var(--page-x) 48px;background:var(--surface-page)}
.xi-patterns-005{max-width:var(--inner-max);margin:0 auto}

.xi-patterns-007{margin:0 0 20px 0;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual}
.xi-patterns-008{font-style:italic;margin:0 0 20px 0;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual;font-variant-numeric:oldstyle-nums proportional-nums}

.xi-patterns-012{display:block;padding:32px;border:1px solid var(--accent-fill);border-left:3px solid var(--accent-text);border-radius:4px;background:color-mix(in srgb, var(--accent-text) 4%, transparent);text-decoration:none;color:inherit;margin-bottom:24px;transition:border-color 0.3s,transform 0.3s}



.xi-patterns-016{margin:0 0 16px 0;max-width:var(--measure)}
.xi-patterns-017{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap}
.xi-patterns-018{display:block;padding:24px 24px;border:1px solid var(--border-strong);border-radius:4px;background:var(--surface-card);text-decoration:none;color:inherit;margin-bottom:64px;transition:border-color .25s}
.xi-patterns-019{display:grid;grid-template-columns:repeat(2,1fr);gap:24px;margin-bottom:64px}
@media(max-width:768px){.xi-patterns-019{grid-template-columns:1fr}}
.xi-patterns-021{margin-bottom:16px}
.xi-patterns-022{padding:32px;background:var(--surface-card);border:1px solid var(--border-strong);border-radius:4px;margin-bottom:24px}
.xi-patterns-023{border:1px solid var(--border-strong);border-radius:4px;padding:24px 24px;margin:0 0 40px 0}
.xi-patterns-024{margin:0 0 12px 0;max-width:var(--measure)}
.xi-patterns-026{margin:0;max-width:var(--measure)}

.xi-patterns-028{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;flex-wrap:wrap}
.xi-patterns-029{font-family:var(--ff-mono);font-size:var(--fs-caption);line-height:1.8;color:var(--text-body);margin:0;flex:1;min-width:260px}
.xi-patterns-030{padding:4px 12px;background:transparent;border:1px solid var(--accent-fill);border-radius:2px;cursor:pointer;transition:background 0.3s,color 0.3s}
.xi-patterns-031{margin:20px 0 0 0}

.xi-patterns-act-review-ignore-006{margin:0;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual}
.xi-patterns-act-review-ignore-007{padding:4px 12px;border-radius:4px;background-color:var(--acc-copper);white-space:nowrap}
.xi-patterns-act-review-ignore-008{margin-top:8px}

.xi-patterns-act-review-ignore-013{margin-top:0;margin-bottom:0;border:1px solid var(--border-strong);border-radius:6px;overflow:hidden;background:var(--surface-card)}

.xi-patterns-act-review-ignore-015{margin-bottom:20px;font-style:italic;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual;font-variant-numeric:oldstyle-nums proportional-nums}


.xi-patterns-act-review-ignore-018{margin:0 0 24px;max-width:none}


.xi-patterns-act-review-ignore-021{overflow-x:auto;margin:24px 0}
.xi-patterns-act-review-ignore-022{width:100%;border-collapse:collapse;font-variant-numeric:tabular-nums lining-nums}
.xi-patterns-act-review-ignore-023{border-bottom:1px solid var(--border-strong)}
.xi-patterns-act-review-ignore-024{text-align:left;padding:8px 12px}
.xi-patterns-act-review-ignore-025{padding:8px 12px}
.xi-patterns-act-review-ignore-026{padding-left:24px}
.xi-patterns-act-review-ignore-027{margin-bottom:8px}
.xi-patterns-act-review-ignore-028{background:color-mix(in srgb, var(--accent-text) 3%, transparent)}


.xi-patterns-act-review-ignore-031{min-width:200px;background:var(--surface-page)}
.xi-patterns-act-review-ignore-032{background:transparent;cursor:pointer;transition:background 0.3s,color 0.3s}


.xi-patterns-act-review-ignore-035{border-top:1px solid var(--border-strong);padding-top:24px}




.xi-patterns-ai-failure-states-008{border-bottom:1px dotted var(--text-body);cursor:help}



.xi-patterns-ai-failure-states-015{background:var(--surface-sunken)}
.xi-patterns-ai-failure-states-016{margin-bottom:24px;text-align:center}
.xi-patterns-ai-failure-states-017{display:flex;gap:20px;align-items:stretch}
.xi-patterns-ai-failure-states-018{flex:1;background:var(--surface-card);border:1px solid color-mix(in srgb, var(--status-negative) 40%, transparent);border-radius:6px;padding:24px;opacity:0.8;display:flex;flex-direction:column;justify-content:center;align-items:center;text-align:center}

.xi-patterns-ai-failure-states-020{width:40px;height:40px;border-radius:50%;background:var(--status-neg-bg);color:var(--status-negative);display:flex;align-items:center;justify-content:center;font-size:var(--fs-lead);margin-bottom:16px}
.xi-patterns-ai-failure-states-021{margin-bottom:8px;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual}
.xi-patterns-ai-failure-states-022{font-family:var(--ff-sans);font-size:var(--fs-caption);color:var(--text-muted)}
.xi-patterns-ai-failure-states-023{flex:1;background:var(--surface-card);border:1px solid var(--accent-text);border-radius:6px;padding:24px;box-shadow:var(--elev-2)}
.xi-patterns-ai-failure-states-024{margin-bottom:16px;text-align:center}
.xi-patterns-ai-failure-states-025{display:flex;gap:12px;align-items:flex-start;margin-bottom:16px}
.xi-patterns-ai-failure-states-026{width:24px;height:24px;border-radius:4px;background:var(--text-muted);opacity:0.2}
.xi-patterns-ai-failure-states-027{font-family:var(--ff-sans);font-size:var(--fs-ui);color:var(--text-body);font-weight:600;margin-bottom:4px}
.xi-patterns-ai-failure-states-028{font-family:var(--ff-sans);font-size:var(--fs-caption);color:var(--text-muted);line-height:1.5}


.xi-patterns-ai-failure-states-031{display:flex;gap:8px}
.xi-patterns-ai-failure-states-032{flex:1;text-align:center;padding:8px;border:1px solid var(--border-strong);border-radius:4px;font-family:var(--ff-sans);font-size:var(--fs-caption);color:var(--text-body)}
.xi-patterns-ai-failure-states-033{flex:1;text-align:center;padding:8px;background:var(--text-body);color:var(--surface-page);border-radius:4px;font-family:var(--ff-sans);font-size:var(--fs-caption)}












.xi-patterns-ai-failure-states-046{margin-bottom:32px;padding-top:32px;border-top:1px solid var(--border-strong)}
.xi-patterns-ai-failure-states-047{font-family:var(--ff-display);font-size:var(--fs-card);color:var(--accent-text);text-decoration:none;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual}










.xi-patterns-calibration-track-record-014{margin-top:8px;margin-bottom:48px;text-align:center}







.xi-patterns-calibration-track-record-022{overflow-x:auto}




























.xi-patterns-capability-contract-023{position:relative}
.xi-patterns-capability-contract-024{position:absolute;top:12px;right:12px;padding:4px 12px;background:var(--surface-page);border:1px solid var(--accent-fill);border-radius:2px;cursor:pointer;transition:background 0.3s,color 0.3s}
.xi-patterns-capability-contract-025{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:4px;padding:24px 24px;white-space:pre-wrap;overflow-wrap:break-word;/* the template must be READ, not just copied: ~130px of every long line hid behind a sideways scroll at every width (2026-09-02 sweep) */margin:0;font-family:var(--ff-mono);font-size:var(--fs-caption);line-height:1.8;color:var(--text-muted);overflow-x:auto}






























.xi-patterns-confidence-scores-030{display:flex;flex-direction:column;gap:16px;max-width:400px;margin:0 auto}
.xi-patterns-confidence-scores-031{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:6px;padding:16px;display:flex;justify-content:space-between;align-items:center}
.xi-patterns-confidence-scores-032{width:32px;height:32px;background:var(--text-muted);opacity:0.1;border-radius:4px}
.xi-patterns-confidence-scores-033{width:120px;height:12px;background:var(--text-body);border-radius:2px}
.xi-patterns-confidence-scores-034{background:rgba(94, 212, 142, 0.1);border:1px solid rgba(94, 212, 142, 0.2);padding:4px 8px;border-radius:4px;display:flex;gap:4px;align-items:center}
.xi-patterns-confidence-scores-035{width:6px;height:6px;background:var(--status-positive);border-radius:50%}
.xi-patterns-confidence-scores-036{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);color:var(--status-positive);font-weight:600;font-variant-numeric:tabular-nums lining-nums}
.xi-patterns-confidence-scores-037{width:140px;height:12px;background:var(--text-body);border-radius:2px}
.xi-patterns-confidence-scores-038{background:color-mix(in srgb, var(--accent-text) 10%, transparent);border:1px solid color-mix(in srgb, var(--accent-text) 20%, transparent);padding:4px 8px;border-radius:4px;display:flex;gap:4px;align-items:center}
.xi-patterns-confidence-scores-039{width:6px;height:6px;background:var(--accent-text);border-radius:50%}
.xi-patterns-confidence-scores-040{font-family:var(--ff-sans);font-size:var(--fs-eyebrow);color:var(--accent-text);font-weight:500}
.xi-patterns-confidence-scores-041{width:100px;height:12px;background:var(--text-body);border-radius:2px}
.xi-patterns-confidence-scores-042{background:transparent;border:1px dashed var(--text-muted);padding:4px 8px;border-radius:4px;display:flex;gap:4px;align-items:center;opacity:0.7}
.xi-patterns-confidence-scores-043{font-family:var(--ff-sans);font-size:var(--fs-eyebrow);color:var(--text-muted);font-style:italic}


















.xi-patterns-human-in-loop-016{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:6px;padding:24px;max-width:450px;margin:0 auto;box-shadow:var(--elev-2)}
.xi-patterns-human-in-loop-017{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:20px}
.xi-patterns-human-in-loop-018{font-family:var(--ff-display);font-size:18px;color:var(--text-body);margin-bottom:4px;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual}
.xi-patterns-human-in-loop-019{font-family:var(--ff-sans);font-size:12px;color:var(--text-muted)}
.xi-patterns-human-in-loop-020{width:24px;height:24px;border-radius:50%;background:var(--text-muted);opacity:0.1}
.xi-patterns-human-in-loop-021{background:color-mix(in srgb, var(--accent-text) 5%, transparent);border:1px solid color-mix(in srgb, var(--accent-text) 20%, transparent);border-radius:4px;padding:12px;margin-bottom:20px}
.xi-patterns-human-in-loop-022{font-family:var(--ff-mono);font-size:var(--fs-micro);color:var(--accent-text);letter-spacing:.02em;margin-bottom:4px}
.xi-patterns-human-in-loop-023{font-family:var(--ff-sans);font-size:13px;color:var(--text-body)}

.xi-patterns-human-in-loop-025{font-family:var(--ff-sans);font-size:12px;color:var(--text-body);font-weight:600;margin-bottom:8px}
.xi-patterns-human-in-loop-026{padding:4px 12px;border:1px solid var(--border-strong);border-radius:16px;font-family:var(--ff-sans);font-size:11px;color:var(--text-body)}
.xi-patterns-human-in-loop-027{padding:4px 12px;background:var(--text-body);color:var(--surface-page);border-radius:16px;font-family:var(--ff-sans);font-size:11px}
.xi-patterns-human-in-loop-028{display:flex;justify-content:flex-end;gap:12px;border-top:1px solid var(--border-strong);padding-top:16px}
.xi-patterns-human-in-loop-029{padding:8px 16px;font-family:var(--ff-sans);font-size:12px;color:var(--text-muted);font-weight:600}
.xi-patterns-human-in-loop-030{padding:8px 16px;background:var(--text-body);color:var(--surface-page);border-radius:4px;font-family:var(--ff-sans);font-size:12px;font-weight:600}





.xi-patterns-human-in-loop-036{margin-top:16px}















.xi-patterns-human-in-loop-052{color:var(--accent-text);text-decoration:none;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual}












.xi-patterns-ml-explainability-016{background:var(--surface-card);border:1px solid var(--border-strong);border-radius:6px;padding:24px;max-width:500px;margin:0 auto;box-shadow:var(--elev-2)}

.xi-patterns-ml-explainability-018{display:flex;flex-direction:column;gap:16px}
.xi-patterns-ml-explainability-019{display:flex;justify-content:space-between;margin-bottom:4px}
.xi-patterns-ml-explainability-020{font-variant-numeric:tabular-nums lining-nums}
.xi-patterns-ml-explainability-021{width:100%;height:6px;background:var(--text-muted);border-radius:3px;opacity:0.1;overflow:hidden}
.xi-patterns-ml-explainability-022{width:45%;height:100%;background:var(--accent-text)}
.xi-patterns-ml-explainability-023{width:30%;height:100%;background:var(--accent-text)}
.xi-patterns-ml-explainability-024{width:15%;height:100%;background:var(--accent-text)}













.xi-patterns-ml-explainability-038{font-size:var(--fs-caption);color:var(--text-muted);margin-top:12px;font-style:italic}



































































.xi-resources-003{padding:104px 24px 40px;background:var(--surface-page)}
.xi-resources-004{max-width:900px;margin:0 auto}
.xi-resources-005{font-family:var(--ff-display);font-size:var(--fs-hero);font-weight:300;letter-spacing:-0.02em;color:var(--text-body);margin-bottom:20px}
.xi-resources-007{display:grid;grid-template-columns:1fr;gap:40px}
.xi-resources-008{background:var(--surface-card);text-decoration:none;transition:border-color 0.3s,transform 0.3s var(--ease-out)}



.xi-resources-ai-design-checklist-006{font-family:var(--ff-display);font-size:var(--fs-hero);font-weight:300;line-height:1.15;letter-spacing:-0.02em;color:var(--text-body);margin-bottom:20px}
.xi-resources-ai-design-checklist-007{font-size:var(--fs-caption);color:var(--text-muted);font-family:var(--ff-mono);letter-spacing:.02em}
.xi-resources-ai-design-checklist-009{font-style:italic;max-width:none;margin-bottom:40px}
.xi-resources-ai-design-checklist-010{margin:-24px 0 40px}
.xi-resources-ai-design-checklist-011{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin:-16px 0 32px}
.xi-resources-ai-design-checklist-012{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.06em;color:var(--accent-text)}
.xi-resources-ai-design-checklist-013{background:none;border:1px solid var(--border-strong);border-radius:3px;color:var(--text-muted);font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:.02em;padding:4px 8px;cursor:pointer}
.xi-resources-ai-design-checklist-014{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);color:var(--text-muted);letter-spacing:.04em}
.xi-resources-ai-design-checklist-015{margin:40px 0 20px;max-width:none}
.xi-resources-ai-design-checklist-016{margin:-8px 0 16px}
.xi-resources-ai-design-checklist-018{font-size:var(--fs-body);color:var(--text-body);line-height:1.8;margin-bottom:20px;padding-left:24px}
.xi-resources-ai-design-checklist-019{list-style:none;margin:0 0 2px -24px}
.xi-resources-ai-design-checklist-020{display:flex;gap:12px;align-items:flex-start;cursor:pointer;padding:8px 8px;border-radius:4px;transition:background .15s}
.xi-resources-ai-design-checklist-021{margin-top:4px;accent-color:var(--accent-text);width:15px;height:15px;flex:0 0 auto}
.xi-resources-ai-design-checklist-022{padding:32px;border-left:3px solid var(--accent-text);margin:32px 0;background:var(--surface-card)}
.xi-resources-ai-design-checklist-023{font-family:var(--ff-display);font-style:italic;font-size:var(--fs-lead);line-height:1.6;color:var(--text-body);margin:0}
.xi-resources-ai-design-checklist-024{font-size:var(--fs-body);color:var(--text-body);line-height:1.8;margin-bottom:20px}

.xi-resources-founder-questions-006{font-family:var(--ff-display);font-size:var(--fs-hero);font-weight:300;line-height:1.15;letter-spacing:-0.02em;color:var(--text-body);margin:0 0 20px}

.xi-resources-founder-questions-009{font-style:italic;margin-bottom:40px}
.xi-resources-founder-questions-010{max-width:none;margin:48px 0 24px}
.xi-resources-founder-questions-011{font-size:var(--fs-body);color:var(--text-body);line-height:1.7;margin-bottom:20px;padding-left:24px}

.xi-resources-founder-questions-013{color:var(--text-muted);margin-top:8px;font-size:var(--fs-ui)}
.xi-resources-founder-questions-014{padding:24px;border-left:3px solid var(--accent-text);margin:32px 0;background:var(--surface-card)}
.xi-resources-founder-questions-015{font-family:var(--ff-display);font-weight:300;font-style:italic;font-size:var(--fs-lead);line-height:1.4;color:var(--text-body);margin:0}

.xi-resources-intelligent-systems-glossary-006{font-family:var(--ff-display);font-size:var(--fs-hero);font-weight:300;line-height:1.15;letter-spacing:-0.02em;color:var(--text-body);margin-bottom:20px;font-optical-sizing:auto;font-variant-ligatures:common-ligatures contextual}




.xi-resources-intelligent-systems-glossary-012{font-weight:600;margin-top:16px}
.xi-resources-intelligent-systems-glossary-013{margin-left:0;color:var(--text-muted)}
.xi-resources-intelligent-systems-glossary-014{font-weight:600;margin-top:16px;scroll-margin-top:80px}
.xi-resources-intelligent-systems-glossary-015{font-size:var(--fs-caption);color:var(--text-muted);margin-top:64px;padding-top:40px;border-top:1px solid var(--border-strong)}
.xi-writing-003{padding:100px 24px 40px;background:var(--surface-page);border-bottom:1px solid var(--border-strong)}


.xi-writing-006{margin:0;max-width:54ch}


.xi-writing-011{display:grid;grid-template-columns:1fr;gap:24px}

.xi-writing-013{margin:0 0 12px}

.xi-writing-015{margin-top:64px;padding-top:40px;border-top:1px solid var(--border-strong)}
.xi-writing-016{display:flex;align-items:baseline;justify-content:space-between;flex-wrap:wrap;gap:12px;margin-bottom:24px}
.xi-writing-017{margin:0;max-width:none}
.xi-writing-018{text-decoration:none}







.xi-writing-confidence-scoring-014{padding:24px 24px;border-left:3px solid var(--accent-text);margin:32px 0;background:var(--surface-card)}
.xi-writing-confidence-scoring-015{font-family:var(--ff-display);font-weight:400;font-style:italic;font-size:var(--fs-card);line-height:1.5;color:var(--text-body);margin:0}
.xi-writing-confidence-scoring-016{padding:24px 24px;border:1px solid var(--border-strong);border-radius:4px;background:var(--surface-card);margin:48px 0 8px}

.xi-writing-confidence-scoring-018{line-height:1.7;margin:0 0 12px}
.xi-writing-confidence-scoring-019{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);letter-spacing:0.05em;color:var(--accent-text);text-decoration:none}


.xi-writing-confidence-scoring-022{display:grid;grid-template-columns:1fr 1fr;gap:20px}
.xi-writing-confidence-scoring-023{display:block;padding:16px;border:1px solid var(--border-strong);border-radius:4px;background:var(--surface-card);text-decoration:none;transition:border-color 0.3s}
.xi-writing-confidence-scoring-024{font-family:var(--ff-mono);font-size:var(--fs-eyebrow);color:var(--accent-text);letter-spacing:.02em;margin-bottom:4px}







.xi-writing-explainability-015{font-style:italic;margin:0}






























.xi-writing-human-in-loop-011{max-width:none;margin:0 0 20px}



.xi-writing-human-in-loop-015{font-style:italic;max-width:none;margin:0}








}
@layer overrides{/* ── ember.css, the unlayered half (2026-08-29 →): the last word, by position then and by layer now ── */
/* ============================================================================
/* ---------- work-grid tier (2026-08-29, Arpit's pick: headliners + index cards).
   The three flagship lanes keep their exact treatment; the four range cases
   compress to index cards in the same skew family. Accent cycling follows the
   system order ember -> violet -> amber -> rose. Evidence: the 3-5-case
   consensus in the Five-Minute Screen dossier; tiering, not deletion. */
body.p-home .range-lbl{font-family:var(--mono);font-size:11.5px;letter-spacing:.02em;color:var(--text-muted);margin-top:40px}
/* x5 and x6 exist because the strip went from four products to six on
   2026-09-08. Without them the last two fell back to .idx's own --lc (ember) and
   two cases that had distinct colours came out identical — a positional class
   system silently loses its identity the moment the list grows. */

/* ---------- the verdict slip (2026-08-29, Arpit's pick: option A). A cream
   evidence object + one product plate directly under the case hero, so the
   2-5-minute screener gets outcome / call / ownership / boundary without
   entering the essay. Scoped to all case pages: AdTech first, FinTech and
   VC-diligence to follow. The slip declares its own cream tokens (component
   declares its critical properties; the p-home token scope does not reach
   case pages). All inks below are pre-computed pairs from the system table. */
body[class*="p-case-studies"] .vband{padding:0 0 clamp(40px,6vh,64px)}
body[class*="p-case-studies"] .vband-in{max-width:1040px;margin:0 auto;padding:0 24px;display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);gap:clamp(24px,4vw,48px);align-items:start}
@media (max-width:900px){body[class*="p-case-studies"] .vband-in{grid-template-columns:1fr}}
body[class*="p-case-studies"] .vslip{position:relative;background:var(--surface-page);color:var(--text-body);border-radius:var(--radius-2);padding:24px 32px 20px;box-shadow:var(--elev-2);transform:rotate(-.5deg)}
body[class*="p-case-studies"] .vslip-stamp{position:absolute;top:20px;right:20px;border:2px solid var(--acc-copper);color:var(--acc-copper);font-family:var(--mono);font-size:11.5px;letter-spacing:.02em;padding:4px 8px;transform:rotate(3deg)}
body[class*="p-case-studies"] .vslip-k{font-family:var(--mono);font-size:11.5px;letter-spacing:.02em;color:var(--acc-copper);padding-right:118px}
body[class*="p-case-studies"] .vslip-title{font-family:var(--serif);font-weight:400;font-size:24px;line-height:1.2;letter-spacing:0;color:var(--text-body);margin:8px 0 4px;max-width:20ch}
body[class*="p-case-studies"] .vslip-sub{font-size:13px;line-height:1.5;color:var(--text-muted);margin-bottom:12px}
body[class*="p-case-studies"] .vslip-rows{border-top:2px solid var(--text-body);margin:0}
body[class*="p-case-studies"] .vslip-rows>div{display:grid;grid-template-columns:96px minmax(0,1fr);gap:12px;padding:12px 0;border-bottom:1px solid var(--border-hairline)}
body[class*="p-case-studies"] .vslip-rows>div:last-child{border-bottom:none}
body[class*="p-case-studies"] .vslip-rows dt{font-family:var(--mono);font-size:11.5px;letter-spacing:.02em;color:var(--text-muted);padding-top:2px}
body[class*="p-case-studies"] .vslip-rows dd{font-size:13.5px;line-height:1.6;color:var(--text-body);margin:0}
body[class*="p-case-studies"] .vslip-rows dd b{font-weight:600;color:var(--text-body)}
body[class*="p-case-studies"] .vslip-rows dd a{color:var(--acc-copper);font-size:12.5px;white-space:nowrap;text-decoration:underline;text-underline-offset:2px}
@media (max-width:520px){body[class*="p-case-studies"] .vslip-rows>div{grid-template-columns:1fr;gap:4px;padding:12px 0}}
body[class*="p-case-studies"] .vplate-wrap{margin:0}
body[class*="p-case-studies"] .vplate{background:var(--surface-card);color:var(--text-primary);border-radius:12px;overflow:hidden;box-shadow:var(--elev-2)}
body[class*="p-case-studies"] .vplate-bar{background:#22201C;color:#A99E8B;display:flex;gap:8px;align-items:center;padding:8px 12px;font-family:var(--mono);font-size:11.5px;letter-spacing:.08em}
body[class*="p-case-studies"] .vplate-bar i{width:8px;height:8px;border-radius:50%;background:#4A453C}
body[class*="p-case-studies"] .vplate-bar em{font-style:normal}
body[class*="p-case-studies"] .vplate-body{padding:16px 20px 20px;font-size:13px}
body[class*="p-case-studies"] .vplate-head{display:flex;justify-content:space-between;gap:12px;align-items:baseline;border-bottom:1px solid var(--border-hairline);padding-bottom:12px;margin-bottom:8px}
body[class*="p-case-studies"] .vplate-head b{font-family:var(--serif);font-weight:400;font-size:17px;line-height:1.45}
body[class*="p-case-studies"] .vplate-head span{font-family:var(--mono);font-size:11.5px;letter-spacing:.02em;color:var(--text-muted);white-space:nowrap}
body[class*="p-case-studies"] .vplate-row{display:flex;justify-content:space-between;gap:12px;padding:8px 0;border-bottom:1px dashed var(--border-hairline);line-height:1.45}
body[class*="p-case-studies"] .vplate-row .vl b{display:block;font-weight:600;font-size:13.5px;line-height:1.45}
body[class*="p-case-studies"] .vplate-row .vl span{color:var(--text-muted);font-size:12px;line-height:1.5}
body[class*="p-case-studies"] .vplate-row .vr{text-align:right;font-family:var(--mono);font-size:11.5px;color:var(--text-muted);white-space:nowrap}
body[class*="p-case-studies"] .vplate-row .vr b{display:block;color:var(--acc-copper);font-size:13px;font-weight:500}
body[class*="p-case-studies"] .vplate-ok{margin-top:12px;background:#EAF0EE;border-left:3px solid #2F5D52;padding:8px 12px;font-size:12px;line-height:1.5;color:#24493F}
body[class*="p-case-studies"] .vplate-cap{font-family:var(--mono);font-size:11.5px;letter-spacing:.06em;color:var(--text-muted);margin-top:12px;line-height:1.6}
@media (prefers-reduced-motion:reduce){body[class*="p-case-studies"] .vslip,
body[class*="p-case-studies"] .vslip-stamp{transform:none}}
/* ---------- how-i-build section (2026-08-29, phase 2 of the evidence plan).
   Reuses .labrow rhythm and the .memo component verbatim (identity gate:
   one component, one rendering). Only the closing line is new. */

/* ---------- vplate image variant (2026-08-29): PlanIt's band carries a real
   shipped screen instead of a text reconstruction. Cropped from the top so the
   score and voice stay visible at the plate's height. */
body[class*="p-case-studies"] .vplate-shot{display:block;width:100%;height:auto;max-height:340px;object-fit:cover;object-position:top}
/* ---------- contact facts strip (2026-08-29, F2 of the reader review): the
   screening facts and channels a recruiter needs, in plain text at the contact
   block. The email address is still assembled at runtime (privacy: never
   printed in served HTML); the resume PDF is the same artifact sent to ATSes. */

/* ---------- the process walkthrough video (2026-08-29): self-hosted, no third party,
   no tracking — it reuses the .vid-main/.vid-frame component the AdTech film already
   uses, so one component keeps one rendering. preload="none" means the 16MB file is
   fetched only on a real play; the poster carries the first impression. */
.vid-frame video{position:absolute;inset:0;width:100%;height:100%;border:0;background:#000;object-fit:contain}
.vid-walk{max-width:1000px;margin-left:auto;margin-right:auto}
.vid-meta{font-family:var(--ff-mono),monospace;font-size:12px;letter-spacing:.02em;color:var(--text-muted,var(--text-muted))}
.vid-note-t{font-size:14px;line-height:1.65;color:var(--text-muted,var(--text-muted));max-width:68ch}
.vid-fallback{padding:24px;font-size:14px;color:var(--text-muted,var(--text-muted))}
body.p-process .vid-walk{margin-top:24px;margin-bottom:40px}
/* /process has a narrow prose column (~493px at 1440), which rendered the walkthrough
   too small to read the screens inside it. The video breaks out to a readable width,
   centred on the viewport rather than the column. Measured, not guessed. */
body.p-process .vid-walk{--vw-w:min(1000px, calc(100vw - 80px));width:var(--vw-w);max-width:none;margin-left:calc((100% - var(--vw-w)) / 2);margin-right:calc((100% - var(--vw-w)) / 2)}
/* The walkthrough's kicker must align with the video it introduces, not with the prose
   column the video breaks out of — inner elements align to one another, not just inside
   correct outer bounds. Same breakout maths as .vid-walk. */
body.p-process .vid-kick{--vw-w:min(1000px, calc(100vw - 80px));margin-left:calc((100% - var(--vw-w)) / 2)}
/* The whole video frame is clickable (attention.js toggles play) — say so with the cursor. */
.vid-frame video{cursor:pointer}
/* ---------- consolidated bands (2026-08-29): twelve homepage sections became ten, so
   each reader question is answered once. Two merges need layout, not new components.
   1) WHO + HOW-I-LEAD share one band: the who half keeps its two-column grid, the lead
      half (which carries the #how-i-lead nav anchor, linked from 50 places) resets to a
      single column beneath it. 2) AI-WORKFLOW + LAB share one band, split by a rule. */
body.p-home .whoband{background:var(--surface-sunken);padding:96px 0 88px}
body.p-home .whoband .wrap.wl-lead{display:block;margin-top:80px;padding-top:48px;border-top:1px solid var(--border-strong)}
body.p-home .whoband .wl-lead h3{font-family:var(--serif);font-weight:300;font-size:clamp(26px,3vw,40px);line-height:1.2;max-width:34ch;margin:12px 0 40px;color:var(--text-body)}
body.p-home .whoband .wl-lead .k{color:var(--acc-rose)}
body.p-home .whoband .wl-lead p{max-width:none;margin-bottom:0}
@media (max-width:860px){body.p-home .whoband .wrap.wl-lead{margin-top:48px;padding-top:40px}}
/* ============================================================
   CHAPTER OPENERS (2026-08-29) — the four acts of the homepage.
   Arpit's call after three review rounds: the story needs chapters
   a scroller can SEE, inside the ember system — big authored
   numerals, not 12px margin labels (those "got lost in the scroll").
   Component declares its own critical properties (lesson 11):
   numeral size/color/leading are set here, never inherited.
   Accent per act follows the site cycle: ember → violet → amber → rose.
   ============================================================ */
/* two columns now, not three: the decorative .chap-rule came out with the act
   title's resize on 2026-09-08. It was a 48px dash drawn to sit beside a 12px
   uppercase eyebrow; against a wrapping 26px serif line it stranded at the first
   line's height, and the act boundary already carries a full-bleed hairline
   (main > section:has(.chap)) — so it was a second, smaller, orphaned rule
   saying the same thing.

   ALIGNMENT IS BASELINE, DELIBERATELY — 2026-09-08. Arpit: "these numerals
   don't feel align to the corresponding text." He was right, in all four acts
   at all three widths. align-items:start was chosen here to stop `center`
   floating the numeral against the middle of a wrapping title — correct
   reasoning, wrong remedy: `start` aligns the two BOXES, and the numeral's box
   is solid-set (line-height:1) while the title's carries half-leading
   (1.25 desktop / 1.5 mobile). Identical box tops (measured 1141.0 and 1141.0),
   baselines 6.0px apart at 1440 and 7.0px at 768 and 390 — so the numeral rode
   high and every geometry check passed, because they all compare an element to
   its container and never two siblings to each other. Those figures are the
   browser's own: a zero-size inline-block sits ON the baseline, so its bottom
   edge is the baseline exactly. My first pass approximated the ascent as 0.75em
   and reported 8.3px / 11.5px — wrong, and wrong in the direction that
   flatters the finding. tools/baseline-align-check.py now measures this class
   on every page, and its calibration is this defect, planted and watched go
   red in all four acts.
   `baseline` is the right answer and not the trap my own note warns about: a
   baseline row breaks when you wanted vertical centring and a child wraps, but
   here matching text baselines IS the intent — the numeral belongs ON the
   title's first line, and first-baseline alignment is exactly what a wrapping
   title should get. .chap-i sits at grid-column:1/-1 in row 2 and is untouched. */
.chap{display:grid;grid-template-columns:auto 1fr;column-gap:16px;row-gap:12px;align-items:baseline;margin:0 0 40px}
/* THE ACT NUMERAL WAS THE LOUDEST THING ON THE PAGE — 2026-09-08.
   Arpit: "I still can't confidently scan it in a scroll." Instrument built for
   it: step down the page half a viewport at a time and record the LARGEST piece
   of text on screen, because that is what a scanning eye actually reads.
   Result at 1440x900: EIGHT of nineteen scan positions had a bare "01" / "02" /
   "03" / "04" as the biggest thing in view. At clamp(56px,7vw,88px) the numeral
   rendered 88px — TWICE every section heading (42px) and larger than the h1's
   own 83px. So the scan path was a list of numbers, not a list of claims, and
   the eye was pulled off "By Friday of week one I've read your evals..." onto a
   marker that says nothing.
   The principle: in a scroll, the largest thing on screen must be the CLAIM, not
   the marker. The numeral stays an act marker and stops out-shouting the
   heading it introduces — capped below the 42px section h2. */
.chap-n{font-family:var(--serif);font-weight:300;font-size:clamp(18px,1.7vw,22px);line-height:1;letter-spacing:-0.02em}
/* AND THE ACT'S TITLE IS THE ACT'S CLAIM, so it has to be readable at scan
   scale. With the numeral shrunk, one scan position was still left reading a bare
   "03": the act opener is on screen there but the section's own h2 is not yet, and
   the title beside the numeral was 12px mono uppercase — an eyebrow, invisible to
   a scanning eye. Serif at 26px puts the four act titles ("The person — who you'd
   be hiring", "The method — the contract, then the work") into the scan path,
   while staying under the 42px section h2 so the h2 still leads inside the act.
   This changes the .chap component the design system documents as
   "serif 300 numeral + mono 12px UC title"; DESIGN-SYSTEM-EMBER.md is updated to
   match, because a rule I wrote down is not a fact I verified. */
.chap-t{font-family:var(--serif);font-size:clamp(20px,2vw,26px);font-weight:300;letter-spacing:-0.01em;line-height:1.25;text-transform:none;color:var(--text-body)}
.chap-i{grid-column:1/-1;margin:0;font-family:var(--sans);font-size:16px;line-height:1.55;color:var(--text-muted);max-width:600px}
.chap-ember .chap-n{color:var(--acc-copper)}
.chap-violet .chap-n{color:var(--acc-violet)}
.chap-amber .chap-n{color:var(--acc-amber)}
.chap-rose .chap-n{color:var(--acc-rose)}
@media (max-width:768px){.chap{margin-bottom:32px}
.chap-n{font-size:18px}
.chap-t{line-height:1.5}}
/* THE LAB, COMPRESSED TO ONE PROOF ROW (2026-08-30, Arpit's call): the three
   falsifiable stats stay one click away, act III loses a heading and ~300px.
   Replaces the .lab3 card grid — those rules are deleted above, along with the
   #lab .lab3 terminal-listing block that had been silently dead since the
   consolidation moved id="lab" onto the kicker (lesson 10: rules matching 0
   elements get removed, not left to rot). Component declares its own ink. */
body.p-home .lab-row{margin-top:40px;padding-top:24px;border-top:1px solid var(--border-strong);font-family:var(--mono);font-size:12.5px;letter-spacing:.02em;line-height:1.9;color:var(--text-muted)}
body.p-home .lab-row .lr-k{letter-spacing:.02em;font-size:11px;color:var(--acc-amber)}
body.p-home .lab-row a{color:var(--text-body);text-decoration:none;border-bottom:1px solid var(--border-strong)}
body.p-home .lab-row a:hover{color:var(--acc-violet);border-bottom-color:var(--acc-violet)}
/* ============================================================
   HEADING RANKS (2026-08-30) — Arpit's pick: Option C with the
   merge, after the measured diagnosis (h2 rendered at 42/44/48/64
   and h3 at 40/30/26/20/19/14 — rank was unreadable in isolation).
   Four ranks, each with ONE identity; the section address (k-idx)
   merges into the kicker line, so sections are the only headings
   that carry an act address. See DESIGN-SYSTEM-EMBER.md § ranks.
   Declared late so the rank wins over older per-section sizes.
   ============================================================ */
/* R1 — section title: one size, light serif. The close keeps a display license. */
body.p-home main h2{font-size:clamp(32px,3vw,42px);font-weight:300;line-height:1.18}
body.p-home #h-close{font-size:clamp(38px,4vw,56px);line-height:1.1}
/* R2 — subsection lead & item titles: smaller AND semibold (categorical flip) */
body.p-home #h-lead,
body.p-home .thought-title{font-size:22px;font-weight:600;line-height:1.3}
/* R3 — row/label headings: 17px semibold, upright everywhere */
body.p-home .wl-lead .memo h3,
body.p-home .aiwork .memo h3,
body.p-home .contract .col h3{font-size:17px;font-weight:600;font-style:normal;line-height:1.4}
/* the section address — mono, act accent, merged into the kicker line */
body.p-home .k-idx{font-family:var(--mono);font-weight:500;letter-spacing:.08em;margin-right:12px}
body.p-home .k-idx-violet{color:var(--acc-violet)}
body.p-home .k-idx-amber{color:var(--acc-amber)}
body.p-home .k-idx-rose{color:var(--acc-rose)}
/* ============================================================
   CASE SUMMARY FILMS (2026-08-30, Arpit's placement call: ABOVE
   the verdict slip). One narrated summary per case, reusing the
   walkthrough's .vid-frame grammar; attention.js's whole-frame
   click-to-play binds automatically. The section is its own band
   so the film doesn't crowd the slip's cream card.
   ============================================================ */
.vband-film{padding:48px 40px 8px}
.vband-film .vid-case{max-width:1000px;margin:0 auto}
.vband-film .vid-cap-row{display:flex;justify-content:space-between;gap:12px 24px;flex-wrap:wrap;margin-top:12px}
@media (max-width:768px){.vband-film{padding:32px 24px 8px}}
/* live-capture evidence figure (2026-08-30, closes the review's 'no real
   artifact' finding — Arpit's call: the live platform as a longevity receipt,
   framed honestly as today's product, not his screens) */
/* opt OUT of the .measure-c figure breakout (same pattern as .case-hero figure).
   A live-capture receipt reads as evidence at column width. Re-added 2026-08-30
   after css-coverage.py's report-mode restore clobbered a mid-run edit — the
   instrument now refuses to restore over a changed file. */
body[class*="p-case-studies"] .measure-c figure.fig-shot-live{width:100%;max-width:none;margin:40px 0 0;transform:none}
.fig-shot-live{margin:40px 0 0}
.fig-shot-live img{width:100%;height:auto;border-radius:10px;border:1px solid var(--border-strong);display:block}
.fig-shot-live figcaption{margin-top:12px;font-size:13.5px;line-height:1.65;color:var(--text-faint)}
.fig-shot-live figcaption b{color:var(--text-muted);font-weight:500}
/* ============================================================
   REACH-OUT PASS (2026-08-31, from the Reach-Out Gap field review;
   drafts marked for Arpit's strike-through). Every component declares
   its own critical properties (lesson 11).
   ============================================================ */
/* the scene — one cinematic threshold line atop each flagship essay */
.scene{font-family:var(--serif);font-style:italic;font-weight:300;font-size:20px;line-height:1.6;color:var(--text-muted);max-width:56ch;margin:20px 0 32px}
/* 2026-09-10: .ps-line, .contact-channels .book-call, .pass-link (+ its hover
   lift and the transition that served it) and .pass-cta all went with
   direction A. The hover lift in particular was a false affordance once
   Arpit said "keep the pass without the link": it animated on a div that
   could not be clicked. */
/* the lab's public source line (2026-08-31 — repo live, verified 200 before linking) */
.lab-src{font-family:var(--mono),monospace;font-size:12.5px;letter-spacing:.02em;color:var(--text-muted);margin-top:12px}
/* ============================================================
   HERO RECOMPOSITION V1 (2026-08-31, Arpit's pick from two rendered
   options). Three facts absorbed into EXISTING objects — zero new
   hero blocks. Each component declares its own critical properties.
   ============================================================ */
/* the diagnostic gains its asker */
.hd-tag{display:flex;align-items:center;gap:12px}
.hd-face{width:32px;height:32px;border-radius:50%;object-fit:cover;border:1.5px solid var(--accent);flex:0 0 auto}
/* the routing line: two doors, one line; wraps whole-door on mobile */
.hd-route{margin:0;line-height:1.9}
.hd-route a{white-space:nowrap}
/* availability chip: CTA metadata, mono, live-dot */
body.p-home .cta-status{display:inline-flex;align-items:center;gap:8px;font-family:var(--mono),monospace;font-size:11px;letter-spacing:.02em;color:var(--text-faint)}
body.p-home .cta-status i{width:8px;height:8px;border-radius:50%;background:var(--status-positive);flex:0 0 auto}
@media (max-width:700px){body.p-home .cta-status{width:100%;justify-content:flex-start}}
/* route links speak the house CTA grammar (the wrap into .hd-route made them
   standalone arrow-CTAs — the census flags any second dialect) */
.hd-route a{font-family:var(--sans);font-size:11.5px;font-weight:600;letter-spacing:.02em;color:var(--acc-violet)}
/* ============================================================
   THE CHANT (D3, 2026-08-31 — Arpit's pick, paired with the doubt
   ring). Four commandments, one per act, in the act accents; the
   homepage gets the four-column band, every other page one line.
   ============================================================ */
/* The four-commandments chant (Act I-IV) came off the homepage on 2026-09-08 at
   Arpit's request. Its 10 rules went with it — .chant, .chant-in, .cl and the
   four per-act accent colours matched nothing anywhere else on the site. */

/* ============================================================
   H-B HERO (2026-09-01, Arpit's pick): the film is the hero.
   The diagnostic problem-router moved to /patterns, where its
   audience lives; .hd-* rules above were un-scoped from p-home
   for that move. Components declare their own properties.
   ============================================================ */
body.p-home .vid-hero{margin:0}
body.p-home .vid-hero .vid-frame{position:relative;aspect-ratio:16/9;background:var(--surface-card);border:1px solid var(--border-strong);border-radius:12px;overflow:hidden;box-shadow:var(--elev-2)}
body.p-home .vid-hero video{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;cursor:pointer}
body.p-home .vid-hero-k{font-family:var(--mono),monospace;font-size:11.5px;letter-spacing:.02em;color:var(--acc-amber);margin:0 0 12px}
body.p-home .vid-hero-cap{font-family:var(--mono),monospace;font-size:11px;letter-spacing:.04em;line-height:1.7;color:var(--text-faint);margin-top:12px}
body.p-home .vid-hero-cap a{color:var(--acc-amber)}
/* the router card on /patterns keeps its card look, sized to the content column */
/* /patterns hero recomposition (2026-09-01): the claim and the problem-router are the
   two columns of one hero row — the router is the page's front door, not an insert. */
body[class*="p-patterns"] .pat-hero{display:grid;grid-template-columns:minmax(0,7fr) minmax(0,5fr);column-gap:64px;align-items:center}
body[class*="p-patterns"] .pat-diag{max-width:none;margin:0}
body[class*="p-patterns"] .pat-hero-l .hand-note{margin:24px 0 8px}
@media (max-width:960px){body[class*="p-patterns"] .pat-hero{grid-template-columns:1fr;row-gap:32px}}
/* inside a pattern card the global centre-capped-text rule (see the auto-margin
   block above) meets a flex column: auto inline margins shrink each block to
   fit-content and centre it — number and caption flush left, title floating
   centred. A card is a column; everything in it sits flush left. */
body[class*="p-patterns"] .card-p28 :is(p,h2,h3){margin-left:0;margin-right:0}
/* the grid header — the eight cards are the page's substance and get a named section */
body[class*="p-patterns"] .pat-grid-hd{margin:48px 0 24px}
body[class*="p-patterns"] .pat-grid-hd .section-title{margin:0}
/* card index number — the grid reads as a numbered library, not loose tiles */
body[class*="p-patterns"] .card-p28 .pat-n{display:block;font-family:var(--mono,'JetBrains Mono',monospace);font-size:12px;letter-spacing:.12em;color:var(--accent-text,var(--acc-amber));margin-bottom:12px}
/* loop.js follows the grid as its proof artifact, not a peer of the rule */
body[class*="p-patterns"] .xi-patterns-018{margin:8px 0 64px}
/* ============================================================================
   ACT GROUNDS — Arpit's pick from three rendered concepts (2026-09-01, "a").
   The page ran ~9,600px on one ground; each act now sits on a ground cast from
   its own accent, fading back to base so sections hand over quietly.
   ============================================================================ */
body.p-home .receipts,
body.p-home .work{background:linear-gradient(180deg, color-mix(in srgb, var(--act) 7%, var(--surface-page)), var(--surface-page))}
body.p-home .who{background:linear-gradient(180deg, color-mix(in srgb, var(--act) 7%, var(--surface-page)), var(--surface-page))}
body.p-home .aiwork{background:linear-gradient(180deg, color-mix(in srgb, var(--act) 7%, var(--surface-page)), var(--surface-page))}
body.p-home .voices,
body.p-home .thoughts{background:linear-gradient(180deg, color-mix(in srgb, var(--act) 7%, var(--surface-page)), var(--surface-page))}
/* Act III inverts to paper — the contract is a document, and it reads on the
   site's own cream (the boarding-pass palette). Every token the section's
   components read is redeclared here; accents use the paper-proven darks
   (#7E5A14 amber · #6B3A99 violet, 4.31:1 pass-cta precedent · --cream-red). */
body.p-home .contract{background:var(--surface-page);color:var(--text-body)}
/* the live demo stays a dark instrument ON the paper — it re-declares the dark
   set in full, so the section remap cannot reach inside it (lesson 4/11) */
body.p-home .contract .ccd{background:var(--surface-card);border-color:var(--border-hairline)}
/* Anchored arrivals clear the fixed nav (2026-09-02, Arpit's catch: "How I Lead"
   landed with its heading under the bar). Headings already carried scroll-margin;
   the nav's actual targets are sections and divs, which carried none. */
:is(section,div,aside,article)[id]{scroll-margin-top:96px}
/* /lab recomposition (2026-09-02, first-principles revisit Arpit ordered):
   the four runnable artifacts are the page's answer to "is he really technical?"
   — promoted to a 2×2 grid so the proof is the loudest object on the page. */
@media (min-width:861px){body.p-lab .lab-cards{grid-template-columns:repeat(2,minmax(0,1fr))}}
/* lab/eval: the answer panel stretches to meet the lint panel — the default
   preset's 7 findings ran 3.1× the left column and left ~1,100px of void
   (found by the exploratory sweep; per-element gates cannot see composition) */
body.p-lab-eval .lint-grid{align-items:stretch}
body.p-lab-eval .lint-grid > *:first-child{display:flex;flex-direction:column}
body.p-lab-eval .lint-grid textarea{flex:1 1 auto;min-height:220px}
/* Hub cards → editorial rows (2026-09-02, sweep DEFECT: the 520px card cap
   fixed dead space INSIDE the cards and moved it OUTSIDE — 43% right void at
   1024 and two right endings on /writing. The homepage writing section already
   solved this class: full-width ledger rows. Same grammar here.) */
:is(body[class*="p-writing"],body[class*="p-resources"]) :is(.card-p32,.card-p28){max-width:none;display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);column-gap:48px;grid-template-rows:auto auto 1fr;align-items:start;background:none;border:none;border-radius:0;border-bottom:1px solid var(--border-strong);padding:24px 0}
:is(body[class*="p-writing"],body[class*="p-resources"]) :is(.card-p32,.card-p28) > .eyebrow{grid-column:1;grid-row:1}
:is(body[class*="p-writing"],body[class*="p-resources"]) :is(.card-p32,.card-p28) > .card-title{grid-column:1;grid-row:2;margin:8px 0 0}
:is(body[class*="p-writing"],body[class*="p-resources"]) :is(.card-p32,.card-p28) > p{grid-column:2;grid-row:1/span 3}
:is(body[class*="p-writing"],body[class*="p-resources"]) :is(.card-p32,.card-p28) > [class*="lbl-cap"]{grid-column:1;grid-row:3;align-self:end;margin-top:16px}
/* the global centre-capped-text rule meets a grid area: flush left, always (patterns precedent) */
:is(body[class*="p-writing"],body[class*="p-resources"]) :is(.card-p32,.card-p28) :is(p,h2,h3){margin-left:0;margin-right:0}
@media (max-width:768px){:is(body[class*="p-writing"],body[class*="p-resources"]) :is(.card-p32,.card-p28){grid-template-columns:1fr;grid-template-rows:auto}
:is(body[class*="p-writing"],body[class*="p-resources"]) :is(.card-p32,.card-p28) > :is(.eyebrow,.card-title,p,[class*="lbl-cap"]){grid-column:1;grid-row:auto}
:is(body[class*="p-writing"],body[class*="p-resources"]) :is(.card-p32,.card-p28) > p{margin-top:12px}}
/* D3 (2026-09-02 sweep): fintech and vc break their recon out to 1040px and then
   centre a 520px card in it — 260px of empty stage each side, every state. The
   stage only earns the breakout where its content fills it (ptc's grid does);
   here the demo stays in the reading column. */
:is(body.p-case-studies-fintech,body.p-case-studies-vc-diligence) .recon{width:100%;max-width:none;margin-left:0;margin-right:0;transform:none}
/* ============================================================================
   VOICES — the anchors band (2026-09-02, Arpit's pick: TWO anchors).
   The act was "lost in the scroll": a wall of same-size quote cards. The two
   anchors — the client's CTO (authority) and the tech lead who sat beside him
   for five years (specificity) — now hold a full-bleed rose field, the act IV
   counterpart of act III's cream contract band; the chorus sits beneath.
   ============================================================================ */ /* captions share the band foot (lesson 7) */

/* orgos: four vitals in a 3-col grid left the fourth alone on row 2 with a
   two-cell void (2026-09-02 sweep). Four vitals read as a 2x2. */
body[class*="p-case-studies"] .case-vitals:has(> div:nth-child(4):last-child){grid-template-columns:repeat(2,minmax(0,1fr))}
body[class*="p-case-studies"] .case-vitals:has(> div:nth-child(4):last-child) > div{border-right:1px solid var(--border-strong)}
body[class*="p-case-studies"] .case-vitals:has(> div:nth-child(4):last-child) > div:nth-child(2n){border-right:0}
body[class*="p-case-studies"] .case-vitals:has(> div:nth-child(4):last-child) > div:nth-child(n+3){border-top:1px solid var(--border-strong)}
@media (max-width:640px){body[class*="p-case-studies"] .case-vitals:has(> div:nth-child(4):last-child){grid-template-columns:1fr}
body[class*="p-case-studies"] .case-vitals:has(> div:nth-child(4):last-child) > div{border-right:0}}
/* voices provenance line (2026-09-03, Arpit): the quotes are excerpts and say
   so — the unedited set lives at the third-party record. Quiet house grammar,
   not a competing CTA: act IV's one job is still the contact. */
body.p-home .qt-src{margin-top:20px;font-family:var(--sans);font-size:13.5px;color:var(--text-faint)}
body.p-home .qt-src a{font-family:var(--ff-label);font-weight:600;font-size:11.5px;letter-spacing:.02em;color:var(--acc-violet);text-decoration:underline;text-underline-offset:3px;margin-left:8px}
/* ============================================================
   LONG-FORM READING  (2026-09-06)

   Arpit: "the current website is difficult to read for long." Measured on
   /case-studies/adtech — 3,623 words, 22 paragraphs over 160 characters — and
   the cause was not what it looked like at first glance.

   THE MEASURE, and this is the whole problem. `.measure-c` on a case page
   carries FOUR competing max-width declarations, applied in this order:

     styles.css:504   max-width:var(--measure)   (62ch)
     ember.css:597    max-width:1100px
     ember.css:894    max-width:704px
     ember.css:1257   max-width:680px            <- wins

   and the cap that actually governs reading — `max-width:66ch` on the
   paragraphs themselves (ember.css:599 and :630) — was switched OFF by a later
   `max-width:none` (ember.css:895). So body copy runs the container's full
   632px, which in Source Sans 3 at 16px is EIGHTY characters per line, with one
   paragraph at 91. The comfortable range is 45-75. At 80ch the eye loses the
   start of the next line on the return sweep, and it does that a few hundred
   times over 3,600 words.

   Measured for comparison: /writing and /patterns both sit at 62ch and are
   fine. This is a case-page defect, not a site-wide one.

   Two corrections I made to my own reading of this, recorded because both were
   instrument errors rather than site defects:
     · the first sample said "21px weight 300, line-height 1.4" — that is
       .t-standfirst, the LEAD paragraph, one of 22. Real body copy is .t-body
       at 16px/400/1.8, and 400 with 1.8 leading is correct.
     · the first characters-per-line figure said 28-56 and was nonsense: it
       divided character count by getClientRects().length, and a Range over a
       paragraph containing links returns one rect per inline FRAGMENT per line,
       not one per line. Measuring width in `ch` needs no line counting at all.

   HALATION. Body ink is #F5EDE6 on #120B14 = 16.7:1, near the maximum possible.
   On a dark ground light text blooms — light scatters in the eye — and very
   high contrast makes long passages appear to vibrate. 12-14:1 is the range for
   sustained dark reading. Softened to #E2DBD3 (14.1:1), scoped to long-form
   body only rather than the --ink token, so nothing else on the site moves.

   SIZE. 16px is the web's floor, not a long-form size; 17px costs nothing here
   because the measure is being capped in the same change.
   ============================================================ */
body[class*="p-case-studies"] .measure-c :is(p,li,blockquote){max-width:68ch}
body[class*="p-case-studies"] .measure-c :is(h2,h3){max-width:34ch}
:is(.t-body,.u-body){font-size:var(--fs-body);color:var(--text-body)}
/* ============================================================
   WCAG 1.4.10 REFLOW at 320px, and 2.5.8 TARGET SIZE
   (found by tools/wcag-reflow-target-check.py, cherry-picked 2026-09-06)

   320px is the actual requirement — it is 1280px at 400% zoom, which is how a
   low-vision reader reads this site. Every other gate here starts at 390, so
   this had never been measured on ember.

   Six pages scrolled sideways, and the causes were measured one page at a time
   rather than assumed to be the same:

     patterns/ai-failure-states  +42px   div.xi-*     min-width:auto
     case-studies/adtech         +27px   tr/th        white-space:nowrap
                                         div.vslip    326px in a 320px viewport
     patterns/confidence-scores  +21px   div.xi-*     min-width:auto
     lab/index                   +20px   div.dsg-card min-width:auto
     writing/failure-states      +17px   a.xi-*       min-width:auto
     patterns/index               +4px   div.pat-hero-l min-width:auto

   min-width:auto is the default on a flex or grid child and it means "never go
   below your min-content width", so a child refuses to shrink and takes the
   page with it. min-width:0 lets the track shrink to the space it actually has.
   ============================================================ */
@media (max-width:420px){/* let flex and grid children shrink to the space they have */
  main :is([class*="xi-"],.dsg-card,.dsg-grid,.pat-hero-l,
    .pat-hero-r,.lab-wrap,.measure-c,.wrap) > *{min-width:0}
main :is([class*="xi-"],.dsg-card,.pat-hero-l,.pat-hero-r){min-width:0}
/* a short before/after cell wraps rather than taking the page sideways. An
     inner scroll would satisfy 1.4.10 (tables are its two-dimensional
     exception) but would then be flagged as content behind a gesture, and
     trading one real defect for another is not a fix. */
  main :is(th,td){white-space:normal}
/* an artifact is capped against the VIEWPORT, not against a percentage of a
     parent that is itself too wide — .vslip measured 326px inside 320px with
     max-width:none, and a percentage cannot save a child whose parent is the
     thing overflowing. */
  :is(.vslip,.vplate,.vplate-wrap,.pass,.lug,figure,pre,table){max-width:calc(100vw - 48px)}
/* width:auto belongs to everything here EXCEPT a case-page figure. Those carry
     the house breakout width:min(1040px, 100vw - 48px), which already guarantees
     they fit; auto let one of them fall back to its share of a two-column track
     and it halved — 171px at 390 for an SVG with a 1180-unit viewBox, a scale of
     0.145, which painted fintech's 11px annotations at 1.6px. Fifty-four text
     nodes on that page went from readable to invisible, and contrast-audit is
     what caught it: NO-INK plus 54 UNMEASURABLE at 390, all under 2.5px. Same
     failure mode as the 2026-08-17 note above, which is why the min() width is
     never given up. */
  :is(.vslip,.vplate,.vplate-wrap,.pass,.lug,pre,table){width:auto}
main figure:not(.measure-c figure){width:auto}}
/* SC 2.5.8: a crowded target must be at least 24px on the block axis. Fifteen
   were under it — the 404's three reclaim links (49x21, 50x21, 68x21) and the
   product-mockup demo buttons (.rxa-why 70x18, .rxf-explain 94x18). Padding is
   on the block axis only, so nothing moves horizontally. This repo's notes
   assumed 44px, which is SC 2.5.5 (AAA) and a different requirement — the AA
   line at 24px had never been checked. */
:is(.inline-links a,.divert a,.btn-row a,
  .wr-more a,p.hand a,.hd-route a,.contract-links a,.scr-receipt a,.lab-row a):not(.cta){padding-block:4px;display:inline-block}
:is(button.rxa-why,button.rxf-explain,button.rxa-logged,
  .rx2-btn,.demo-btn,.ccd-q){min-height:24px;padding-block:4px}
/* The last reflow failure: div.pat-hero is a grid whose container is 272px at
   320px viewport, but whose grid-template-columns computed to 300.266px — a
   minmax() floor wider than the space available, which is the standard
   auto-fit/minmax overflow. minmax(0,1fr) lets the track shrink to what there
   actually is. */
@media (max-width:420px){.pat-hero{grid-template-columns:minmax(0,1fr)}
.pat-hero > *{min-width:0;max-width:100%}}
/* The loop diagram was unreachable on a phone, and it predates today's work:
   tools/reachability-check.py found 27px of h-scroll inside FIGURE.loopfig at
   390px on /case-studies/adtech and /case-studies/talon. Measured, the figure
   renders 147px wide inside a 294px section — exactly half — so a four-step
   flow with 140px steps was being asked to live in half a phone screen, and the
   remainder sat behind a sideways gesture inside its own box. Its .loop-steps
   already wraps; it simply had no room to wrap into. Full width below the
   two-column breakpoint, and the inner scroll goes with it. */
@media (max-width:700px){.loopfig{width:100%;max-width:100%;overflow-x:visible}
.loopfig .loop-steps{flex-wrap:wrap;min-width:0}
.loopfig .loop-steps > *{min-width:0;max-width:100%}}
/* ============================================================================
   WIREFRAMES ON A PHONE (2026-09-12, found by walking every page at 390)
   The four .card-wire mock UIs spend 80px of a 342px card on padding, leaving
   260px of content. patterns/ai-failure-states then split that into two 120px
   columns, so its two mock buttons held 45px and 43px of text in 30px boxes and
   read "Searc Web" and "Ask Expe"; its answer line ran 57px wide in 54px, and
   confidence-scores' "Moderate" chip 47px in 40px. Measured, not inferred.

   The min-width:0 rule above is what LETS a leaf shrink below its own text, and
   it stays: it exists to stop a grid track taking the whole page sideways, which
   is the worse defect. So this stops the squeeze instead of fighting it — the
   card gives its padding back, the two-panel comparison stacks, and a mock row
   wraps before it crushes a label. A row only wraps when it must, so nothing
   moves where the space was already there.
   Verified after: zero runs of text wider than their own box at 390, 480 and
   560, all four wireframes; nothing changes at 561px and up. */
@media (max-width:560px){main .card-wire{padding:20px}
/* the before/after comparison becomes two full-width panels */
  main .card-wire > div{flex-direction:column}
/* inert unless the element is a flex row; then it wraps rather than squeeze */
  main .card-wire :is([class*="xi-"],.row-ic){flex-wrap:wrap}}
/* Same class, found by the same sweep: the four writing essays end on a two-up
   "Continue exploring" pair, 1fr 1fr with a 20px gap, which is 161px a column at
   390. "The Explainability Layer" needs 146px of min-content in a 127px title box,
   so on writing/failure-states the card's own heading ran past its card. The other
   three pages carry shorter titles and are one long word from the same defect, so
   the pair stacks rather than each title being taught to break. Every other card
   grid on the site (patterns, resources, writing index) is already single-column
   at this width — checked, all eight/three/four of them — so this rule is scoped
   to the essay pages and is a no-op anywhere it also matches. */
@media (max-width:560px){body[class*="p-writing"] main
    [class*="xi-"]:has(> a > .card-title){grid-template-columns:1fr}}
/* ============================================================
   LONG-FORM READING, part two  (2026-09-07)

   Measured on /case-studies/adtech after the measure cap landed.

   1 · THE PHONE MEASURE WAS 35ch. Capping the desktop measure at 68ch fixed
       one end and left the other: at 390px the column is 294px, which at 17px
       Source Sans 3 is thirty-five characters — as far below the 45-75 range as
       80 was above it, and the same fatigue from the opposite direction (a
       return sweep every four or five words). At 390px you cannot have both
       17px and 45ch, so the phone takes 16px and the page gutter narrows from
       24px to 16px: 358px of column, ~45ch. Desktop keeps 17px and 68ch.

   2 · PARAGRAPH SPACING WAS SMALLER THAN LINE SPACING — 20px between
       paragraphs against a 31px line box. That is the wrong way round: if the
       gap between paragraphs is tighter than the gap between lines, the eye
       cannot see where one paragraph ends, and a page of prose reads as one
       slab. Paragraph spacing is now 32px, just over one line box.

   3 · TRACKING WAS NEGATIVE (-0.048px) on light-on-dark text. Light text on a
       dark ground blooms — light scatters in the eye and strokes thicken — so
       the counters need MORE air, not less. Now +0.01em on body copy only;
       headings keep their tighter fit because display sizes do not bloom the
       same way.

   4 · text-wrap:pretty for orphan control. The browser can now avoid a
       one-word last line by itself, which at any measure is free.

   5 · hyphens:auto BELOW the two-column breakpoint only. At 68ch the rag is
       fine and hyphenation would be noise; at 45ch on a phone the rag is severe
       enough that evening it out is worth the hyphens.
   ============================================================ */
:is(.t-body,.u-body,.measure-c p,.measure-t p){letter-spacing:.01em;text-wrap:pretty}
:is(.t-body,.u-body) + :is(.t-body,.u-body),
.measure-c :is(p,li) + :is(p,li){margin-top:32px}
@media (max-width:430px){/* hyphens:auto with LIMITS. Unconstrained it put five hyphens in fifteen lines
     at 42ch — "dis-covered", "indepen-dent", "conversa-tion", "engi-neering",
     "partner-ship" — which evens the rag but interrupts the read every third
     line. hyphenate-limit-chars 8 4 3 means: only words of 8+ characters, never
     fewer than 4 before the break or 3 after, and at most two in a row. */
  :is(.t-body,.u-body){font-size:16px;hyphens:auto;-webkit-hyphenate-limit-before:4;-webkit-hyphenate-limit-after:3;hyphenate-limit-chars:8 4 3;hyphenate-limit-lines:2}
/* ZERO, not 16. The gutter was double-stacked: main.section already pads 24px
     each side, and .measure-c added its own on top — 80px of a 390px screen
     spent twice on the same margin, which is where the missing characters were.
     main keeps the gutter; the inner container stops repeating it. */
  :is(.measure-c,.measure-t){padding-left:0;padding-right:0}}
/* At 320-360px the measure is physically constrained: 45ch at 16px needs a
   333px column, and a 320px screen has 272px after a 24px gutter each side. The
   only lever left is the gutter itself, so below 380px it narrows to 16px —
   worth about three characters a line, which at 33ch is not nothing. It does not
   go tighter than 16px, because a gutter below that reads as text touching the
   bezel. 33-38ch at these widths is the honest floor, not a defect. */
@media (max-width:380px){main.section{padding-left:16px;padding-right:16px}}
/* ============================================================
   THE LEAD-IN BECOMES A SUB-HEAD  (2026-09-07)

   Arpit asked for more sub-heads on the long case studies. Measured first, and
   the answer was not to write any: the chunks ALREADY EXIST. Every paragraph in
   the long runs opens with a <strong> lead-in in his own words —

     "The structural play: a media agency became the market's aggregator."
     "The four systems that made the claim hold"
     "One design system made six products one platform."
     "Then the design system learned to build itself."

   — and /case-studies/adtech carries NINE h2 and ZERO h3. So the document was
   chunked and the chunks were invisible: same size, same colour, inline at the
   start of a paragraph, and absent from the outline entirely. Writing new
   sub-heads would have duplicated his sentences in worse prose.

   33 such lead-ins exist across six case pages. 27 are a complete clause and
   are now promoted — role="heading" aria-level="3" for the outline, .lead-in
   for the eye. The other five are single words (Plato, Ada, Atlas, PlanIt) and
   stay INLINE: as blocks they would orphan the em-dash that follows them onto
   the next line.

   Not a size jump — brightness and position. The body ink is softened to
   #E2DBD3 for long reading, so a lead-in at full --ink already separates
   without needing to be bigger, and a bigger sub-head every 70 words would
   fight the h2s above it.
   ============================================================ */
.t-body .lead-in,
.u-body .lead-in{display:block;color:var(--text-body);letter-spacing:.005em;margin-bottom:8px}
/* a sub-head wants more air above it than a paragraph does */
:is(.t-body,.u-body):has(> .lead-in:first-child){margin-top:40px}
/* ============================================================================
   ARTALT — the diagrams, typeset, for every width that cannot render them
   ----------------------------------------------------------------------------
   MEASURED, 2026-09-07: the case-page diagrams are authored in a 1180-unit
   viewBox with 11-unit labels, and the figure is width:min(1040px, 100vw-48px).
   So the rendered type is 2.9-4.3px at 390, 6.1-7.9px at 768, and only reaches
   9px around a 1013px viewport. All 24 art SVGs on the site do this; 11 of 13
   on the case pages had 100% of their text under 9px at 390.
   No CSS can fix that. The type is small RELATIVE TO ITS OWN PANEL — a 11-unit
   label inside a 470-unit card — so even giving one panel the whole phone gives
   8px, and the SVGs are flat: absolute x/y on every element, no groups, no ids,
   and <text> does not wrap. There is nothing to reflow. Bumping the font-size in
   user units overflows every rect it sits in.
   And the <desc> these SVGs carry is not a substitute: it describes the PICTURE
   ("A wide left-to-right diagram on cream paper..."), which reads as alt text,
   not as copy.
   So below 1000px the plate is replaced by the same diagram typeset as HTML,
   where the text is real text at 14-21px and reflows. Every string in those
   blocks is copied verbatim from that diagram's own <text> nodes.
   It keeps the paper identity: .fig-paper already re-scopes --bg-card to cream
   and --amber to the paper gold (#7E5A14, 5.62:1 on cream), so the typeset
   version inherits the plate's palette rather than inventing one — but every
   colour below is DECLARED, because those same tokens hold dark-ground values
   one selector away.
   Rolled out on fintech first (4 diagrams). The other 20 still show the
   unreadable plate below 1000px; same treatment, one diagram at a time.
   ============================================================================ */
.artalt{display:none}
/* COLOURS ARE DECLARED, AND THEY ARE THE PLATE'S OWN. First attempt used
   var(--bg-card) on the assumption that .fig-paper re-scopes it to cream. It
   does not — that selector re-scopes only --goldA/--gold — so the block painted
   on #241800 dark purple with #2C2620 ink on it, and the headline and every
   .artalt-t were invisible. Rendered and looked at it, which is the only reason
   I saw it. These values are read out of the SVG itself (fill="#F4ECDA" ground,
   #EEE4CE cards, #2C2620 ink) and every pair below is computed, not assumed:
     #2C2620 on #F4ECDA 12.71:1 · on #EEE4CE 11.83:1
     #463E33 (detail)   8.94:1 · 8.32:1        #5A3A1A (prevents) 8.69:1 · 8.09:1
     #7A5410 (eyebrow)  5.75:1 · 5.36:1        #8A3A1C (abstain)  6.61:1 · 6.15:1
     #5A4A2A (cost)     7.30:1 · 6.79:1
   The plate's own accent, #C0512B, is NOT reused here: it measures 4.01:1 on its
   own paper and 3.73:1 on its cards.
   2026-09-12, CHASED AND CLOSED: that was recorded as "a real finding about the
   SVGs themselves". It is not one any more, and it is worth saying why so nobody
   spends another afternoon on it. Graded all 410 <text> runs inside the 24
   drawings against the shape each one actually sits on: ZERO now compute to
   #C0512B. All four <text fill="#C0512B"> had since been given an inline
   style="fill:…" (#76321A, #D97856), and in SVG a style attribute beats a
   presentation attribute — so the fill attributes are dead weight, not live ink.
   Where #C0512B survives is strokes and shape fills: arrows, connectors, rules,
   node outlines, 56 of them. For a graphical object WCAG 1.4.11 asks 3:1, and
   4.01:1 and 3.73:1 both clear it. Nothing to fix.
   (Two readings did come back red and both were the probe, not the page: a
   <path fill> whose BOUNDING BOX contains a label is not the ground painted
   behind it — that gave exactly 1.00:1 on /process, whose real pair is #D4A85E
   on #0A0A0A at 9.01:1 — and a label with no host shape fell through to the
   svg's transparent background and got graded against black, where the true
   pair is #494338 on #F4ECDA at 8.33:1.)
   What IS live in these drawings is the SIZE of that text, which no gate had an
   opinion about until tools/svg-text-size-check.py. See its docstring. */
/* ----------------------------------------------------------------------------
   2026-09-12: 999px -> 1439px. THE DRAWING IS SHOWN ONLY WHERE IT CAN BE READ.
   The note above says "no CSS can fix that" and it is right about the font size.
   What it never measured is how far the drawing itself is downscaled. These are
   1180- and 1280-unit viewBoxes rendered at 976-1120px, so the label a reader
   meets is 0.65-0.88 of the authored size. Measured across all 410 labels
   (tools/svg-text-size-check.py): 8.13px at 1024, and only 11.35-12.23px at 1440.
   Every one of the 24 was under the 12.5px floor at every width it was shown.
   So this extends the rule /process already applies (styles.css:396 — "an
   unreadable diagram is worse than no diagram") with a measured threshold rather
   than a round number. 1440 is the ceiling on purpose: it is the widest width
   this site is designed and QA'd at, and inventing new behaviour past it would be
   designing for a screen nobody has tested.
   WHAT CLEARS AT 1440, with the figures widened below: the ten patterns and
   /process drawings whose bottom tier is 13-14u, and the six case-study drawings
   whose bottom tier is 11-13u. Sixteen of twenty-four.
   WHAT STAYS TYPESET AT EVERY WIDTH: the eight whose bottom tier is 10-12u —
   reversibility-safe-to-act, fintech-3, vc-diligence-1 and -2, adtech-1 and -2,
   o2-1, ptc-3. A 10-unit label needs the drawing upscaled 1.3x to reach 13px,
   which is a 1534-1664px figure and a 1582-1712px viewport. Raising those labels
   to 12.5u would bring all eight back at 1440; that is an artwork change and it
   has not been made.
   Either way nobody loses the content: the typeset block is real text at 14-21px
   that reflows, and every string in it is copied verbatim from that diagram's own
   <text> nodes.
   ---------------------------------------------------------------------------- */
@media (max-width:1439px){/* SCOPED TO THE ONES THAT HAVE A REPLACEMENT. The first version hid every
     .art-svg below 1000px while only fintech carried a typeset rendering — so
     adtech, o2, orgos, ptc, vc-diligence and eleven pattern pages showed NOTHING
     at all on a phone. Found because artifact-legibility-check suddenly measured
     0 text runs at 390 where it should have measured dozens; an instrument going
     quiet is a reading to chase, not to accept. */
  .art-svg:has(+ .artalt){display:none}
.art-svg + .artalt{display:grid}
/* /process hides its poster outright below 1040px (styles.css:376) — so a phone
     reader got NOTHING there, not even the unreadable version. The figure comes
     back when it holds a typeset rendering, with the poster's own breakout
     (width:100% + 300px, margin-left:-150px) neutralised: that pulls 150px into
     each margin, which is right for a 1280-unit drawing and wrong for a column
     of text. */
  .process-fig:has(> .artalt){display:block;width:100%;margin-left:0;max-width:none}
/* The plate's shadow is for a drawn artefact, not a text block — but its
     transform is LOAD-BEARING, not decoration: the house breakout is
     margin-left:50% + translateX(-50%), so `transform:none` here dropped the
     translate and shoved every figure half a parent-width to the right. 768px
     viewport, figure at 384..1104, 336px of horizontal scroll. Keep the
     translate, drop only the filter. */
  .fig-paper:has(> .artalt){transform:translateX(-50%);filter:none}}
/* ----------------------------------------------------------------------------
   THE COMPONENT'S OWN STYLING IS NOT WIDTH-GATED, and that is a fix, not a tidy-up.
   Everything below used to sit inside the media query above. The moment eight
   drawings were made to keep their typeset block at >=1440px, those blocks
   rendered with NONE of this: raw numbered lists in white-ish text straight on the
   dark page, no cream panel, no cards, no hierarchy. Rendered it and looked, which
   is the only reason I saw it — the same way the var(--bg-card) mistake recorded
   above was caught.
   A component that is displayed at some width must be PAINTED at every width it can
   be displayed at. Only the three rules left in the query above are genuinely
   width-specific: the drawing's display toggle, and the two figure containers whose
   breakout has to be neutralised when they hold a text block instead of a drawing.
   Harmless while .artalt is display:none, which is its default (line ~3051).
   ---------------------------------------------------------------------------- */
  /* GRID GAP, not `> * + * {margin-top}`. The margin version did not land: every
     part below sets `margin:0` and those rules come later, so they won every
     cascade and the measured gap between group-level siblings was 0 at 390 AND
     768 — the gate and its branches read as if they were inside the "Score"
     card. A grid gap cannot be overridden by a child's margin.
     24px between GROUPS, 16px between items inside a set: without the two being
     different the hierarchy flattens. */
  .artalt{/* text-align IS DECLARED. The pattern pages centre their figure, so the block
       inherited centring there and rendered every card centre-aligned while the
       case pages looked correct — the same component in two shapes. Third time
       today that leaning on an inherited property cost a defect. *//* display is NOT set here. It was, and moving this rule out of the media query
       took `display:grid` with it, overriding the .artalt{display:none} default and
       showing every typeset block next to its own drawing on six pages. Paint
       belongs at every width; the decision to SHOW belongs only where it is made. */gap:24px;background:var(--surface-card);color:var(--text-primary);text-align:left;border:1px solid var(--border-hairline);border-radius:var(--radius-2);padding:24px}
.artalt-k{margin:0;font-family:var(--ff-label,var(--ff-mono));font-size:var(--fs-eyebrow);font-weight:600;letter-spacing:.02em;line-height:1.4;color:var(--accent-fill)}
/* A STANDFIRST IS NOT AN EYEBROW. The pattern diagrams put a full sentence
     under their title ("One score, one action — a number never reaches the screen
     alone.") where the case diagrams put a two-word kicker. Both were landing on
     .artalt-k, so that sentence rendered uppercase and tracked at 12px — the same
     class doing two jobs, which is how one component comes to look different per
     page. */
  .artalt-sub{margin:0;font-size:var(--fs-ui);line-height:1.5;color:var(--text-muted);max-width:60ch}
/* a chip row inside a card is a continuation of its detail, not a new block */
  .artalt-set > li > .artalt-chips{margin-top:8px}
.artalt-h{margin:0;font-family:var(--serif,Georgia,serif);font-size:var(--fs-lead);font-weight:400;line-height:1.25;color:var(--text-primary)}
.artalt-set{margin:0;padding:0;list-style:none;display:grid;gap:16px}
.artalt-set > li{margin:0;background:var(--surface-sunken);border-left:2px solid var(--accent-fill);padding:16px}
.artalt-n{margin:0 0 8px;font-family:var(--ff-label,var(--ff-mono));font-size:var(--fs-eyebrow);font-weight:600;letter-spacing:.02em;line-height:1.4;color:var(--accent-fill)}
.artalt-t{margin:0;font-size:var(--fs-body);font-weight:600;line-height:1.4;color:var(--text-primary)}
.artalt-d{margin:8px 0 0;font-size:var(--fs-ui);line-height:1.5;color:var(--text-muted)}
.artalt-p{margin:8px 0 0;font-size:var(--fs-caption);line-height:1.5;font-style:italic;color:#5A3A1A}
/* ONLY a set item carries a fill. Everything else sits on the paper and is
     separated by a rule — when the gate, the branches and the cards all shared
     #EEE4CE there were no card boundaries left to read. */
  :is(.artalt-bar,.artalt-hub,.artalt-gate){margin:0;font-size:var(--fs-ui);line-height:1.5;color:var(--text-primary);background:none}
.artalt-hub{background:var(--surface-sunken);padding:12px 16px;border-left:2px solid var(--accent-fill)}
.artalt-gate{padding:12px 0 12px 16px;border-left:2px solid var(--status-negative);border-top:1px solid var(--border-hairline);border-bottom:1px solid var(--border-hairline)}
.artalt-bar{padding:16px 0 0;border-top:1px solid var(--border-hairline)}
/* the branch under a gate is nested, and reads as nested */
  .artalt-set--branch{margin-left:16px}
.artalt-set--branch > li{background:none;border-left:2px solid var(--border-hairline);padding:0 0 0 16px}
.artalt-cost{display:block;margin-top:8px;font-family:var(--ff-label,var(--ff-mono));font-size:var(--fs-eyebrow);letter-spacing:.02em;line-height:1.4;color:var(--text-muted)}
.artalt-factors{margin:0;display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px 16px;align-items:center}
.artalt-factors dt{margin:0;font-size:var(--fs-ui);line-height:1.5;color:var(--text-primary)}
.artalt-factors dd{margin:0;justify-self:end;font-family:var(--ff-label,var(--ff-mono));font-size:var(--fs-ui);line-height:1.5;color:var(--accent-fill)}
.artalt-note{margin:0;font-size:var(--fs-caption);line-height:1.6;color:var(--text-muted)}
/* A CONNECTOR. In the drawing these label an arrow between two panels — small,
     lowercase, and outside every painted box. They are neither a conclusion bar
     nor a note, and flattening them into either loses the fact that the diagram
     was showing a movement. #5A4A2A is 7.30:1 on the paper. */
  .artalt-flow{margin:0;font-size:var(--fs-caption);line-height:1.5;font-style:italic;color:var(--text-muted);padding-left:16px;border-left:2px solid rgba(44,38,32,.22)}
/* dashed read as two or three stray ticks on a 40px-tall line — solid, lighter */
  /* A CHIP ROW. Several one-word boxes in a line (iOS · Android · Windows Phone)
     are one enumeration, not four cards — rendering them as cards made a
     four-item list look like four arguments. */
  .artalt-chips{margin:0;font-family:var(--ff-label,var(--ff-mono));font-size:var(--fs-caption);line-height:1.5;letter-spacing:.04em;color:var(--text-muted)}
/* MEASURED at 768: the cards stopped at 541px, the bar at 473 and the eyebrow
     at 418 inside a 670px column — three different ragged widths and a large
     dead band down the right. Cause was mine: the reading cap added on
     2026-09-06, `body[class*="p-case-studies"] .measure-c :is(p,li,blockquote)
     {max-width:68ch}`, applies to every part of this block, and 68ch resolves
     per font-size (473px at 14px, 541px at 16px, 418px at 12px uppercase) —
     which is exactly the three numbers measured.
     A card is not a reading line, so structure fills the width; only the RUNNING
     PROSE keeps a measure. The selector matches the capping rule's shape and
     adds one class, so it actually wins. */
  body[class*="p-case-studies"] .measure-c .artalt :is(p,li,dt,dd){max-width:none}
body[class*="p-case-studies"] .measure-c .artalt :is(.artalt-d,.artalt-note,.artalt-p){max-width:64ch}
/* 34ch is the site's own heading measure (.measure-c :is(h2,h3)), not a new
     number — and it keeps the headline from being stranded in a 670px column. */
  body[class*="p-case-studies"] .measure-c .artalt .artalt-h{max-width:34ch}
/* THE DRAWINGS COME BACK AT 1440, and the figure widths are arithmetic rather than
   preference: a label clears the floor when 12.5 / labelUnits <= figureWidth /
   viewBoxWidth. Targeted at 13px, not 12.5px, because a first pass computed the
   exact width and sub-pixel layout delivered 12.48px — a floor needs headroom, not
   a knife edge.
     patterns + /process   1280px of figure -> 13u reads 13.0px, 14u reads 14.0px
     case studies          1360px of figure -> 11u reads 12.7px, 13u reads 13.8px
   Scoped with :has(> svg.art-svg) so the shared 1040px breakout — the
   reconstruction plates, .case-vitals, .recon, and the case nav deliberately
   aligned to them (see the note at ~1428) — is left alone. */
@media (min-width:1440px){:is(body[class*="p-patterns"],body.p-process)
    figure:has(> svg.art-svg){--art-w:min(1280px,calc(100vw - 96px))}
body[class*="p-case-studies"]
    .measure-c figure:has(> svg.art-svg){width:min(1360px,calc(100vw - 80px))}
/* patterns/index.html hangs its drawing inside an <a>, not a <figure>, so
     neither --art-w nor the figure rule reaches it. Measured: 1180px and a 0.867
     scale where its siblings got 1231px. Named rather than left to inherit a rule
     that does not match it — the same trap as a per-page .xi- class. */
  body[class*="p-patterns"] a.is-paper:has(> svg.art-svg){width:min(1280px,calc(100vw - 96px));max-width:none;margin-left:calc((100% - min(1280px,calc(100vw - 96px)))/2);margin-right:calc((100% - min(1280px,calc(100vw - 96px)))/2)}}
/* The eight that still cannot clear it stay typeset at every width. Listed by
   drawing, not by page: ptc and fintech and vc-diligence each carry both a drawing
   that clears and one that does not, so a page-level rule would be wrong. */
@media (min-width:1440px){:is(#art-adtech-1,#art-adtech-2,#art-o2-1,#art-ptc-3,
    #art-fintech-3,#art-vc-diligence-1,#art-vc-diligence-2,
    #art-reversibilit-1):has(+ .artalt){display:none}
:is(#art-adtech-1,#art-adtech-2,#art-o2-1,#art-ptc-3,
    #art-fintech-3,#art-vc-diligence-1,#art-vc-diligence-2,
    #art-reversibilit-1) + .artalt{display:grid}
/* AND THE FIGURE GIVES UP THE BREAKOUT, because it is now holding a text block.
     Without this the typeset version inherited the drawing's 1360px band while its
     own lines stay capped at 64ch — 900px of dead space down the right of every
     card. The void is milder but already present at 1024 (976px band, same cap);
     this stops the widened band from making it 384px worse.
     All four declarations together, deliberately: the house breakout is
     margin-left:50% + translateX(-50%), and the note in the query above records
     that `transform:none` ALONE once shoved every figure half a parent-width to
     the right. Dropping the translate is only safe with the margin dropped too. */
  body[class*="p-case-studies"] .measure-c
    figure:has(> :is(#art-adtech-1,#art-adtech-2,#art-o2-1,#art-ptc-3,#art-fintech-3,
    #art-vc-diligence-1,#art-vc-diligence-2)){width:100%;margin-left:0;margin-right:0;transform:none;filter:none}
body[class*="p-patterns"]
    figure:has(> #art-reversibilit-1){--art-w:100%;width:100%;margin-left:0;margin-right:0}}
/* ============================================================================
   THE GLANCE, THE NOMINATION, THE SKIM — 2026-09-08
   Measured first. The homepage is 18.5 phone screens and 2,089 words, but prose
   is only 23% of its height, so "text heavy" was never the defect. Three were:
     · the answer to a recruiter's only question ("what are you, at what level?")
       was set at 12px under a 38px sentence about the reader;
     · the first metric-bearing case row sat at screen 3.2 of 18.5, and the first
       number a visitor met was a client name;
     · seven cases were presented as equals, on a page whose job is to convert.
   ============================================================================ */

/* THE ROLE LINE IS NOT AN EYEBROW. It carries the one thing a 10-second reader
   came for, so it gets its own class rather than a bigger .k — .k is the section
   eyebrow, used a dozen times at 12px, and growing it here would have made one
   component render at two sizes. Tracking comes down as the size goes up, or the
   line gains a wrap it did not need. */
body.p-home .hero .role-line{font-size:15px;letter-spacing:.02em;line-height:1.5;color:var(--acc-copper);max-width:46ch}
@media (max-width:560px){body.p-home .hero .role-line{font-size:14px;letter-spacing:.08em}}
/* TWO NUMBERS IN THE FIRST SCREEN. Both already existed on the page — three
   screens down, on their own case cards. They attach to the client strip that
   was already there, so the glance gets a receipt instead of four bare names.
   --amber on the hero ground, declared, not inherited: the strip's captions are
   --ink-dim and a <span> inside one would have come out muted, which is the
   opposite of the job. (Was .cred until 2026-09-11; the metric survived the
   run-on line it used to sit in.) */
/* THE FILM'S ROUTE IS NOW A CTA, so it speaks the house CTA grammar. It used to
   be an inline link at the end of a caption sentence; when that sentence came off
   on 2026-09-08 the link became the caption's only content and
   cta-grammar-check correctly reported a second grammar — JetBrains Mono 11px,
   no case, 0.4 tracking against the house's Source Sans 3 11.5px uppercase 0.9.
   Nine CTAs, one grammar. */
body.p-home .hero .vid-hero-cap a{font-family:"Source Sans 3",var(--sans);font-size:11.5px;font-weight:600;/* .08em, the house CTA tracking — NOT the .02em the uppercase sweep left here.
     This CTA was the only one of the six set in capitals, so it was the only one
     the sweep touched, and relaxing its tracking with the caps put it 0.7px off
     its five siblings. cta-grammar-check caught it: 5/6 at 0.9px, this one at
     0.2px. Normalised to the majority, which is what the comment below already
     asks for. */letter-spacing:.08em;line-height:1.6;color:var(--acc-violet)}
body.p-home .hero .cred-strip .cred-m{color:var(--acc-amber);font-weight:500;white-space:nowrap}
/* Six in the strip, not four: 4 columns left a 4+2 row with two orphans. Three
   columns give 3+3 — but ONLY above 1000px. Declared without the media query it
   sat later in the file than the existing 2-column (<=1000) and 1-column (<=560)
   rules and beat both, so a phone got three 127px columns. */

/* THE SKIM LAYER for the person section. Arpit's own research is the reason this
   is bold text and not a block sub-head: stage 2 of four reads "titles, bold
   text, and images", 2-5 minutes, no full reading. Each bolded clause is
   verbatim and stays where it was written — nothing moved, nothing rewritten —
   and read in order they are the section's argument. .who p is --mut, so a <b>
   inside it inherits muted and the emphasis inverts; the ink is declared. */
body.p-home .who p .skim{color:var(--text-body);font-weight:600}
/* The same skim layer wherever a long paragraph lives — the errata blocks and
   the patterns band, not just the .who column. Declared per ground because
   .errata p and .patterns p each set their own ink. */
body.p-home :is(.errata,.patterns,.lead,.labrow) p .skim{color:var(--text-body);font-weight:600}
/* The rule that gave the Overruled note's three beats their air came out with
   the note on 2026-09-08 — the one remaining .errata holds a single paragraph, so
   `.errata p + p` matched nothing. Dead rules with a live selector are how a
   stylesheet starts lying about the page. */

/* One lane instead of three, so its head column can hold "ADTECH · NAMED CLIENT"
   on one line instead of breaking after "NAMED". */

/* ============================================================================
   ACT BOUNDARIES, AND THE HERO'S SMALL PRINT — 2026-09-08
   ============================================================================ */

/* AN ACT BOUNDARY WAS ONLY VISIBLE WHERE THE CREAM BAND WAS. Measured: every
   section on the homepage is background:transparent with border-top 0px, so the
   four acts are told apart by their .chap opener alone (serif numeral + mono
   title + rule). That opener is strong once you see it — but arriving at act 04
   from section 03 · 2 there is nothing between them except 92px of padding, and
   Arpit read the two as one section. The one obvious boundary on the whole page
   is /patterns' cream ground, which is an act PEAK, not an act START.
   `:has(.chap)` is the exact discriminator the design system already relies on:
   act openers carry the numeral, sub-sections carry a NN · N address in their
   kicker and must NOT get this rule. So all four acts gain the hairline the page
   already uses everywhere else, and no sub-section does. */
body.p-home main > section:has(.chap){border-top:1px solid var(--border-strong)}
/* the cream act keeps its own edge — a hairline in --border is invisible on it */
body.p-home main > section.pat:has(.chap),
body.p-home main > section#patterns:has(.chap){border-top-color:var(--border-hairline)}
/* ============================================================================
   THE CLIENT STRIP — the hero's proof row (2026-09-11)
   ----------------------------------------------------------------------------
   Replaces .cred, which was a 12.5px monospace run-on line inside .hero-copy
   capped at 600px. Two defects, one content and one composition:

   CONTENT — it was the only place on the homepage that named a client, and it
   named them in the smallest type on the page. Measured against the live page
   with one instrument at 1440: 112 words in the first screen, of which the four
   client names were 31 and set at 12.5px.

   COMPOSITION — capped at 600px inside a 1160px band, so the right 48% of the
   row was empty. My own layout rule calls that a defect, not breathing room:
   whitespace is designed or it is left over.

   So the strip is a ROW OF THE HERO GRID (grid-column 1/-1), not a paragraph in
   the left column. Four clients, four columns, the full width used.

   The rows are SHARED across the four cells (display:contents + explicit
   grid-row) rather than each cell owning a 2-row grid. That is the whole point:
   with per-cell grids the four captions align only where no client name wraps,
   and one wrap at 768px stranded one caption 22px below its neighbour's —
   lesson 7, inner elements in a row must align to ONE ANOTHER. Shared rows make
   that alignment structural instead of coincidental. Measured 1 caption row at
   1024 and 1440, 2 at 768 (a 2x2 grid), 4 at 390 (stacked, which is correct).

   Every property is declared on the component, not inherited: --ff-mono and
   --ink-dim, never --mono/--dim, which exist only on body.p-home and silently
   fall back anywhere else. Leading is 1.4 on the 16px names and 1.65 on the
   11.5px captions — both at or above the floor for their rendered size.
   ========================================================================== */
body.p-home .hero .cred-strip{grid-column:1 / -1;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));grid-template-rows:auto auto;column-gap:32px;row-gap:0;margin-top:clamp(32px,4.4vh,48px);padding-top:24px;border-top:1px solid var(--border-strong)}
body.p-home .hero .cred-strip > div{display:contents}
body.p-home .hero .cred-strip > div > b{grid-row:1;font-family:"Source Sans 3",var(--sans),system-ui;font-size:16px;font-weight:600;letter-spacing:.005em;line-height:1.4;color:var(--text-body)}
body.p-home .hero .cred-strip > div > span{grid-row:2;font-family:var(--ff-mono),ui-monospace,monospace;font-size:11.5px;letter-spacing:.01em;line-height:1.65;color:var(--text-faint);padding-top:8px}
/* two columns: the rows stay shared, so the two captions in a row still align
   when one client name wraps and the one beside it does not */
@media (max-width:900px){body.p-home .hero .cred-strip{grid-template-columns:repeat(2,minmax(0,1fr));grid-template-rows:auto auto auto auto;column-gap:24px}
body.p-home .hero .cred-strip > div:nth-child(-n+2) > b{grid-row:1}
body.p-home .hero .cred-strip > div:nth-child(-n+2) > span{grid-row:2}
body.p-home .hero .cred-strip > div:nth-child(n+3) > b{grid-row:3;padding-top:24px}
body.p-home .hero .cred-strip > div:nth-child(n+3) > span{grid-row:4}}
/* one column: each client is its own two-line block again, so the shared rows
   must be RELEASED — leave them in place and four clients pair into two rows */
@media (max-width:520px){body.p-home .hero .cred-strip{grid-template-columns:minmax(0,1fr);grid-template-rows:none;row-gap:20px;margin-top:clamp(24px,3.6vh,32px)}
body.p-home .hero .cred-strip > div{display:grid}
body.p-home .hero .cred-strip > div > b,
body.p-home .hero .cred-strip > div > span{grid-row:auto}
body.p-home .hero .cred-strip > div:nth-child(n+3) > b{padding-top:0}
body.p-home .hero .cred-strip > div > b{font-size:15px}}
/* ============================================================================
   THE WRITING INDEX — an index that previews (homepage, act 04 · 2)
   ----------------------------------------------------------------------------
   Replaces three stacked cards, each carrying its own excerpt, with a numbered
   index whose hovered or FOCUSED entry writes itself into a panel beside the
   list. Measured: 204 words visible dropped to 123, and the right column gained
   a content role instead of being the leftover half of a capped paragraph.
   The pattern is Codrops' index-with-content-preview.

   NO JAVASCRIPT. /lab publishes "0 runtime deps" and "0 build steps" as
   measured facts, so a hover-preview that needed a listener would have made one
   of them false. The state lives in `:has()`, which this codebase already uses.
   The panels sit INSIDE their own <li> so that below 860px they simply flow
   under their title — the mobile layout is the no-JS, no-:has() layout, and it
   is also the fallback anywhere `:has()` is unsupported.
   ============================================================================ */
body.p-home #thoughts .ixw{--ixl:55%;position:relative;display:grid;grid-template-columns:var(--ixl) 1fr;gap:48px;align-items:start;margin-top:40px;border-top:1px solid var(--border-strong);padding-top:8px}
body.p-home #thoughts .ixl{list-style:none;margin:0;padding:0;grid-column:1}
body.p-home #thoughts .ixl > li{margin:0}
body.p-home #thoughts .ixi{display:grid;grid-template-columns:auto minmax(0,1fr);gap:20px;/* BASELINE — Arpit's call, 2026-09-08, after seeing both rendered. The
     previous comment here argued centre "because a two-line title next to a
     one-line numeral snaps the numeral to the title's FIRST line and strands
     it". Rendered side by side, centre is what strands it: "01" and "03" float
     between their two title lines aligned to neither, and one-line "02" sits
     5.7px below its own title's baseline. First-baseline alignment is what a
     wrapping title should get — the numeral belongs where the reading starts.
     Same call as .chap, so the two numeral components on this page now agree
     instead of one being the odd one out. */align-items:baseline;padding:24px 0;text-decoration:none;border-bottom:1px solid var(--border-hairline);min-height:44px}
body.p-home #thoughts .ixn{font-family:var(--mono);font-size:11px;font-weight:500;letter-spacing:.14em;line-height:1.4;color:var(--text-faint)}
body.p-home #thoughts .ixt{font-family:var(--serif);font-weight:300;font-size:clamp(19px,1.8vw,25px);/* 1.28, not 1.20: these titles wrap to two and three lines, and the floor for
     rendered 18-24px is 1.25. At the clamp's low end (19px) 1.20 was 22.8px. */line-height:1.28;color:var(--text-body)}
/* the panel: one grid cell, all three stacked in it, one shown */
/* The preview is a HOVER affordance, so it is gated on the input device and
   not on width alone: 861-1023px is portrait-tablet territory, where there
   is no hover, and the panel just sat on entry 01 and never answered a tap.
   A touch device at any width gets the in-flow layout instead, where every
   entry already carries its own tag, date and excerpt. */
@media (min-width:861px) and (hover:hover) and (pointer:fine){body.p-home #thoughts .ixp{position:absolute;top:8px;left:calc(var(--ixl) + 24px);right:0;border-left:2px solid var(--acc-rose);padding:4px 0 4px 24px;opacity:0;visibility:hidden}
/* default: the newest piece previews itself, so the panel is never empty */
  body.p-home #thoughts .ixw:not(:hover):not(:focus-within) .ixl > li:first-child .ixp{opacity:1;visibility:visible}
body.p-home #thoughts .ixl > li:hover .ixp,
body.p-home #thoughts .ixl > li:focus-within .ixp{opacity:1;visibility:visible}
body.p-home #thoughts .ixl > li:hover .ixt,
body.p-home #thoughts .ixl > li:focus-within .ixt,
body.p-home #thoughts .ixw:not(:hover):not(:focus-within) .ixl > li:first-child .ixt{color:var(--acc-rose)}
body.p-home #thoughts .ixl > li:hover .ixn,
body.p-home #thoughts .ixl > li:focus-within .ixn,
body.p-home #thoughts .ixw:not(:hover):not(:focus-within) .ixl > li:first-child .ixn{color:var(--acc-rose)}}
/* below 861: no preview mechanic at all — every entry carries its own text,
   which is the layout a keyboard, a screen reader and a phone all get. */
@media (max-width:860px){body.p-home #thoughts .ixw{grid-template-columns:1fr;gap:0}
body.p-home #thoughts .ixi{/* start, not center: below 861 the entry carries its title AND its tag, date
       and excerpt, so it is a tall block and a vertically centred numeral floats
       in the middle of it. On desktop the entry is a title alone, one or two
       lines, where centred is right. The content shape differs, so the alignment
       does. */align-items:start;border-bottom:0;padding:20px 0 8px}
body.p-home #thoughts .ixn{padding-top:8px}
body.p-home #thoughts .ixp{padding:0 0 20px 0;border-bottom:1px solid var(--border-hairline)}}
body.p-home #thoughts .ixg{margin:0 0 12px;font-family:var(--mono);font-size:10.5px;font-weight:500;letter-spacing:.02em;line-height:1.5;color:var(--acc-rose)}
body.p-home #thoughts .ixd{display:block;color:var(--text-faint);letter-spacing:.02em;margin-top:4px}
body.p-home #thoughts .ixx{margin:0;font-size:15px;line-height:1.65;color:var(--text-muted);max-width:46ch}
/* ============================================================================
   THE CATALOGUE SLIP — /writing's Substack list
   ----------------------------------------------------------------------------
   The piece stops being a paragraph and becomes an OBJECT: cream stock on the
   heat, a serif index numeral, the publication date as a stamp, a dashed score
   line. This is not a new visual language — it is the cream artifact set this
   site already owns (boarding pass, the nutrition-label facts card, the paper
   plates), used on writing for the first time. It gives the section a visual
   without a photograph, which is the constraint.
   THE DATE IS THE STAMP, deliberately: a tag would have meant composing a
   taxonomy label for the new piece, and the date is fetched, factual, and tells
   a reader the thing a "recent writing" list actually has to prove. A library
   card is date-stamped anyway.
   Palette is the DS's own cream set, every pair already measured there:
   #221C10 ink ~13:1 · #5D5442 secondary ~5.6:1 · #A93A24 stamp ~4.9:1 on
   #EFE7D2. Never #C2452D (4.1:1, fails small text).
   ============================================================================ */
body.p-writing .slips{list-style:none;margin:32px 0 0;padding:0;/* TWO columns, not four. /writing's own container caps at 900px
     (.xi-writing-004), so four tracks are 207px each and a 20px serif title
     wraps to five lines in 159px of content. Two give 438px. */display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:24px}
@media (max-width:640px){body.p-writing .slips{grid-template-columns:1fr;gap:16px}}
body.p-writing .slip{margin:0}
body.p-writing .slip > a{display:grid;height:100%;background:#EFE7D2;color:#221C10;border-radius:2px;padding:24px 24px 32px;text-decoration:none;box-shadow:0 12px 30px rgba(0,0,0,.4);transition:transform .2s var(--ease-out,ease-out),box-shadow .2s}
/* artifact tilt, DS ceiling is 1.5 degrees */
body.p-writing .slip:nth-child(4n+1) > a{transform:rotate(-1.1deg)}
body.p-writing .slip:nth-child(4n+2) > a{transform:rotate(.6deg)}
body.p-writing .slip:nth-child(4n+3) > a{transform:rotate(-.5deg)}
body.p-writing .slip:nth-child(4n+4) > a{transform:rotate(.9deg)}
body.p-writing .slip > a:hover,
body.p-writing .slip > a:focus-visible{transform:rotate(0deg) translateY(-3px);box-shadow:0 18px 40px rgba(0,0,0,.5)}
/* baseline — the same call Arpit made on .chap and #thoughts .ixi: a big
   numeral beside small text belongs on that text's line. Here a 32px "01"
   sat 7.0px off a 10px date under align-items:center. Third instance of one
   pattern, so this is his decision applied, not a new one. */
body.p-writing .slip-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:16px}
body.p-writing .slip-no{font-family:var(--serif);font-size:32px;font-weight:300;line-height:1;color:#A93A24}
body.p-writing .slip-stamp{font-family:var(--mono);font-size:10px;font-weight:500;letter-spacing:.02em;line-height:1.4;color:#A93A24;border:2px solid #A93A24;border-radius:3px;padding:4px 8px;transform:rotate(-2.2deg);white-space:nowrap}
/* 1.30, not 1.22: the writing index's slip titles wrap to two and three
   lines at 20px, and the floor for rendered 18-24px is 1.25. */
body.p-writing .slip-title{font-family:var(--serif);font-weight:400;font-size:20px;line-height:1.30;color:#221C10}
body.p-writing .slip-rule{display:block;border-top:1px dashed rgba(34,28,16,.42);margin:16px 0}
body.p-writing .slip-x{font-size:13px;line-height:1.6;color:#5D5442}
/* the DS's reduced-motion contract: every tilt and transform comes off */
@media (prefers-reduced-motion:reduce){body.p-writing .slip > a,
body.p-writing .slip > a:hover,
body.p-writing .slip > a:focus-visible,
body.p-writing .slip-stamp{transform:none;transition:none}}
/* ╔══════════════════════════════════════════════════════════════════════════╗
   ║  THE CASE BOARD AND ITS INSTRUMENTS                       2026-09-08     ║
   ╚══════════════════════════════════════════════════════════════════════════╝

   Replaces the .lane / .idx card set. Those seven tiles shared one ground, one
   type scale and a 3px accent edge as their only difference — a set where every
   item carries the same visual weight cannot be triaged, so a reader took the
   first two and assumed the rest. Arpit's words: "they will have the same
   colour in theme and therefore it would be hard to scan and people might
   ignore elements and might just focus on first few."

   Each card now carries a working miniature of that product, built from an
   artefact already in this repository:

     .vg-plan     WALL-E — a brief in, a plan computed, splits settled
     .vg-cite     a screening score with its three sources attached inline
     .vg-dossier  signals clearing a bar, one verdict landing
     .vg-cat      five disconnected platforms folding into one
     .vg-allow    the O2 allowances screen filling to what shipped
     .vg-bus      eight modules on one shared object model, no hierarchy
     .vg-fail     a graceful unknown, and two ways out of it

   Rules that hold for every instrument:

   1. DIEGETIC. It shows the product behaving like itself, never a chart ABOUT
      the product. A bar that shrinks beside "2 wks -> 3 hrs" only restates the
      caption; that was the first version and it read as force-fitted.
   2. NOTHING INVENTED. Every figure and label traces to a named artefact. Where
      a proportion has no denominator in canon there is no meter (O2's Unlimited
      row), and where canon does not say which of five platforms survived, the
      result is unnamed.
   3. THE RESOLVED STATE IS THE DEFAULT. Everything above the motion block is
      the product as it ends up. That is what renders with JavaScript off, and
      what a reduced-motion visitor sees — the pre-animation states exist only
      inside the no-preference block. Motion is the enhancement, never the
      carrier of the information.
   4. PLAY ONCE. instruments.js adds .live at 34% visibility and unobserves that
      card. A view() scroll timeline scrubs back and forth as the reader moves
      up and down; a plan computing and a verdict landing happen once. Cost at
      rest measured 0.00% of wall clock on a phone, against 6.1% when these
      looped.
   5. THE TEXT IS CONTENT, NOT DECORATION. While these were bars they were
      aria-hidden, correctly. They now hold the evidence, so only the graphical
      parts are hidden and the card is a figure with a LINKED TITLE rather than
      one <a> wrapping a dashboard — otherwise a screen reader reads the whole
      panel aloud as the link's name. Note for future audits: contrast-audit
      skips aria-hidden subtrees, so while the instruments were hidden it graded
      40 text nodes on the homepage and reported zero failures. Exposed, it
      grades 342 across three widths.
   6. NINE-PX FLOOR. No label in an instrument goes under 9.5px, and the chip
      rows are auto-fit at 68px because "Onboarding" needs 64 of them.
*/

/* ── the board: one lead card, six under it ────────────────────────────────
   Rows are 1 / 3 / 3 at desktop, 1 / 2 / 2 / 2 at tablet, one column on a
   phone. Measured leftover space in every row at nine widths: 0px. */
body.p-home .caseboard{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:12px;align-items:stretch;margin-top:16px}
body.p-home .bcard{grid-column:span 2}
/* ── one eye level across the row (option D, 2026-09-08) ───────────────────
   Arpit: "$1M per year, 4M+, zero managers, 60% faster … they don't appear at
   the same eye level on desktop." Measured: 58px apart in the same row. The
   cause was structural, not per-card — each instrument is a different height
   and the number came AFTER it, so the number inherited whatever height the
   instrument happened to be.

   The fix is subgrid: the six cards borrow the board's row tracks, so number,
   sector, title and instrument each sit on a shared line. Measured after:
   numbers 0px apart, instruments 0px apart, no dead space inside any
   instrument. It fixes the CLASS — the next title that wraps to three lines
   cannot knock the row out of alignment, because the title track grows for
   every card at once.

   Rejected: stretching the instrument to fill (numbers still 20px apart and
   79px of dead space INSIDE a bordered box) and bottom-aligning the
   instruments (numbers level but instruments 58px apart, and the eye lands on
   empty card-top first). */
@supports (grid-template-rows: subgrid){body.p-home .caseboard{grid-template-rows:auto auto auto auto auto}
body.p-home .bcard--lead{grid-row:1}
body.p-home .caseboard > .range-lbl{grid-row:2}
body.p-home .bcard:not(.bcard--lead){grid-row:span 4;display:grid;grid-template-rows:subgrid;align-content:stretch}
body.p-home .bcard:not(.bcard--lead) .bcard-m{align-self:start}
body.p-home .bcard:not(.bcard--lead) .bcard-s{align-self:start}
body.p-home .bcard:not(.bcard--lead) h3{align-self:start}
body.p-home .bcard:not(.bcard--lead) .vg{align-self:start;margin:16px 0 0}}
/* Without subgrid the cards simply stack in DOM order — number, sector, title,
   instrument — which is still the right reading order, just unaligned. */
body.p-home .bcard--lead{grid-column:1/-1}
/* the range label is a band across the board, not a tile in it — without the
   span it took two columns and pushed the six cards into 2/1/3/1 rows */
body.p-home .caseboard > .range-lbl{grid-column:1/-1;margin:24px 0 2px}
@media (max-width:1000px){body.p-home .bcard{grid-column:span 3}
body.p-home .bcard.bcard--lead{grid-column:1/-1}}
@media (max-width:660px){body.p-home .caseboard{grid-template-columns:minmax(0,1fr)}
body.p-home .bcard,
body.p-home .bcard.bcard--lead{grid-column:span 1}}
/* ── the card ─────────────────────────────────────────────────────────────── */
.bcard{position:relative;display:block;padding:20px 24px 24px;border:1px solid var(--border-strong);border-radius:var(--radius-2);background:linear-gradient(180deg,color-mix(in oklab,var(--a) 9%,var(--surface-sunken)),var(--surface-sunken));transition:border-color .2s,transform .2s}
.bcard:hover{border-color:color-mix(in oklab,var(--a) 55%,transparent);transform:translateY(-2px)}
.bcard:has(.bcard-go:focus-visible){outline:2px solid var(--a);outline-offset:3px}
.bcard-go{color:inherit;text-decoration:none}
.bcard-go:focus-visible{outline:none}
/* the title's link stretches over the whole card, so the card clicks but the
   link's accessible name is just the title */
.bcard-go::after{content:"";position:absolute;inset:0;border-radius:inherit;z-index:1}
.bcard .vg{position:relative;z-index:0;margin-bottom:16px}
.bcard--lead .vg{margin-bottom:0}
/* the lead card uses its WIDTH: the case on the left, the instrument right */
.bcard--lead{padding:32px 32px;display:grid;grid-template-columns:minmax(0,.92fr) minmax(0,1fr);column-gap:48px;align-items:center}
.bcard--lead .bcard-txt{min-width:0}
@media (max-width:1000px){.bcard--lead{grid-template-columns:minmax(0,1fr);row-gap:24px}}
@media (max-width:660px){.bcard--lead{padding:20px 20px 24px}}
/* the case line — declared here, never inherited (a component that inherits
   its ink renders differently on every page it lands on) */
.bcard-m{margin:0;font-family:var(--serif);font-weight:300;font-size:34px;line-height:1.05;letter-spacing:-.02em;color:var(--a)}
.bcard-m i{font-style:normal;opacity:.5;padding:0 .12em}
.bcard--lead .bcard-m{font-size:clamp(40px,4.6vw,60px)}
.bcard-s{margin:8px 0 0;font-family:var(--mono);font-size:10.5px;letter-spacing:.02em;color:var(--text-faint);line-height:1.5}
/* 1.45, not 1.35: these titles wrap to two lines in six of seven cards, and
   this repo's own floor for rendered text under 18px is 1.40. I declared 1.35
   when I built the board and put a wrapping card title below my own floor.
   line-height-check caught it (a.bcard-go 15px/20.25px = 1.35) — but only
   because it was run by hand: that gate is NIGHTLY, so the pre-push suite went
   22-of-23 green over it. Leading is invisible on one line, which is why a
   card title is exactly where it hides. */
.bcard h3{margin:12px 0 0;font-size:15px;font-weight:600;line-height:1.45;color:var(--text-body)}
.bcard--lead h3{margin-top:16px;font-family:var(--serif);font-size:clamp(20px,2vw,26px);font-weight:400;line-height:1.25}
.bcard-d{margin:12px 0 0;font-size:13.5px;line-height:1.65;color:var(--text-muted);max-width:46ch}
.bcard-nom{position:absolute;top:0;right:24px;transform:translateY(-50%);margin:0;font-family:var(--mono);font-size:10px;letter-spacing:.02em;color:var(--surface-page);background:var(--a);padding:4px 8px;border-radius:2px;line-height:1.4;z-index:2}
@media (max-width:660px){.bcard-nom{right:16px}}
/* ── the instrument shell ─────────────────────────────────────────────────── */
.vg{margin:0;border:1px solid var(--border-hairline);border-radius:10px;background:linear-gradient(180deg,var(--ink-wash),var(--ink-wash));padding:16px 16px 16px;min-width:0}
.vg-hd{display:flex;align-items:center;justify-content:space-between;gap:8px;padding-bottom:12px;margin-bottom:12px;border-bottom:1px solid var(--border-hairline)}
.vg-hd b{font-family:var(--mono);font-size:10.5px;letter-spacing:.02em;color:var(--text-body);line-height:1.4;font-weight:400}
.vg-hd i,
.vg-count,
.vg-held{font-family:var(--mono);font-style:normal;font-size:9.5px;letter-spacing:.02em;color:var(--text-faint);line-height:1.4}
.vg-state{width:6px;height:6px;border-radius:50%;background:var(--a);flex:0 0 auto}
/* ── 1 · WALL-E: a brief in, a plan computed, splits settled ─────────────── */
.vg-brief{margin:0 0 12px;padding-left:8px;position:relative;font-family:var(--mono);font-size:10px;letter-spacing:.055em;color:var(--text-muted);line-height:1.5}
.vg-brief::before{content:"";position:absolute;left:0;top:2px;bottom:2px;width:2px;border-radius:2px;background:color-mix(in oklab,var(--a) 60%,transparent)}
.vg-metrics{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-bottom:16px}
.vg-met{position:relative;min-width:0}
.vg-met i{display:block;font-family:var(--mono);font-style:normal;font-size:9.5px;letter-spacing:.02em;color:var(--text-faint);line-height:1.4;margin-bottom:4px}
.vg-met b{display:block;font-family:var(--mono);font-size:13.5px;font-weight:400;font-variant-numeric:tabular-nums;color:var(--text-body);line-height:1.4;white-space:nowrap}
/* the skeleton the value resolves out of — an absence, never a wrong number */
.vg-met s{display:none;position:absolute;left:0;bottom:2px;height:11px;width:78%;border-radius:2px;text-decoration:none;overflow:hidden;background:var(--bar-track)}
.vg-met s::after{content:"";position:absolute;inset:0;background:linear-gradient(90deg,transparent,var(--bar-track),transparent)}
.vg-rings{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px}
.vg-ring{text-align:center;min-width:0}
.vg-ring svg{width:100%;max-width:46px;height:auto;transform:rotate(-90deg);display:inline-block}
.vg-ring circle{fill:none;stroke-width:4.2;stroke-linecap:butt}
.vg-ring .r-t{stroke:var(--border-hairline)}
/* One circle per real segment. Each segment's own arc length and start offset
   come from the percentages on the screenshot, so the ring is the product's
   actual split — and the 7-way rings read visibly richer than the 3-way one,
   which is exactly the difference the real screen shows. */
.vg-ring .r-s{stroke:var(--a);stroke-dasharray:calc(var(--l) * 1px) 94.25;stroke-dashoffset:calc(var(--o) * 1px)}
.vg-ring .r-s:nth-child(3){stroke:color-mix(in oklab,var(--a) 52%,transparent)}
.vg-ring .r-s:nth-child(4){stroke:color-mix(in oklab,var(--a) 78%,transparent)}
.vg-ring .r-s:nth-child(5){stroke:color-mix(in oklab,var(--a) 34%,transparent)}
.vg-ring .r-s:nth-child(n+6){stroke:color-mix(in oklab,var(--a) 62%,transparent)}
.vg-ring span{display:block;margin-top:8px;font-family:var(--mono);font-size:9.5px;letter-spacing:.02em;color:var(--text-faint);line-height:1.4}
/* ── 2 · the diligence dossier: signals clear a bar, one verdict lands ───── */
.vg-sig{list-style:none;margin:0;padding:0;display:grid;gap:8px}
.vg-sig li{display:grid;grid-template-columns:34px minmax(0,1fr) 30px;align-items:center;column-gap:8px}
.vg-sig i{font-family:var(--mono);font-style:normal;font-size:9.5px;letter-spacing:.08em;color:var(--text-faint);line-height:1.4}
.vg-sig span{display:block;height:3px;border-radius:2px;background:var(--bar-track);position:relative;overflow:hidden}
.vg-sig span::after{content:"";position:absolute;inset:0;transform-origin:left center;transform:scaleX(var(--v));border-radius:2px;background:var(--a)}
.vg-sig b{font-family:var(--mono);font-size:10px;font-weight:400;font-variant-numeric:tabular-nums;color:var(--text-muted);line-height:1.4;text-align:right}
.vg-held{display:block;margin:12px 0 0}
.vg-verdict{display:flex;align-items:baseline;gap:8px;margin:12px 0 0;padding-top:12px;border-top:1px solid var(--border-hairline)}
.vg-verdict i{font-family:var(--mono);font-style:normal;font-size:9.5px;letter-spacing:.02em;color:var(--text-faint);line-height:1.4}
.vg-verdict b{font-family:var(--serif);font-size:22px;font-weight:400;line-height:1;color:var(--a)}
.vg-verdict em{font-family:var(--mono);font-style:normal;font-size:9px;letter-spacing:.02em;color:var(--text-muted);line-height:1.4;border:1px solid color-mix(in oklab,var(--a) 45%,transparent);border-radius:999px;padding:3px 8px}
/* ── 3 · OrgOS: eight modules on one shared bus, no hierarchy ────────────── */
/* auto-fit at 88px, not 68: a 285px card leaves 203px inside the instrument,
   which at 68px gives three columns and wraps the fourth chip onto a lonely
   row. 88px gives a clean two-by-two either side of the bus, and four across
   once there is room. */
/* Never auto-fit a row of exactly four chips: it resolves to THREE in a
   mid-width card and orphans the fourth. Measured [3,1] at 390 and 1440 and
   [2,2] at 768/1024 — the same orphan the .memos grid had, in a different
   component. Two per row inside a board card, four inside the wider case-page
   instrument. Both stated, neither inferred. */
.vg-row{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:4px}
.vg-hero .vg-row{grid-template-columns:repeat(4,minmax(0,1fr))}
.vg-row b{font-family:var(--mono);font-size:9.5px;font-weight:400;letter-spacing:.02em;color:var(--text-muted);line-height:1.4;text-align:center;border:1px solid var(--border-hairline);border-radius:3px;padding:4px 2px;background:var(--ink-wash)}
.vg-spine{position:relative;margin:12px 0;height:22px;display:grid;place-items:center}
.vg-spine::before{content:"";position:absolute;left:0;right:0;top:50%;height:1px;background:color-mix(in oklab,var(--a) 34%,transparent)}
.vg-spine i{position:absolute;top:50%;left:0;width:34px;height:3px;margin-top:-1.5px;border-radius:3px;background:var(--a);filter:blur(.3px)}
.vg-spine span{position:relative;font-family:var(--mono);font-size:9.5px;letter-spacing:.02em;color:var(--text-body);line-height:1.4;background:#191021;padding:0 8px}
/* ── 4 · the failure state: a graceful unknown, and two ways out ─────────── */
.vg-q{margin:0 0 12px;font-family:var(--serif);font-size:16px;font-weight:400;line-height:1.35;color:var(--text-body)}
.vg-conf{display:flex;align-items:center;gap:8px;margin:0 0 12px}
.vg-conf i{font-family:var(--mono);font-style:normal;font-size:9.5px;letter-spacing:.02em;color:var(--text-faint);line-height:1.4;flex:0 0 auto}
.vg-conf span{flex:1 1 auto;height:3px;border-radius:2px;background:var(--bar-track);position:relative;overflow:hidden}
.vg-conf span::after{content:"";position:absolute;inset:0;transform-origin:left center;transform:scaleX(.22);border-radius:2px;background:var(--a)}
.vg-conf em{font-family:var(--mono);font-style:normal;font-size:9.5px;letter-spacing:.02em;color:var(--a);line-height:1.4;flex:0 0 auto}
.vg-routes{display:grid;gap:8px}
.vg-routes b{font-family:var(--sans);font-size:11.5px;font-weight:600;color:var(--text-body);line-height:1.4;border:1px solid color-mix(in oklab,var(--a) 40%,transparent);border-radius:4px;padding:8px 12px;background:color-mix(in oklab,var(--a) 7%,transparent)}
/* small tiles: the instrument sits above the case line */
/* At 9.5px — my own legibility floor is 9px, and the chips were at 8 — the
   longest real module name ("Onboarding") needs ~62px, more than a quarter of
   a 285px tile. Two chips per row in that context; four everywhere else. */

@media (max-width:1000px){.bcard--lead{grid-template-columns:minmax(0,1fr);row-gap:24px}}
@media (max-width:660px){
.vg-metrics{grid-template-columns:repeat(2,minmax(0,1fr))}
.vg-rings{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}}
/* ═══════════════════ 5 · FinTech: a score, and its sources ═════════════════
   The case is "cites its sources", and the artefacts are explicit about the
   mechanism: "3 sources behind a score, inline — not in a tooltip". So the
   instrument is a score with its three sources attaching to it. */
.vg-score{display:flex;align-items:baseline;gap:8px;margin:0 0 12px}
.vg-score b{font-family:var(--serif);font-size:32px;font-weight:300;line-height:1;letter-spacing:-.02em;color:var(--a)}
.vg-score em{font-family:var(--mono);font-style:normal;font-size:9.5px;letter-spacing:.02em;color:var(--text-muted);line-height:1.4;border:1px solid color-mix(in oklab,var(--a) 45%,transparent);border-radius:999px;padding:3px 8px}
.vg-srcs{list-style:none;margin:0;padding:0 0 0 12px;display:grid;gap:8px;position:relative}
/* OPEN ANOMALY, not a fix. In the case-page instrument the same
   three 14px items rendered 54px apart while the board card had them 22px
   apart — the used grid-template-rows read 13.77px 45.77px 45.77px with only
   one 14px item in each row, and I could not identify what was contributing
   the extra 32px: no padding, no margin, no marker, white-space normal, three
   auto-placed items and nothing else in the tree, and no rule anywhere in the
   cascade sets grid-template-rows or a height on either element.
   grid-auto-rows:min-content changed nothing, so I removed it rather than leave
   a rule that does nothing (and it would have read as a fix). The spacing is
   cosmetic and the content is correct in both contexts; the cause is still
   unknown and is worth a second pair of eyes before anyone "fixes" it. */
.vg-srcs::before{content:"";position:absolute;left:3px;top:5px;bottom:6px;width:1px;background:color-mix(in oklab,var(--a) 38%,transparent)}
.vg-srcs li{position:relative;font-family:var(--mono);font-size:9.5px;letter-spacing:.04em;color:var(--text-muted);line-height:1.45}
.vg-srcs li::before{content:"";position:absolute;left:-10px;top:.52em;width:6px;height:1px;background:color-mix(in oklab,var(--a) 55%,transparent)}
.vg-note{margin:12px 0 0;padding-top:12px;border-top:1px solid var(--border-hairline);font-family:var(--mono);font-size:9.5px;letter-spacing:.06em;color:var(--text-faint);line-height:1.45}
/* ═══════════════════ 6 · PTC: five platforms become one ═══════════════════
   The artefact names all five; the title says four products were killed. Which
   one survived is not in canon, so nothing is marked as the survivor and the
   result is unnamed — five converge into one. */
.vg-plats{list-style:none;margin:0;padding:0;display:grid;gap:4px}
.vg-plats li{font-family:var(--mono);font-size:9.5px;letter-spacing:.04em;color:var(--text-muted);line-height:1.4;border:1px solid var(--border-hairline);border-radius:3px;padding:4px 8px;background:var(--ink-wash)}
.vg-after{display:flex;align-items:baseline;gap:8px;margin:12px 0 0;padding-top:12px;border-top:1px solid var(--border-hairline)}
.vg-after i{font-family:var(--mono);font-style:normal;font-size:9.5px;letter-spacing:.02em;color:var(--text-faint);line-height:1.4}
.vg-after b{font-family:var(--mono);font-size:11px;font-weight:400;letter-spacing:.05em;color:var(--text-body);line-height:1.4;border:1px solid color-mix(in oklab,var(--a) 52%,transparent);border-radius:3px;padding:4px 12px;background:color-mix(in oklab,var(--a) 9%,transparent)}
/* ═══════════════════ 7 · O2: the allowances screen ════════════════════════
   Real allowances off the shipped screen. The unlimited row carries no meter:
   a proportion of an unlimited allowance is undefined, and a bar there would
   be a number I made up. */
.vg-allows{list-style:none;margin:0;padding:0;display:grid;gap:8px}
.vg-allows li{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"label value" "meter meter";row-gap:4px;column-gap:8px;align-items:baseline}
.vg-allows i{grid-area:label;font-family:var(--mono);font-style:normal;font-size:9.5px;letter-spacing:.06em;color:var(--text-faint);line-height:1.4}
.vg-allows b{grid-area:value;font-family:var(--mono);font-size:10px;font-weight:400;font-variant-numeric:tabular-nums;color:var(--text-body);line-height:1.4;white-space:nowrap}
.vg-allows span{grid-area:meter;display:block;height:3px;border-radius:2px;background:var(--bar-track);position:relative;overflow:hidden}
.vg-allows span::after{content:"";position:absolute;inset:0;transform-origin:left center;transform:scaleX(var(--u,0));border-radius:2px;background:var(--a)}
.vg-allows .nobar span{background:repeating-linear-gradient(90deg,
  var(--bar-track) 0 3px,transparent 3px 7px)}
.vg-allows .nobar span::after{display:none}
.vg-bill{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;margin:12px 0 0;padding-top:12px;border-top:1px solid var(--border-hairline)}
.vg-bill i{font-family:var(--mono);font-style:normal;font-size:9.5px;letter-spacing:.02em;color:var(--text-faint);line-height:1.4}
.vg-bill b{font-family:var(--serif);font-size:18px;font-weight:400;line-height:1;color:var(--a)}
.vg-bill em{font-family:var(--mono);font-style:normal;font-size:9.5px;letter-spacing:.05em;color:var(--text-faint);line-height:1.4}
/* ════════════════════════════════════════════════════════════════════════════
   PLAY ONCE, ON SCROLL

   Everything above this line is the RESOLVED state — the product as it ends up.
   That is what renders with JavaScript off, and what a reduced-motion visitor
   sees, with no override required: the pre-animation states and the animations
   themselves exist only inside the no-preference block below. So the default is
   the truthful state and motion is the enhancement, rather than the other way
   round.

   A view() scroll timeline was the other option and it is wrong here: it scrubs
   back and forth as the reader scrolls up and down, and these are one-shot
   events — a plan computes, a verdict lands, a bill arrives. They should happen
   once. So an IntersectionObserver adds .live at 34% visibility and unobserves
   that card; the last card disconnects the observer. Nothing animates before it
   is seen, and nothing animates ever again after it has played.
   ══════════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion:no-preference){@keyframes vFade{from{opacity:0}
to{opacity:1}}
@keyframes vOut{from{opacity:1}
to{opacity:0}}
@keyframes vUp{from{opacity:0;transform:translateY(5px)}
to{opacity:1;transform:none}}
@keyframes vIn{from{opacity:0;transform:translateX(-7px)}
to{opacity:1;transform:none}}
@keyframes vGrow{from{transform:scaleX(0)}
to{transform:scaleX(var(--g,1))}}
@keyframes vRise{from{transform:scaleY(0)}
to{transform:scaleY(1)}}
@keyframes vSeg{from{stroke-dasharray:0 94.25}
to{stroke-dasharray:calc(var(--l) * 1px) 94.25}}
@keyframes vStamp{from{opacity:0;transform:scale(1.2)}
to{opacity:1;transform:scale(1)}}
@keyframes vBus{0%{left:-12%;opacity:0}
14%{opacity:1}
86%{opacity:1}
100%{left:100%;opacity:0}}
@keyframes vChip{from{border-color:var(--border-hairline);color:var(--text-faint)}
to{border-color:color-mix(in oklab,var(--a) 34%,transparent);color:var(--text-muted)}}
/* The five platform names ARE the evidence on this card. Folding them to .26
     made the card's proof unreadable for every reader who arrives after the
     animation — and squashing them vertically made the type look broken. They
     de-emphasise; they do not disappear. */
  @keyframes vFold{from{opacity:1;transform:none}
to{opacity:.58;transform:translateY(4px)}}
/* ── pre-states: what a card looks like before it has been seen ────────── */
  html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-hd,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-brief,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-met b,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-score,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-srcs li,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-note,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-sig b,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-held,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-verdict,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-plats li,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-after,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-allows li i,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-allows li b,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-bill,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-row b,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-q,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-conf em,
.vg-js :is(.bcard,.vg-hero):not(.live) .vg-routes b{opacity:0}
.vg-js :is(.bcard,.vg-hero):not(.live) .vg-met s{display:block}
.vg-js :is(.bcard,.vg-hero):not(.live) .r-s{stroke-dasharray:0 94.25}
.vg-js :is(.bcard,.vg-hero):not(.live) .vg-srcs::before{transform:scaleY(0)}
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-sig span::after,
html.vg-js :is(.bcard,.vg-hero):not(.live) .vg-allows span::after,
.vg-js :is(.bcard,.vg-hero):not(.live) .vg-conf span::after{transform:scaleX(0)}
.vg-js :is(.bcard,.vg-hero):not(.live) .vg-spine i{opacity:0}
/* every card opens with its own header */
  .vg-js :is(.bcard,.vg-hero).live .vg-hd{animation:vUp .45s cubic-bezier(.2,.7,.3,1) both}
/* ── 1 · WALL-E — a brief in, splits drawn, figures resolved ──────────── */
  .vg-js :is(.bcard,.vg-hero).live .vg-brief{animation:vUp .5s cubic-bezier(.2,.7,.3,1) .12s both}
.vg-js :is(.bcard,.vg-hero).live .r-s{animation:vSeg .8s cubic-bezier(.32,.02,.2,1) both;animation-delay:calc(var(--d,.25s) + var(--k,0) * .05s)}
.vg-js :is(.bcard,.vg-hero).live .vg-met s{display:block;animation:vOut .3s linear .82s forwards}
.vg-js :is(.bcard,.vg-hero).live .vg-met b{animation:vFade .4s ease-out var(--t,.95s) both}
/* ── 2 · FinTech — the sources attach to the number ───────────────────── */
  .vg-js :is(.bcard,.vg-hero).live .vg-score{animation:vUp .5s cubic-bezier(.2,.7,.3,1) .1s both}
.vg-js :is(.bcard,.vg-hero).live .vg-srcs::before{transform-origin:top center;animation:vRise .5s cubic-bezier(.3,.7,.3,1) .45s both}
.vg-js :is(.bcard,.vg-hero).live .vg-srcs li{animation:vIn .45s cubic-bezier(.2,.7,.3,1) var(--t) both}
.vg-js :is(.bcard,.vg-hero).live .vg-note{animation:vFade .4s ease-out 1.1s both}
/* ── 3 · the dossier — signals clear the bar, a verdict lands ─────────── */
  .vg-js :is(.bcard,.vg-hero).live .vg-sig span::after{animation:vGrow .65s cubic-bezier(.3,.02,.2,1) var(--t) both}
.vg-js :is(.bcard,.vg-hero).live .vg-sig b{animation:vFade .35s ease-out calc(var(--t) + .3s) both}
.vg-js :is(.bcard,.vg-hero).live .vg-held{animation:vUp .45s cubic-bezier(.2,.7,.3,1) .85s both}
.vg-js :is(.bcard,.vg-hero).live .vg-verdict{animation:vFade .4s ease-out 1.02s both}
.vg-js :is(.bcard,.vg-hero).live .vg-verdict b{display:inline-block;transform-origin:center bottom;animation:vStamp .5s cubic-bezier(.2,1.5,.4,1) 1.02s both}
/* ── 4 · PTC — five platforms fold into one ───────────────────────────── */
  .vg-js :is(.bcard,.vg-hero).live .vg-plats li{animation:vUp .4s cubic-bezier(.2,.7,.3,1) calc(var(--t) - .5s) both,
              vFold .5s cubic-bezier(.4,0,.3,1) var(--t) forwards}
.vg-js :is(.bcard,.vg-hero).live .vg-after{animation:vFade .4s ease-out 1.2s both}
.vg-js :is(.bcard,.vg-hero).live .vg-after b{display:inline-block;transform-origin:left center;animation:vStamp .5s cubic-bezier(.2,1.5,.4,1) 1.2s both}
/* ── 5 · O2 — the allowances fill to what shipped ─────────────────────── */
  .vg-js :is(.bcard,.vg-hero).live .vg-allows li i{animation:vFade .35s ease-out var(--t) both}
.vg-js :is(.bcard,.vg-hero).live .vg-allows span::after{animation:vGrow .7s cubic-bezier(.3,.02,.2,1) calc(var(--t) + .1s) both}
.vg-js :is(.bcard,.vg-hero).live .vg-allows li b{animation:vFade .35s ease-out calc(var(--t) + .28s) both}
.vg-js :is(.bcard,.vg-hero).live .vg-bill{animation:vUp .45s cubic-bezier(.2,.7,.3,1) 1.02s both}
.vg-js :is(.bcard,.vg-hero).live .vg-bill b{display:inline-block;transform-origin:left bottom;animation:vStamp .5s cubic-bezier(.2,1.5,.4,1) 1.06s both}
/* ── 6 · OrgOS — one pulse down the shared bus, lighting each module ──── */
  .vg-js :is(.bcard,.vg-hero).live .vg-spine i{animation:vBus 1.25s cubic-bezier(.42,0,.58,1) .3s forwards}
.vg-js :is(.bcard,.vg-hero).live .vg-row b{animation:vFade .3s ease-out calc(.3s + var(--i,0) * .085s) both,
              vChip .45s ease-out calc(.42s + var(--i,0) * .085s) forwards}
/* ── 7 · the failure state — a graceful unknown, then two ways out ────── */
  .vg-js :is(.bcard,.vg-hero).live .vg-q{animation:vUp .5s cubic-bezier(.2,.7,.3,1) .12s both}
.vg-js :is(.bcard,.vg-hero).live .vg-conf span::after{animation:vGrow .6s cubic-bezier(.3,.02,.2,1) .45s both}
.vg-js :is(.bcard,.vg-hero).live .vg-conf em{animation:vFade .35s ease-out .85s both}
.vg-js :is(.bcard,.vg-hero).live .vg-routes b{animation:vUp .45s cubic-bezier(.2,.7,.3,1) var(--t) both}}
/* the growable bars each name their own target, so one keyframe serves all three */
.vg-sig li{--g:var(--v)}
.vg-allows li{--g:var(--u)}
.vg-conf{--g:.22}
/* ── the instrument that opens a case page ────────────────────────────────
   Same component, one per case, sized to the page's reading measure rather
   than a card. It sits after the hero's prose so the principle still comes
   first, and it carries a caption because on a case page the artefact is
   being shown as evidence, not as an invitation. */
/* Sized to the page's own reading measure. I briefly made the caption a rail
   beside the specimen, having read a screenshot as showing 480px of dead space
   to its right — but the measure here is 632px, not the 1040px a full-bleed
   figure gets, so the real leftover was 72px of ordinary ragging. The rail
   shrank the specimen to 450px and squeezed the label into 150px. Measure the
   container before diagnosing a void. */
.vg-hero{margin:32px 0 8px;max-width:560px;--a:var(--acc-copper)}
/* The instrument is a <figure>, and case pages give every figure a full-bleed
   breakout — width:min(1040px,100vw-48px), max-width:none, margin-left:50%,
   transform:translateX(-50%). Inherited, that blew a 560px specimen out to
   1040px and pushed it half a page left. A component declares its own box. */
.vg-hero .vg{width:auto;max-width:100%;margin-left:0;transform:none;background:linear-gradient(180deg,
  color-mix(in oklab,var(--a) 7%,var(--surface-sunken)),var(--surface-sunken))}
.vg-cap{margin:12px 0 0;font-family:var(--mono);font-size:11px;letter-spacing:.06em;color:var(--text-faint);line-height:1.5;max-width:52ch}
/* the act accents, keyed to the real body classes (p-case-studies-*) */
body.p-case-studies-fintech .vg-hero,
body.p-case-studies-vc-diligence .vg-hero{--a:var(--acc-violet)}
body.p-case-studies-ptc .vg-hero,
body.p-case-studies-orgos .vg-hero{--a:var(--acc-amber)}
body.p-case-studies-o2 .vg-hero,
body.p-case-studies-planit .vg-hero{--a:var(--acc-rose)}
/* ╔══════════════════════════════════════════════════════════════════════════╗
   ║  THE VOICES BAND — one voice at a time                    2026-09-08     ║
   ╚══════════════════════════════════════════════════════════════════════════╝

   Replaces two anchor quotes plus a three-card row: five figures of equal
   weight, differentiated only by size. Those five people do not sit in a row,
   they SURROUND him — the client's CTO and the manager above, the tech lead and
   the engineer beside, a designer at the next desk — and the section already
   labelled every voice by vantage point.

   PROXIMITY IS THE WHOLE POINT OF THE MARKUP. The first version put the five
   controls in one column and the quote in another. That reads at 1440 and is
   broken on a phone: measured at 390, tapping the first name changed a card
   283px BELOW it, so you tap and nothing appears to happen. Arpit found it in
   minutes — "it is not following the laws of proximity."

   So every quote now sits immediately after the control that reveals it, which
   is the correct order for a thumb and for a screen reader. On a phone that IS
   the layout: the quote opens under the name you touched. From 761px up, grid
   placement lifts the quotes into a second column — the markup never reorders,
   only the geometry does.

   Radios, not :target — a hash would hijack the URL and jump the page. :has()
   reaches each quote from the shared ancestor. Zero script. Arrow keys move
   between voices natively because it is a real radiogroup.
*/
body.p-home .qvoices{--act:var(--acc-rose);display:grid;grid-template-columns:minmax(0,1fr);gap:4px;margin-top:32px}
body.p-home .qv-t{display:block;cursor:pointer;padding:12px 16px;border-left:2px solid transparent;transition:color .18s,border-color .18s,background .18s}
body.p-home .qv-t input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
body.p-home .qv-n{display:block;font-family:var(--sans);font-weight:600;font-size:13px;line-height:1.4;color:var(--text-faint)}
/* Sentence case, not caps. The string this carries used to be .qt-view — a
   one-off eyebrow above a single quote card, where uppercase mono is the house
   label treatment and correct. Its JOB changed: it is now one of eight rows a
   reader scans as a menu, and these are sentences of 30-36 characters, not
   labels. Eight stacked lines of all-caps shout and read slower, and the
   vantage line is the part doing the differentiating — so it gets the most
   readable setting, and the hierarchy comes from weight and ink instead. */
body.p-home .qv-v{display:block;margin-top:3px;font-family:var(--sans);font-style:normal;font-weight:400;font-size:12px;letter-spacing:0;text-transform:none;color:var(--text-faint);line-height:1.4}
body.p-home .qv-t:hover .qv-n{color:var(--text-body)}
body.p-home .qv-t:has(input:checked){border-left-color:var(--acc-rose);background:color-mix(in oklab,var(--acc-rose) 8%,transparent)}
body.p-home .qv-t:has(input:checked) .qv-n{color:var(--text-body)}
body.p-home .qv-t:has(input:focus-visible){outline:2px solid var(--acc-rose);outline-offset:2px}
/* height:auto is DECLARED, not inherited: the base .qt sets height:100% — right
   when it was three equal-height cards in a row, and wrong for one card at a
   time. As a grid item spanning every row it resolved to the full span, so the
   short quotes carried up to 168px of empty card. A component that inherits a
   critical property renders differently in every context it lands in. */
body.p-home .qt-solo{display:none;margin:0;height:auto;max-width:min(100%,600px)}
body.p-home .qvoices:has(#qv0:checked) #qvq0,
body.p-home .qvoices:has(#qv1:checked) #qvq1,
body.p-home .qvoices:has(#qv2:checked) #qvq2,
body.p-home .qvoices:has(#qv3:checked) #qvq3,
body.p-home .qvoices:has(#qv4:checked) #qvq4,
body.p-home .qvoices:has(#qv5:checked) #qvq5,
body.p-home .qvoices:has(#qv6:checked) #qvq6,
body.p-home .qvoices:has(#qv7:checked) #qvq7{display:block}
/* no :has(): every quote shows, stacked under its own name. The information
   never depends on the mechanism. */
@supports not selector(:has(*)){body.p-home .qt-solo{display:block;margin:8px 0 24px}}
body.p-home .qt-solo blockquote{margin:0;font-family:var(--serif);font-weight:300;font-style:normal;font-size:clamp(19px,2.1vw,26px);line-height:1.45;color:var(--text-body);max-width:40ch}
body.p-home .qt-solo figcaption{margin-top:20px;display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 8px;font-family:var(--mono);font-size:11px;letter-spacing:.06em;color:var(--text-faint);line-height:1.4}
body.p-home .qt-solo figcaption b{font-family:var(--sans);font-weight:600;font-size:14px;color:var(--text-body);line-height:1.4}
/* phone: the quote opens directly under the name you touched, so it needs a
   little air from the control and from the next name */
/* the accordion spacing is the default now, so it applies wherever the
   two-column rule does not win */
body.p-home .qt-solo{margin:8px 0 16px}
/* 761px up: the quotes lift into a second column and share one cell, so the
   index stays a scannable list beside a single display quote */
/* Two columns only where there is a pointer. A touch device keeps the
   accordion at every width: the effect must appear under the thing the thumb
   touched, and on a tablet the two-column version put the fifth voice's quote
   585px away from its control. */
/* 1000px, not 761: at 768 the card column is ~300px, which runs a 26px display
   quote to 26 lines and stretches the eight label rows to match it. The
   two-column master/detail needs real width; below that the accordion reads
   better and keeps the effect under the control. */
@media (min-width:1000px) and (hover:hover) and (pointer:fine){/* ROWS MUST BE DECLARED. grid-row:1/-1 counts lines of the EXPLICIT grid, and
     with no grid-template-rows there is only one line — so "1 / -1" silently
     collapsed to row 1, the card inflated the FIRST label's row to its own 421px
     height, and a 372px hole opened between the first name and the second. It
     measured fine on every check I had (the card was in view, one quote showed,
     nothing overflowed) because none of them asked whether the list was still a
     list. Arpit saw it instantly.
     One track per voice, so the card spans all of them and the sum of the label
     rows carries its height. If a voice is added, add a track. */
  body.p-home .qvoices{grid-template-columns:minmax(230px,340px) minmax(0,1fr);grid-template-rows:repeat(8,auto);column-gap:48px;align-items:start}
body.p-home .qv-t{grid-column:1;padding:8px 16px}
body.p-home .qt-solo{grid-column:2;grid-row:1/-1;align-self:start}
/* No sticky and no trailing clearance: both were treating the symptom of the
     bug above. With the rows declared, the index is ~450px and the tallest card
     ~421px — comparable, both inside one viewport, so nothing needs to follow
     anything. */}
/* ╔══════════════════════════════════════════════════════════════════════════╗
   ║  THE NAV BAR AT VERY SMALL WIDTHS                         2026-09-08     ║
   ╚══════════════════════════════════════════════════════════════════════════╝

   Arpit: "the button overflows the container for very small size screen."
   Measured at 280px: the toggle was 16px wide with 18px bars — the three lines
   stuck 17px PAST their own button — and the logo was crushed from 36px to 12.

   Two causes, and neither was a spacing value:

   1. Every child of #nav was flex:0 1 auto, so all three were shrinkable. The
      CTA's 189px of content made it the least compressible in practice, so the
      logo and the TAP TARGET absorbed all the shrinkage. A declared 44px target
      is a requirement, not a preference: it now refuses to shrink.
   2. This skin had replaced the base's flex-column bars with
      position:absolute; left:13px; width:18px. Absolute children do not shrink
      with their box, so when the button was squeezed the bars simply left it.
      The bars are laid out BY the button again — a flex column, centred — so
      the box contains them whatever happens to it.

   The bar needs 325px to hold logo + 44px target + a 189px pill without
   compressing anything (measured, not guessed). Below 340px the pill leaves the
   bar and the same action appears as the drawer's last item (.nav-cta-sm), so
   the bar is a logo and a full-size target, and the action is one tap away
   rather than a crushed 16px hamburger.
*/
#nav .nav-logo,
.menu-toggle{flex:0 0 auto}
.menu-toggle{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;width:44px;height:44px;min-width:44px;min-height:44px;padding:0;margin:0;position:relative}
/* ...and hidden once the real link row appears. The rule above is UNLAYERED, so a
   copy of this inside @layer base lost to it no matter how specific I made it —
   ember.css layers most of itself into `base` and anything unlayered outranks the
   whole layer. This lives beside the rule it has to beat, deliberately.
   1101px, matching styles.css's own .nav-links breakpoint exactly: hiding the
   toggle at a rounder 1000px would strand 1000-1100px with no navigation at all,
   because the links are still display:none there. */
@media (min-width:1101px){#nav .menu-toggle{display:none}}
.menu-toggle span{position:static;left:auto;flex:0 0 auto;width:18px;height:2px;border-radius:2px;background:var(--cta-grad);transition:transform .28s cubic-bezier(.2,.9,.3,1),opacity .18s}
/* closed: three bars, spaced by the flex gap — no transform needed, so nothing
   has to be undone to animate */
.menu-toggle span:nth-child(1),
.menu-toggle span:nth-child(3){transform:none}
/* open: the outer two converge on the middle (gap 4 + bar 2 = 6px of travel)
   and cross */
.menu-toggle[aria-expanded="true"] span:nth-child(1){transform:translateY(6px) rotate(45deg)}
.menu-toggle[aria-expanded="true"] span:nth-child(2){opacity:0}
.menu-toggle[aria-expanded="true"] span:nth-child(3){transform:translateY(-6px) rotate(-45deg)}
/* the drawer's copy of the action: present in the markup on every page, shown
   only where the bar cannot hold the pill */
.nav-links .nav-cta-sm{display:none}
@media (max-width:339px){#nav .nav-cta{display:none}
.nav-links .nav-cta-sm{display:block}}
/* ╔══════════════════════════════════════════════════════════════════════════╗
   ║  THE EIGHT WALK FINDINGS                                  2026-09-08     ║
   ╚══════════════════════════════════════════════════════════════════════════╝
   Found by rendering all nine bands at 390 / 768 / 1440 and opening every one.
   Three of my first readings were wrong and the measurements corrected them —
   noted where that happened, because the wrong version is the instructive part.
*/

/* 1 · THE FOOTER WAS FOUR PEERS IN A ROW — recomposed 2026-09-09.
      History: it held five cells, all flex:0 1 auto, whose natural widths summed
      past the footer, so every one shrank and wrapped and "last shipped 2026-" /
      "09-07" split a date at its hyphen. That was patched by pinning the short
      labels and letting only the sentence wrap. Then the ship stamp was deleted,
      which freed room, and the sentence stretched to 581px — more than twice any
      neighbour, and the ONLY item at 76% ink while the rest sat at 62%. So the
      least important text in the footer became the largest and brightest thing
      in it. Arpit: "the footer looks busy now."
      I offered four options that each adjusted brightness, borders or wrapping.
      He rejected all four: "you are not thinking from the first principal, do I
      need all this, can I have two buttons dyslexia and back to tap on the
      right, and on the left can I have a two liner of text of name and the
      second line is about copyright". He was right. There are TWO groups here —
      words and controls — not four peers, and no amount of tuning a peer row
      fixes a wrong grouping. The markup is regrouped in partials/footer.html;
      this is the composition, and the old per-child pinning is deleted rather
      than left to fight it. */
footer .footer-words{display:grid;gap:4px;min-width:0;justify-items:start}
footer .footer-tools{display:flex;align-items:center;gap:20px;flex:0 0 auto}
/* 2026-09-10 — Arpit: "Why are you wrapping it in two lines for just a word".
   Measured: max-width:64ch resolves to 422.4px at 11px mono, the sentence needs
   498px on one line, and the footer row had 847px free. So a hard cap was
   forcing a wrap that stranded exactly ONE of twelve words on line two, at
   every width from 768 up, with 233-449px sitting empty to its right. That is
   the leftover-space defect in the layout rule, in one line of copy.
   No cap: it is one short sentence, not prose that needs a reading measure, and
   the flex row already constrains it. text-wrap:pretty tells the browser to
   avoid a short last line if the copy ever grows past the row. */
footer .footer-note{white-space:normal;max-width:none;text-wrap:pretty}
@media (max-width:640px){footer .footer-tools{gap:16px}}
/* 2 · THE PATTERNS WIDGET IS INSET AT 768. The slot is the full 688px column at
      x=40 like everything else — my first reading blamed the slot, and the slot
      was innocent. The card INSIDE it is 440px, centred, so it sits at x=164
      while every other element on the page starts at 40. Below the two-column
      breakpoint the card fills its slot. */
@media (max-width:1000px){body.p-home .demo-slot > *{max-width:none;width:100%;margin-left:0;margin-right:0}}
/* 3 · .memos ORPHANS ITS THIRD ITEM between 601 and 1000px. Three items in a
      two-column grid leaves the third alone beside an empty cell — and .memos
      is used by BOTH act-03 bands, so it happened twice on the page. (My walk
      called how-i-build clean at 768; I had only looked at it at 1440.) One
      column in that range: a stack reads better than a deliberate orphan. */
@media (max-width:1000px) and (min-width:601px){body.p-home .memos{grid-template-columns:minmax(0,1fr)}}
/* 4 · THE BODY FLOATS OFF ITS TITLE. Inside every .memo the eyebrow hugs its
      title at 12px and the body sits 40px below it, so the paragraph reads as
      unattached. One treatment, both bands — not two treatments as I first
      said. 16px keeps the group together while still separating it. */
body.p-home .memo > * + *{margin-top:12px}
/* Two corrections to my own walk report here. The 40px gap really WAS specific
   to how-i-lead — how-i-build has always been 12/16 — and I "corrected" my own
   finding to "uniform" only because I had measured document.querySelector(
   '.memo'), which is always the first band's. Then zeroing the h3's bottom
   margin changed nothing, because .whoband .wl-lead h3{margin:12px 0 40px} is
   three classes and outranks a one-class rule. Matching specificity, and
   matching the value how-i-build already uses. */
body.p-home .memo > :is(h3,h4){margin-bottom:0}
body.p-home .whoband .wl-lead .memo :is(h3,h4){margin-bottom:0}
body.p-home .memo > :is(h3,h4) + p{margin-top:16px}
/* 5 · TWO RIGHT-HAND OBJECTS END EARLY. patterns (0 above, 156 below) and
      writing (9 above, 167 below) are top-aligned, while hero, how-i-lead and
      contact CENTRE theirs against a taller prose column — 127px, 179px and
      243px of equal space, which is composition, not a void. I reported all
      five as defects; the measurement corrected three of them. The two real
      ones now match the majority. */
@media (min-width:1001px){body.p-home #patterns .demo-slot,
body.p-home #thoughts .ixp{align-self:center}}
/* 7 · THE HERO EYEBROW splits "AI &" from "LLM PRODUCTS" while capped at 354px
      inside a 612px column. At this length it must wrap somewhere; uncapped it
      breaks after a separator instead of inside a product name. */
body.p-home .hero .k.role-line{max-width:none}
/* 8 · THE CASE BOARD IS THE ODD SECTION OUT. Eight of nine bands use a 1240px
      wrap at x=100; .work has been 1040px at x=200 since before this work.
      Normalised to the majority, which is the rule when instances disagree. */
body.p-home .work .wrap{max-width:1240px}
/* ── act 03·2 · the bar, as a READOUT ─────────────────────────── 2026-09-08
   Was three prose columns with the design system leading the headline. The band
   now shows the checking instead of describing it, the three old memos fold into
   the lede, and the design system is a clause there — out of the headline at
   Arpit's call. Every figure is from tools/teardown-facts.py or a gate's output.

   TANDEM WITH 03·1 — the review Arpit asked for. Read together the two halves
   work: the contract, then the verification of his own output, with the cream-to
   -dark flip earning the boundary. Two things did not, both measured:

   1. THE OBJECT FLIPPED SIDES. 03·1's widget sits at x=779 with prose left. My
      first version of this band put its panel at x=140 — so the eye went right,
      then left, and the halves mirrored instead of rhyming. Prose left, object
      right, in both halves now.
   2. THEY LOOKED LIKE ONE COMPONENT. Both were boxed cards: 1px border, 10-12px
      radius, a mono header row, label/value rows beneath. On a dark ground the
      second read as a repeat of the first. But they are not the same kind of
      thing — 03·1's widget is a PRODUCT UI, it has chrome because it is
      pretending to be software and you can click it; the bar is a MEASUREMENT of
      his own work. So the bar is set as a printout: no box, no radius, hairline
      rules, mono throughout. That is also why it does not borrow .vg from the
      case board — those are product miniatures, and this is a readout. */
/* ============================================================================
   THE ARTIFACT INDEX — act 03 · 2 stops asserting and starts pointing
   ----------------------------------------------------------------------------
   Replaces .aiwork-prose: a 62-word lede and a 34-word close, both of which
   CLAIMED things the repo can be asked instead. The three sentences of the lede
   are rows 2-4, each standing beside the artifact that settles it. It occupies
   the slot .aiwork-prose held, so the band keeps its two-column composition and
   the CI readout beside it is not left alone in a two-column grid.

   NO NUMBERS IN THE ROWS. The CI ledger to the right already publishes the gate
   count and the proof row below publishes the test counts; repeating either here
   would be the defect the fact-uniqueness prototype was written to catch. A row
   earns its place with a claim and a link, not with a statistic.

   Every property declared on the component: --ff-mono and --ink-dim, never
   --mono/--dim, which exist only on body.p-home. Leading is 1.4 on the 16px
   claim and 1.65 on the 11.5px receipt, both at or above the floor for their
   rendered size.
   ========================================================================== */
body.p-home .arts{min-width:0;border-top:1px solid var(--border-strong)}
body.p-home .art{padding:16px 0;border-bottom:1px solid var(--border-strong)}
body.p-home .art > b{display:block;font-family:"Source Sans 3",var(--sans),system-ui;font-size:16px;font-weight:600;letter-spacing:.005em;line-height:1.4;color:var(--text-body)}
/* A GRID, NOT A FLEX ROW. With flex and space-between, a receipt that wraps to
   two lines eats a different amount of the line, so the four doors landed at
   three different right edges — 798, 825 and 828px. Four instances of one
   component must align to ONE ANOTHER, not merely sit inside correct bounds.
   An auto column is as wide as the widest door and every door shares it.
   Baseline alignment keeps the door on the receipt's FIRST line when it wraps. */
body.p-home .art-r{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:baseline;gap:4px 20px;margin:8px 0 0}
body.p-home .art-r > i{font-style:normal;font-family:var(--ff-mono),ui-monospace,monospace;font-size:11.5px;letter-spacing:.01em;line-height:1.65;color:var(--text-faint)}
/* the house CTA grammar, declared: Source Sans 3, 11.5px, 600, .08em, violet —
   the same six properties the film's caption had to be normalised onto */
body.p-home .art-r > a{justify-self:end;font-family:"Source Sans 3",var(--sans),system-ui;font-size:11.5px;font-weight:600;letter-spacing:.08em;line-height:1.6;color:var(--acc-violet);white-space:nowrap}
body.p-home .art-note{margin:16px 0 0;font-family:var(--ff-mono),ui-monospace,monospace;font-size:11.5px;letter-spacing:.01em;line-height:1.65;color:var(--text-faint)}
/* one column on a phone: the door drops under its receipt, left-aligned */
@media (max-width:560px){body.p-home .art-r{grid-template-columns:minmax(0,1fr)}
body.p-home .art-r > a{justify-self:start;margin-top:4px}}
/* ============================================================================
   WHAT HE OWNED — the scope line on a case card, and act 01's scope band
   ----------------------------------------------------------------------------
   Both exist because of one measurement: on 2026-09-11 I counted every
   product-leadership term on the homepage by whether a HUMAN can see it without
   clicking. "roadmap" 0 visible / 2 behind a click. "product definition" 0 / 3.
   "prioritisation", "backlog", "product lead" 0 anywhere. "designer" 4 visible.
   The only visible claims to vision and strategy were inside someone else's
   testimonial, and the only place "Product Roadmapping" appeared in the served
   source was the JSON-LD knowsAbout array — the page told Google he does
   product management and did not tell a human.

   Meanwhile four clicks away: "Owned product definition, roadmap, and
   end-to-end design across all six systems", "the quarterly release roadmap
   (2016-2019), the 5->1 consolidation strategy and its four sunsets",
   "subscriptions went 0% -> 64% of new bookings in a year". The receipts
   pattern had filed WHAT HE OWNED in the same drawer as how-it-was-measured.
   For a Staff engineer that is right; for product leadership the scope is the
   headline, not the footnote.

   Both components DECLARE their ink, family, size and leading: --ff-mono and
   --ink-dim / --amber, never --mono/--dim, which exist only on body.p-home.
   ========================================================================== */
/* the two metadata lines are ONE grid item — see index.html. align-self moves
   with them, or the pair sits centred in a track sized for something else. */
body.p-home .bcard:not(.bcard--lead) .bcard-meta{align-self:start}
body.p-home .bcard-own{margin:8px 0 0;font-family:var(--ff-mono),ui-monospace,monospace;font-size:11px;letter-spacing:.02em;line-height:1.6;color:var(--acc-amber)}
/* The band is act 01's own four-column grid, a second time. Rows are SHARED
   across the cells (display:contents + explicit grid-row) so the four
   provenance lines align to one another at every width even when one headline
   wraps — per-cell grids align only where nothing wraps. .scope-k is itself a
   grid item in row 1, which is why the cell selectors count from nth-child(2). */
body.p-home .scope{margin-top:clamp(32px,4.4vh,48px);padding-top:24px;border-top:1px solid var(--border-strong);display:grid;grid-template-columns:repeat(4,minmax(0,1fr));grid-template-rows:auto auto auto;column-gap:32px;row-gap:0}
body.p-home .scope-k{grid-column:1 / -1;margin:0 0 20px;font-family:var(--ff-mono),ui-monospace,monospace;font-size:10.5px;letter-spacing:.16em;line-height:1.7;color:var(--acc-amber);text-transform:uppercase}
body.p-home .scope > div{display:contents}
body.p-home .scope > div > b{grid-row:2;font-family:var(--ff-serif),Georgia,serif;font-size:30px;font-weight:400;line-height:1.15;color:var(--text-body)}
body.p-home .scope > div > span{grid-row:3;font-family:var(--ff-mono),ui-monospace,monospace;font-size:11px;letter-spacing:.01em;line-height:1.65;color:var(--text-faint);padding-top:8px}
@media (max-width:900px){body.p-home .scope{grid-template-columns:repeat(2,minmax(0,1fr));grid-template-rows:auto auto auto auto auto;column-gap:24px}
body.p-home .scope > div:nth-child(-n+3) > b{grid-row:2}
body.p-home .scope > div:nth-child(-n+3) > span{grid-row:3}
body.p-home .scope > div:nth-child(n+4) > b{grid-row:4;padding-top:24px}
body.p-home .scope > div:nth-child(n+4) > span{grid-row:5}}
/* one column: each fact is its own block again, so the shared rows are RELEASED
   — leave them in place and four facts pair into two rows */
@media (max-width:520px){body.p-home .scope{grid-template-columns:minmax(0,1fr);grid-template-rows:none;row-gap:20px}
body.p-home .scope > div{display:grid}
body.p-home .scope > div > b,
body.p-home .scope > div > span{grid-row:auto}
body.p-home .scope > div:nth-child(n+4) > b{padding-top:0}
body.p-home .scope > div > b{font-size:26px}}
body.p-home .aiwork-two{display:grid;grid-template-columns:minmax(0,1fr) minmax(280px,420px);column-gap:48px;align-items:start;margin-top:8px}
/* 1000px, matching 03·1's own breakpoint — the two halves of the act must flip
   to one column at the same width or they disagree for 99px. */
@media (max-width:1000px){body.p-home .aiwork-two{grid-template-columns:minmax(0,1fr);row-gap:24px}}
/* the readout: hairlines, no card */
body.p-home .barledger{margin:0;padding:0;border:0;background:none}
body.p-home .bl-hd{display:flex;align-items:baseline;justify-content:space-between;gap:12px;padding-bottom:8px;border-bottom:1px solid color-mix(in oklab,var(--acc-amber) 40%,transparent)}
body.p-home .bl-hd b{font-family:var(--mono);font-weight:400;font-size:11px;letter-spacing:.02em;color:var(--acc-amber);line-height:1.4}
body.p-home .bl-hd i{font-family:var(--mono);font-style:normal;font-size:10.5px;letter-spacing:.02em;color:var(--text-faint);line-height:1.4}
body.p-home .bl-rows{list-style:none;margin:0;padding:0;display:grid}
body.p-home .bl-rows li{display:grid;grid-template-columns:minmax(80px,auto) minmax(0,1fr);column-gap:16px;align-items:baseline;padding:8px 0;border-bottom:1px solid var(--border-hairline)}
body.p-home .bl-rows i{font-family:var(--mono);font-style:normal;font-size:10.5px;letter-spacing:.02em;color:var(--text-faint);line-height:1.4}
body.p-home .bl-rows span{font-family:var(--mono);font-size:11.5px;letter-spacing:.03em;color:var(--text-body);line-height:1.5}
body.p-home .bl-foot{margin:12px 0 0;font-family:var(--sans);font-size:13px;line-height:1.6;color:var(--text-muted)}
/* ── the close: the cost of getting it wrong, and the first ninety days ──────
   Brand review, 2026-09-08. The page had enormous proof and no PROMISE: the H1
   states the reader's problem, the sub stated Arpit's credentials, and nothing
   said what he does about it. The sub now carries the promise.
   AND TWO BLOCKS CAME BACK OUT — 2026-09-08. Arpit: "we removed the redundancy
   from the contact form last time to make sure that it does his primary job,
   now you have added content which should not be here." He was right, and the
   justification I had written here convicted itself: I argued for the
   first-90-days list on the grounds that "every beat of it was already on the
   site in three different places". That is the redundancy he had removed.
   Where each beat already lives:
     · "five customer calls" → act 02's memo "Five calls in week one"
     · the capability contract → act 03·1, which is entirely about writing it
     · "watched someone fail to use it" → already on the page TWICE, in that
       same act 02 memo and in .aiwork-close
     · the Talon override (.cost) → act 01's AdTech card tells it with the
       outcome attached; in front of the form it was the anecdote without it
   So the answer to "where would you place it" is nowhere: it was a summary of
   the page, printed at the one moment the reader is trying to act. The section
   states the role, the logistics once, and the ways to start. Nothing else. */



/* the close's right column carries the post-form matter ─────── 2026-09-08
   Measured against the page's own pattern: the object in a two-column band runs
   57% of its column in the hero, 49% in how-i-lead, 74% in patterns and 85% in
   how-i-build. After today's copy additions the boarding pass was 30% of a
   1209px column — 423px of empty column above it and 423px below, the only band
   on the page under a third, and my additions are what pushed it there. The
   three post-form blocks move right, which fills the column without disturbing
   the reading order: they already came after the form, so a phone still reads
   ask, then ticket, then footnotes. */
/* 2026-09-10: .close-side and everything about balancing two columns went
   with direction A. The section is one centred column now, so there is no
   right-hand stack to strand space beside — the void those rules were
   fighting cannot occur. */


/* ═══════════════════════════════════════════════════════════════════════════
   ONE DOOR                                                       2026-09-09
   ═══════════════════════════════════════════════════════════════════════════
   Arpit: "there are multiple doors like email send me the role linkedin
   another I want you to browse on the web and figure out which is the best
   door and then you recommend me what should I do."
   He was right that I had ADDED a door rather than chosen one. Counted: the
   closing section offered TWELVE things to act on, including the same calendar
   link twice and three links back INTO the site at the moment of decision.
   The web evidence: a single CTA converts ~13.5%, two competing ~11.9%, three
   or more ~10.5%, and cutting to one has lifted conversion up to 266% — choice
   overload. In a hiring context LinkedIn replies run 17.1% against email's
   5.0% across 4M+ messages. And mailto FAILS SILENTLY for the ~40% of visitors
   with no mail client configured; the standard fix is printing the address as
   copyable text, which Arpit ruled out ("I don't want to reveal my Internet
   email address on the Internet") — so a mailto button is a door that quietly
   does not open. That is what moved the recommendation off the "Email me" CTA
   I had shipped an hour earlier, onto LinkedIn.
   Twelve actions became five, one of which is the fold's own summary. Spacing
   values are on the 4px grid — the prototype used 28px and 14px, which are not
   steps on it. */
body.p-home #contact .one-door{display:inline-flex;align-items:center;gap:8px;background:var(--cta-grad);color:var(--btn-fill-ink);border-radius:999px;padding:16px 24px;font-family:var(--sans);font-size:13px;font-weight:600;letter-spacing:.06em;text-decoration:none;min-height:44px;box-sizing:border-box}
body.p-home #contact .one-door:hover{filter:brightness(1.06)}
/* the alternative is TEXT, not a rival button — that is the whole point */
/* 2026-09-10: the form is GONE, not folded. Direction A is pass + one door +
   three text alternates, and Arpit picked it from a render with no form in
   it. Canon already recorded that his audience does not fill forms; email,
   LinkedIn, the resume and the call all remain. The Formspree endpoint left
   the site with it — git has the markup if he wants it back. */


/* ═══════════════════════════════════════════════════════════════════════════
   THE DOOR — UNLAYERED ON PURPOSE                                2026-09-10
   ═══════════════════════════════════════════════════════════════════════════
   This block sits outside @layer base deliberately, because unlayered rules
   outrank EVERY layered rule regardless of specificity. That is the mechanism
   this stylesheet already uses when a component must win (the nav menu-toggle
   rule does the same, for the same reason).

   Why it needs to win: measured across 107 instances, the component was being
   overridden by page context in four separate ways —
     * .nav-cta re-declared font, size, tracking, padding, border and radius,
       so the nav door rendered 48px tall at .08em while the same class
       elsewhere rendered 44px at .02em;
     * .lab-links a re-declared the whole pill (11.5px, radius 4px, 8px 16px);
     * an :is(.wr-more a, .contact-alt a, .lab-links a, ...) group set .08em;
     * a prose-link rule with an eleven-deep :not() chain set color:var(--link),
       which painted MAGENTA TEXT on the gradient on 37 instances.
   I patched those selectors one at a time and each fix revealed the next. The
   honest fix is not a longer :not() chain — it is the component owning its own
   properties, once, where nothing can reach it. Execution lesson 11.

   The gradient is fixed here rather than var(--heat)/var(--heat2), which are
   PER-PAGE accents: the "identical door" was painting orange on the homepage,
   magenta on /lab/ and /fit/, pale orange on the case pages. --cta-grad is
   used by nothing else. */
/* EMBER -> AMBER, not ember -> violet. The old fill travelled 43 hue-degrees
   UNDER the label — every point on it cleared 4.5:1, which is all the old
   gradient rule asked, and the word still had to be read across two hues on a
   64%-saturated ground. Staying inside the warm family cuts the travel to 9
   degrees and lifts the worst point from 7.24:1 to 9.40:1. The gradient stays,
   because "energy from heat" is the identity; the violet was the damage. */
:root{--cta-grad:linear-gradient(92deg,var(--acc-copper),var(--acc-amber))}
.cta--secondary:hover{filter:none;background:color-mix(in srgb, var(--text-body) 8%, transparent);color:var(--text-body)}
/* ============================================================================
   THE A1 RULES THAT WERE HERE NOW LIVE IN THE DESIGN SYSTEM.
   ----------------------------------------------------------------------------
   390 hand-written rules across three blocks — the o2 pilot, the homepage, and the
   seven instrument panels — are replaced by amber.css (vendored from
   amber-design-system v1.0.0) plus amber-bridge.css, which maps this site's three
   token families onto the system's semantic roles.

   WHAT THAT BOUGHT. Each of those rules existed because a colour had been solved
   for one surface: a 4% card tint that cost the accent its AA margin, a receipt row
   that cost the quiet ink its own, a plate caption sitting in its own drop shadow, a
   screen that borrowed its ground from the page. Every one of those is now a stop on
   a measured ramp, so the replacement is a mapping and not a re-solve.

   WHAT IS STILL HERE, deliberately: everything that is about this site's LAYOUT
   rather than its colour — the artalt breakpoints and figure widths at ~3231-3404,
   the act grounds, the breakouts, the grid. A design system supplies tokens and
   components; it does not know where this site puts its figures.
   ============================================================================ */

/* ── what used to be !important ── */
/* no hover, no tooltip: on touch the box could only appear clipped off-viewport;
   the surrounding prose (and the glossary) carry the definitions (2026-09-02 sweep) */
@media(hover:none){abbr[title]::after,abbr[title]::before{display:none}}
/* ── SYSTEM ADOPTION — what the bridge used to do, now stated once and by role ──
   A reconstruction plate quotes somebody else's product; it owns its whole interior,
   ink and edges alike, and the system's roles are re-pointed at ITS palette so every
   rule inside it resolves against the plate rather than the page. */
:is(.plA, .plF, .plM, .plO, .plP, .plV, .recon, [class*="-app"], [class*="-paper"],
    .plA-caption, .plF-caption, .plM-caption, .plO-caption, .plP-caption, .plV-caption, .recon-caption){
  --text-body: #16181D; --text-muted: #282B31; --text-faint: #3C4148;
  --border-hairline: #E3E6EA; --border-strong: #C6CBD2;
  --accent-text: #5C420E; --accent-fill: #5C420E; --acc-amber: #7A5410;   /* the plate's own gold: a caption over its grey chrome read 2.83:1 in the page amber */
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--text-primary) 14%, transparent),
              0 1px 2px color-mix(in srgb, var(--text-primary) 8%, transparent);
  filter: none;
}
/* A PAPER OBJECT paints paper wherever it sits. The boarding pass in the closing bookend read
   var(--cream) → the page ground, which on a bookend is dark: a cream ticket went black (Arpit
   caught it, 2026-09-12). Objects read the object tokens, and re-point the roles their
   interiors use so nothing inside them follows the page. */
:is(.pass, .bp, .qc, .psc, .cf, .env, .spec-tag, .lug){
  background: var(--obj-paper); color: var(--obj-paper-ink);
  --surface-page: var(--obj-paper); --surface-card: var(--obj-paper-2); --text-primary: var(--obj-paper-ink);
  --text-body: var(--obj-paper-ink); --text-muted: var(--obj-paper-soft); --text-faint: var(--obj-paper-soft);
  --border-strong: var(--obj-paper-rule); --border-hairline: var(--obj-paper-rule);
  --acc-copper: var(--stamp-red); --accent-text: var(--stamp-red);
}
/* the site's own instruments are charts, not screenshots: on paper a bar needs a track.
   Not scoped to main: on the case pages the panels sit outside it (found live, 2026-09-12). */
.vg{ background: var(--surface-card); border: 1px solid var(--border-strong);
  --a: var(--act); }
.vg-hero .vg{ background: var(--surface-card); }
.vg .vg-hd{ border-bottom-color: var(--border-hairline); }
.vg :is(.vg-verdict, .vg-note, .vg-after, .vg-bill){ border-top-color: var(--border-hairline); }
.vg :is(.vg-met s, .vg-sig span, .vg-conf span, .vg-allows span){ background: var(--bar-track); }
.vg .vg-met s::after{ background: linear-gradient(90deg, transparent, var(--bar-track), transparent); }
.vg :is(.vg-row b, .vg-plats li){ border-color: var(--border-hairline); background: var(--ink-wash); }
.vg .vg-spine span{ background: var(--surface-sunken); color: var(--text-body); }
.vg .vg-allows .nobar span{
  background: repeating-linear-gradient(90deg, var(--bar-track) 0 3px, transparent 3px 7px); }
:is(.hd-track, .plM-track, .lug-meter){ background: var(--bar-track); }
/* the homepage's acts each name an act accent — the system's six are interchangeable */
body.p-home .work{ --act: var(--acc-copper); }
body.p-home .who{ --act: var(--acc-violet); }
body.p-home .aiwork{ --act: var(--acc-amber);  }
body.p-home .voices{ --act: var(--acc-rose);   }
body.p-home .contract{ --act: var(--acc-amber);  }
body.p-home .labrow{ --act: var(--acc-violet); }
/* ── THE ACT ACCENT RE-RESOLVES BENEATH ITS FAMILY (see css-adopt-tokens.py, step 11) ── */
body[class*="p-case-studies"] [data-ground="bookend"], body[class*="p-case-studies"] [data-tint]{--act:var(--acc-copper)}
body.p-case-studies-adtech [data-ground="bookend"], body.p-case-studies-adtech [data-tint]{--act:var(--acc-copper)}
body.p-case-studies-fintech [data-ground="bookend"], body.p-case-studies-fintech [data-tint]{--act:var(--acc-violet)}
body.p-case-studies-vc-diligence [data-ground="bookend"], body.p-case-studies-vc-diligence [data-tint]{--act:var(--acc-amber)}
body.p-case-studies-ptc [data-ground="bookend"], body.p-case-studies-ptc [data-tint]{--act:var(--acc-rose)}
body.p-case-studies-o2 [data-ground="bookend"], body.p-case-studies-o2 [data-tint]{--act:var(--acc-violet)}
body.p-case-studies-orgos [data-ground="bookend"], body.p-case-studies-orgos [data-tint]{--act:var(--acc-copper)}
body.p-patterns [data-ground="bookend"], body.p-patterns [data-tint]{--act:var(--acc-amber)}
:is(body[class*="p-lab"],body.p-fit) [data-ground="bookend"], :is(body[class*="p-lab"],body.p-fit) [data-tint]{--act:var(--acc-violet)}
body.p-screen [data-ground="bookend"], body.p-screen [data-tint]{--act:var(--acc-rose)}
body[class*="p-writing"] [data-ground="bookend"], body[class*="p-writing"] [data-tint]{--act:var(--acc-violet)}
body[class*="p-resources"] [data-ground="bookend"], body[class*="p-resources"] [data-tint]{--act:var(--acc-copper)}
body.p-home #thoughts [data-ground="bookend"], body.p-home #thoughts [data-tint]{--act:var(--acc-violet)}
body.p-home .work [data-ground="bookend"], body.p-home .work [data-tint]{--act:var(--acc-copper)}
body.p-home .who [data-ground="bookend"], body.p-home .who [data-tint]{--act:var(--acc-violet)}
body.p-home .aiwork [data-ground="bookend"], body.p-home .aiwork [data-tint]{--act:var(--acc-amber)}
body.p-home .voices [data-ground="bookend"], body.p-home .voices [data-tint]{--act:var(--acc-rose)}
body.p-home .contract [data-ground="bookend"], body.p-home .contract [data-tint]{--act:var(--acc-amber)}
body.p-home .labrow [data-ground="bookend"], body.p-home .labrow [data-tint]{--act:var(--acc-violet)}
body.p-home .qvoices [data-ground="bookend"], body.p-home .qvoices [data-tint]{--act:var(--acc-rose)}
/* the display ink on a bookend: the warm white, not the reading grey */
[data-ground="bookend"] :is(h1, .case-hero h1, .hero h1){color:var(--neutral-50)}
/* ── RHYTHM (Arpit, 2026-09-13: "the negative space between and within sections is not
   proper"). The system names ONE act rhythm (--act-rhythm, 80px; the hero exempt) and
   says every act in a sequence shares it — nothing on the site consumed it. Measured:
   homepage acts carried 84/88/92/96/120 and the seam line added 96px of its own on top,
   so the blank between two acts ran ~200px at phone and desktop alike; case chapters sat
   120px apart at every width, pattern chapters 64, writing chapters 68; the Lab's first
   card in a section added 40px to the section's 88. Two numbers now, each stepping with
   the viewport: the ACT (between bands) and the CHAPTER (between h2 groups inside one
   article). A first child never adds its own top margin to the band's padding. */
:root { --rhythm-act: var(--act-rhythm); --rhythm-chapter: 64px; --section-y: var(--rhythm-act); }
@media (max-width:900px) { :root { --rhythm-act: 64px; --rhythm-chapter: 56px; } }
@media (max-width:600px) { :root { --rhythm-act: 48px; --rhythm-chapter: 48px; } }
body.p-home :is(.receipts, .work, .who, .contract, .labrow, .voices, .close) { padding-top: var(--rhythm-act); padding-bottom: var(--rhythm-act); }
body.p-home section:has(> :is(.seam, .seam-up)) { padding-top: 0; }           /* the seam line sits on the boundary… */
body.p-home :is(.seam, .seam-up) { margin-bottom: var(--rhythm-act); }         /* …and carries the act's top space itself */
body.p-home .wrap > :first-child, .section > :first-child, .section-inner > :first-child, .lab-wrap > :first-child, .measure-c > :first-child { margin-top: 0; }
body.p-home .wrap > :last-child, .section > :last-child, .section-inner > :last-child, .lab-wrap > :last-child, .measure-c > :last-child { margin-bottom: 0; }   /* nor a last child to its bottom */
main > :is([class]) > section { margin-bottom: var(--rhythm-chapter); }           /* case + pattern chapters (was 80 / 64, fixed) */
.measure-c > section[class*="xi-case-studies-"] { padding-top: 24px; }           /* a ruled chapter: the line sits 24 above its heading (was 40) */
main > :is([class]) > h2.section-title { margin-top: var(--rhythm-chapter); }
/* journey-check, 2026-09-13: jump anchors landed 8px UNDER the 94px fixed nav — the site carried
   scroll-margin-top 80/96/120 in three places. One clearance for every anchor target: the bar plus a
   breath, so the heading a reader jumped to is the first thing they see. */
main [id] { scroll-margin-top: 120px; }
/* explore-loop, 2026-09-13: the process page stacked three centred widths — text 555, video 1000,
   diagram 1280 — so eyebrows and captions began at three left edges. Wide objects now share the
   video's width (min(1000px, 100vw − 80px)); the reading measure stays the third edge, by design. */
body.p-process .process-fig { --vw-w: min(1000px, calc(100vw - 80px)); width: var(--vw-w); max-width: none; margin-left: calc((100% - var(--vw-w)) / 2); margin-right: calc((100% - var(--vw-w)) / 2); }
/* explore-loop, 2026-09-13: on the patterns hub at tablet width the SVG hides (≤1040) and its typeset
   twin shows — in a 480px grid cell, three cards stacked, the panel's right half empty. The twin takes
   the SVG's place (the full-width image area) and lays its cards in a row wherever three fit. */
body[class*="p-patterns"] :is(.xi-patterns-012, .xi-patterns-018) .artalt { grid-area: img; }
body[class*="p-patterns"] :is(.xi-patterns-012, .xi-patterns-018) .artalt-set { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
/* Arpit, 2026-09-13 (copy review, group B): a case chapter's spine label — The stakes / The test /
   The mechanism / Falsifiable evidence — used to be glued to the heading with a colon, so the H2
   read as a form field. It is now the chapter's eyebrow, same words, and the sentence stands alone.
   The span declares every property it needs (lesson 11); it inherits nothing from the display face. */
.section-title > .chapter-k { display:block; font-family:var(--ff-mono); font-size:var(--fs-eyebrow); font-weight:500; letter-spacing:.02em; line-height:1.5; color:var(--accent-text); margin:0 0 12px; text-transform:none; }     /* writing + resources chapters (was 48, fixed) */
:is([class*="p-lab"], .p-fit) main > :is(section, header).section:not(.lab-hero) { padding-top: var(--rhythm-act); padding-bottom: var(--rhythm-act); }   /* Lab + Fit acts (was 88 fixed) */
/* Arpit, 2026-09-13: "#CFC4B4 is looking dull". On a dark ground the system's reading ink
   is neutral-200 and everything below the headline shared it. Lift each ink one stop so the
   hero reads in three levels: headline (50) · names and body (100) · quiet mono lines (200).
   Contrast only rises (14.29 / 11.16:1). */
[data-ground="bookend"] { --text-body:var(--neutral-100); --text-muted:var(--neutral-100); --text-faint:var(--neutral-200); }
body.p-home .hero .cred-strip > div > b { color:var(--neutral-50); }
/* /patterns/ — the rule block's meta ("Read the rule", the date) sat centred in the
   300px column beside a 66ch prose block: an element centred in leftover space. It is
   a metadata RAIL: it starts at the top of the prose and reads as a margin note. */
@media (min-width:861px){
  body[class*="p-patterns"] :is(.xi-patterns-012,.xi-patterns-018).is-paper{display:grid}
  body[class*="p-patterns"] :is(.xi-patterns-012,.xi-patterns-018).is-paper{grid-template-columns:minmax(0,66ch) 300px;justify-content:space-between;column-gap:48px}   /* the grid had been switched off by a display:block that outranked it — measured: display:block at 1440, so its areas never applied */
  body[class*="p-patterns"] .xi-patterns-017{grid-area:meta;align-self:start;align-items:flex-start;text-align:left;padding-top:4px}   /* an extracted grid-row:1/span 20 had overridden the named area */
  body[class*="p-patterns"] :is(.xi-patterns-012,.xi-patterns-018) > :is(.eyebrow,.section-title){grid-column:1/-1}
}
/* CASE HERO, desktop: the solo variant capped an 880px column and let the paragraph run
   ~500px wide beside nothing — half the band empty (layout rule: whitespace is designed
   or it is a defect). The stats already belong to the hero; they become its right rail,
   stacked, top-aligned with the paragraph. Kicker and headline still span the band.
   The hero's content sits in ONE inner wrapper, so the grid is declared on that. */
@media (min-width:1100px){
  body[class*="p-case-studies"] .case-hero__in--solo{max-width:1180px;grid-template-columns:1fr}
  body[class*="p-case-studies"] .case-hero__in--solo > div{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(300px,.85fr);column-gap:clamp(40px,5vw,80px);row-gap:0;align-items:start}
  body[class*="p-case-studies"] .case-hero__in--solo > div > :is(.case-hero__kicker,h1){grid-column:1/-1}
  body[class*="p-case-studies"] .case-hero__in--solo > div > .case-hero__hook{grid-column:1;grid-row:3;margin-top:0}
  body[class*="p-case-studies"] .case-hero__in--solo > div > .hand{grid-column:1;grid-row:4}
  body[class*="p-case-studies"] .case-hero__in--solo > div > .case-stats{grid-column:2;grid-row:3/span 2;display:flex;flex-direction:column;flex-wrap:nowrap;gap:16px;margin-top:0}
  body[class*="p-case-studies"] .case-hero__in--solo > div > .case-stats > .case-stat{flex:0 0 auto;min-width:0}
}
/* card titles: 22px at 1.15 was under the 1.25 floor on two-line titles (line-height-check);
   the system's title leading is 1.3 */
.card-title{line-height:1.3}
/* lab/eval severity chips: amber ink on the amber soft fill read 4.03:1 — the chip's ink is
   one stop deeper than the word colour, the same one-stop rule a tint obeys */
:where(body.p-lab-eval) .sev-medium{color:var(--amber-800)}
:where(body.p-lab-eval) .sev-high{color:var(--rose-800)}
/* the nav links declare their tracking; inheriting the page's -0.003em made the same nav
   compute two values across 35 pages (component-identity-check) */
#nav .nav-links{letter-spacing:0}
#nav .nav-links a:not(.cta){letter-spacing:.02em}
/* a control edge owes 3:1: the lab door's 58% link-ink border read 2.47:1 */
.lab-links a:not(.cta){border-color:var(--link-ink)}
/* the teardown's measured table held min-width:520px through the phone restack (overflow-sweep
   at 390: 520px in 294px) — the restack's own selector loses to :where(body) table.td-table on
   specificity; released here, where the layer decides */
@media (max-width:860px){:where(body.p-lab-teardown) table.td-table{min-width:0}}
/* the two caption doors (the film caption on the hero, the method's receipts link on /process/)
   spoke at 11.5px against the house 14px — one door grammar (cta-grammar-check) */
body.p-home .hero .vid-hero-cap a, .contract-links a{font-size:var(--fs-ui);letter-spacing:.02em;color:var(--door-ink)}   /* 16 of 21 doors track at .02em; these two held .08em */
/* two ledger lines on the homepage — the receipts line and the "rather read first?" links —
   were capped at 720px with 580px of nothing beside them at 1440 (balance-check). They are
   rows of short items, not reading prose; they span the wrap. */
body.p-home .lab-row, body.p-home .contact-read, body.p-home .voices .lede{max-width:none}   /* the voices lede takes the work act's own treatment (.work .lede{max-width:none}) rather than a cap with a void */
/* ── HOMEPAGE, as information architecture (Arpit, 2026-09-12: "sections looking orphaned") ──
   1 · the hero filled the viewport and then padded 120px more under the client strip: a dead
       dark band before act 01. The band ends with the strip. */
body.p-home .hero{padding-bottom:clamp(32px,5vh,64px)}
/* 2 · one opener rhythm for every act and sub-act: eyebrow, 16px, title, 20px, lede — the
       eyebrow→title gap ran 80px on the acts and 40px on the sub-acts, so each opener read as
       three floating lines instead of one unit. */
body.p-home .chap{margin-bottom:16px}
body.p-home :is(.work,.who,.contract,.aiwork,.voices) .wrap > h2,
body.p-home .chap + h2, body.p-home .chap + .chap-i + h2{margin-top:0}
body.p-home .chap-i{margin:0 0 20px}
body.p-home .k{margin-bottom:12px}
body.p-home .wrap > .k + :is(h2,h3,.lede){margin-top:0}
/* 3 · the work sub-act now opens like 02·2, 03·2 and 04·2: its eyebrow uses its own first clause.
       The index chip takes the act's accent, like its siblings. */
body.p-home .k-idx-ember{color:var(--acc-copper)}
body.p-home .work .lede{max-width:none}   /* under its eyebrow the sub-act lede spans the band, as the voices lede does; a 66ch cap left 710px of nothing beside it (balance-check) */
/* 4 · one card grammar in act 01: the case cards took a muddy tint while the receipt cards
       beside them are paper with a coloured top rule. Normalised to the receipt card. */
.bcard{background:var(--surface-card);border-top:3px solid var(--a)}
/* ── CASE PAGES: the section links (case-jump) sat 186px left of the reading column and wore
   underlines; they align to the column and speak the door ink, no underline (Arpit). */
body[class*="p-case-studies"] .case-jump{width:auto;max-width:656px;margin:0 auto 32px;padding:0;box-sizing:border-box;transform:none;left:auto}   /* 656 = the 704 column minus its 24px paddings: the first link starts where the prose starts */
/* eight links in a 656px column wrapped 7 + 1 and orphaned "The public record": two rows of four */
@media (min-width:560px){body[class*="p-case-studies"] .case-jump:has(> a:nth-child(7)){display:grid;grid-template-columns:repeat(4,minmax(0,1fr));column-gap:16px;row-gap:4px}}
.case-jump a{border-bottom:0;color:var(--door-ink);font-weight:600;padding:8px 0}
.case-jump a:hover{color:var(--text-primary)}
/* the close band's heading is display type too */
[data-ground="bookend"] .close h2, [data-ground="bookend"] .page-head h1{color:var(--neutral-50)}


/* ── THE BUTTON. One component, 110 instances, 38 pages; it declares every critical
   property itself (execution lessons 4 and 11) and reads only the system's tokens, so
   the bookend and the paper resolve the same rule against their own roles.
   Variants: .cta (fill) · .cta--secondary (outline) · .cta-quiet (a text link that
   behaves like a control). Icon via --cta-icon on a modifier (.cta--linkedin, .cta--doc);
   .cta--bare drops it.
   Fill and face are the two decisions still open to Arpit (prototypes/amber-buttons.html);
   these two tokens are where his pick lands. */
:root, [data-ground="bookend"], [data-tint] {
  --cta-fill: var(--acc-copper);            /* F — Arpit, 2026-09-12: the copper fill (copper-600, cream label on paper) */
  --cta-fill-hover: var(--cta-fill-hover-copper);
  --cta-face: var(--type-label);           /* D: the system's label face */
}
/* B — Arpit, 2026-09-13: on a dark ground the system's "read upward" rule had stepped the
   fill to copper-100, a pastel that reads as disabled; hover went paler still. The bookend
   now takes the bright copper (copper-500, dark label 4.49:1) and hover brightens. */
/* D — Arpit, 2026-09-14: from eight rendered fills on the dark ground, the bright copper (copper-300,
   dark label 8.17:1). Paper keeps copper-600. Hover steps one stop lighter, as before. */
[data-ground="bookend"] { --cta-fill: var(--copper-300); --cta-fill-hover: var(--copper-200); }
/* a.cta/button.cta: (0,1,1), so a generic `body.p-home a{color:inherit}` (0,1,1) declared
   earlier can no longer strip the label — the button outranks element selectors, lesson 4. */
a.cta, button.cta, .cta {
  display:inline-flex; align-items:center; justify-content:center; gap:12px;
  /* G3 — Arpit, 2026-09-13 ("linkedin icon is not legible"): a 1.35em solid glyph centred on
     the label's x-height, and the pill lifts on hover. Chosen from three rendered directions. */
  min-height:46px; padding:0 24px; box-sizing:border-box;   /* one 46px pill whether or not it carries a glyph; centre alignment does the rest */
  font:var(--cta-face); font-size:15px; font-weight:600; line-height:1; letter-spacing:.02em; text-transform:none;
  white-space:nowrap; text-decoration:none; cursor:pointer;
  border:1px solid transparent; border-radius:var(--radius-pill);
  background:var(--cta-fill); color:var(--btn-fill-ink);
  transition:background var(--dur-quick) var(--ease-standard), color var(--dur-quick) var(--ease-standard), transform var(--dur-quick) var(--ease-standard), box-shadow var(--dur-quick) var(--ease-standard);
}
a.cta:hover, button.cta:hover, .cta:hover { background:var(--cta-fill-hover); color:var(--btn-fill-ink); filter:none; transform:translateY(-2px); box-shadow:0 10px 24px -10px color-mix(in srgb, var(--copper-500) 70%, transparent); }
@media (prefers-reduced-motion:reduce) { a.cta:hover, button.cta:hover, .cta:hover { transform:none; } }
a.cta:focus-visible, button.cta:focus-visible, .cta:focus-visible { outline:2px solid var(--border-focus); outline-offset:3px; }
.cta::before {
  content:""; flex:0 0 auto; display:block; background-color:currentColor;
  --cta-icon-ar:1; --cta-ico:1.35em;   /* G3: the glyph is legible at a glance — 20px beside a 15px label */
  height:var(--cta-ico); width:calc(var(--cta-ico) * var(--cta-icon-ar));
  -webkit-mask:var(--cta-icon) center/100% 100% no-repeat; mask:var(--cta-icon) center/100% 100% no-repeat;
}
.cta:not([class*="cta--"])::before, .cta--bare::before { display:none; }
.cta--linkedin::before { --cta-icon-ar:1; }
.cta--doc::before { --cta-icon-ar:0.8; }
.cta--linkedin { --cta-icon:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M20.45%2020.45h-3.56v-5.57c0-1.33-.03-3.04-1.85-3.04-1.85%200-2.14%201.45-2.14%202.94v5.67H9.35V9h3.41v1.56h.05c.48-.9%201.64-1.85%203.37-1.85%203.6%200%204.27%202.37%204.27%205.46v6.28zM5.34%207.43a2.06%202.06%200%201%201%200-4.13%202.06%202.06%200%200%201%200%204.13zM7.12%2020.45H3.56V9h3.56v11.45zM22.22%200H1.77C.79%200%200%20.77%200%201.73v20.54C0%2023.23.79%2024%201.77%2024h20.45c.98%200%201.78-.77%201.78-1.73V1.73C24%20.77%2023.2%200%2022.22%200z'/%3E%3C/svg%3E"); }
.cta--doc { --cta-icon:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2020'%3E%3Cpath%20fill-rule='evenodd'%20d='M2%200h8l6%206v12a2%202%200%200%201-2%202H2a2%202%200%200%201-2-2V2a2%202%200%200%201%202-2zm7%201.5V7h5.5L9%201.5zM3.5%2010h9v1.5h-9zm0%203.5h9V15h-9z'/%3E%3C/svg%3E"); }
a.cta--secondary, button.cta--secondary, .cta--secondary { background:none; border-color:var(--btn-line); color:var(--btn-line-ink); }
a.cta--secondary:hover, button.cta--secondary:hover, .cta--secondary:hover { background:var(--ink-wash); color:var(--btn-line-ink); box-shadow:none; }
a.cta-quiet, button.cta-quiet, .cta-quiet {
  display:inline-block; min-height:24px; padding:4px 0; border:0; background:none; border-radius:0;
  font:var(--type-label); font-weight:600; letter-spacing:.02em; color:var(--door-ink); text-decoration:none;
  /* Arpit, 2026-09-12: coloured, no underline. The colour is the affordance; hover deepens it. */
}
a.cta-quiet:hover, button.cta-quiet:hover, .cta-quiet:hover { color:var(--text-primary); }
/* the nav door composes .cta; only its placement is local */
.nav-cta { transition:background .3s, color .3s; }
.nav-cta:hover { transform:translateY(-2px); }
@media (prefers-reduced-motion:reduce) { .nav-cta:hover { transform:none; } }


/* ── ACT OPENERS AS LANDMARKS (Arpit, 2026-09-13: "when you scroll the homepage you miss the start of
   the next section"). The opener was a light numeral and a light serif line at body weight. Now: a
   3px rule in the act's own colour across the reading width, the act numeral large and in that colour,
   the act name in small mono caps beside it (below it on a phone); a sub-act repeats the idea at one
   third the size. Scoped to the acts — the hero's eyebrow shares the .k class and stays as it is.
   Chosen from three rendered directions (H1 numeral + H2's rule). */
body.p-home main > section:not(.hero) .chap{grid-template-columns:auto 1fr;align-items:baseline;column-gap:20px;padding-top:20px;border-top:3px solid var(--act);margin-bottom:12px}
body.p-home main > section:not(.hero) .chap-n{font-size:clamp(44px,5vw,72px);font-weight:300;color:var(--act);line-height:.9;letter-spacing:-.03em}
body.p-home main > section:not(.hero) .chap-t{font-family:var(--ff-mono);font-size:clamp(12px,1vw,14px);font-weight:500;letter-spacing:.06em;text-transform:uppercase;line-height:1.5;color:var(--text-muted)}
body.p-home main > section:not(.hero) .k{padding-top:16px;border-top:1px solid var(--act)}
body.p-home main > section:not(.hero) .k-idx{color:var(--act);font-weight:600}
@media (max-width:600px){
  body.p-home main > section:not(.hero) .chap{grid-template-columns:1fr;row-gap:8px}
}

/* ── THE FOOTER'S BOOKENDS (Arpit, 2026-09-13: "add the AM monogram to these empty cream spaces").
   The homepage footer is a 1240px card on the page ground, so beyond 1320px the ground shows either
   side of it. The logo's monogram sits in each gutter, centred on the card, the size of the nav mark —
   the same mark that opens the page closes it. Below 1320px there is no gutter and nothing is drawn. */
@media (min-width:1320px){
  body.p-home footer{position:relative}
  body.p-home footer::before, body.p-home footer::after{content:"";position:absolute;top:50%;width:min(64px, calc((100vw - 1240px)/2 - 24px));aspect-ratio:200/140;transform:translateY(-50%);background:url("/assets/logo-ember.svg") center/contain no-repeat;pointer-events:none}
  body.p-home footer::before{right:calc(100% + 18px)}
  body.p-home footer::after{left:calc(100% + 18px)}
}

/* Act 05 is a card on a dark stage, not a chapter in the reading column: no numeral, no rule — the
   heading alone, centred over the boarding pass (Arpit, 2026-09-13). */
body.p-home main > section.close .chap{display:block;border-top:0;padding-top:0;text-align:center;margin-bottom:24px}
body.p-home main > section.close .chap-n{display:none}
body.p-home main > section.close .chap-t{display:block;color:var(--text-muted)}
/* ── THE FIRST BAND CLEARS THE NAV (2026-09-14, Arpit on /patterns/: "sticking to header, you
   missed in exploratory setting"). The fixed nav renders 94/86/78px tall (its padding steps at
   1024 and 768); every page's first band had a typed padding — 104, 100, 96, 90, or the act
   rhythm's 48 — so the gap under the bar ran from 26px down to −29px (lab/plugin) and the
   patterns eyebrow sat 4px under the bar at 1440. One token, one rule, every first band: the
   nav's height plus one 32px breath. Case heroes and the homepage hero keep their own, larger
   openings. Measured by tools/nav-clearance-check.py (floor 24px) so the token cannot drift
   from the nav it mirrors without going red. */
:root{--nav-h:94px}
@media (max-width:1024px){:root{--nav-h:86px}}
@media (max-width:768px){:root{--nav-h:78px}}
.page-head, .xi-patterns-004, .xi-resources-003, header.xi-writing-003,
:where(body.p-lab,body.p-fit,body.p-lab-eval,body.p-lab-loop,body.p-lab-teardown) main#main > .lab-hero,
body.p-lab-plugin main#main > .section:first-child { padding-top: calc(var(--nav-h) + 32px); }

/* ── SECONDARY CONTROLS REACH THE 44px FLOOR (2026-09-14, explore-loop sessions 4 and 6: the receipt
   buttons measured 37px tall and the Lab's link-buttons 38px on a 412px phone, the case jump links 36px at 768 (round two), the reconstruction mode toggles 40px at 412 (round four, live) — under the 44px thumb
   floor the primary button already clears). Same look, taller box: the padding stays, the pill grows. */
body.p-home .rcpt-btn, .case-jump a, .rxp-mode, .rxo-mode,
:where(body[class*="p-lab"],body.p-fit) .lab-links a:not(.cta) { min-height:44px; display:inline-flex; align-items:center; box-sizing:border-box; }
/* ── THE LAB HERO RUNS THE CODE (2026-09-14, Arpit: "fix the empty right half of the lab hero", A of
   three rendered directions). The band is a 7/5 grid at the inner width: the claim left, a panel right
   that imports loop.test.js and reports the tally. Below the hero, the Lab's list sections are two
   columns from 1024 (claim | list; prose | aside) so no band is a 62ch column beside 700px of nothing. */
:where(body.p-lab) .lab-hero .lab-hero-grid{max-width:var(--inner-max);display:grid;grid-template-columns:minmax(0,7fr) minmax(0,5fr);column-gap:64px;align-items:center}
:where(body.p-lab) .lab-hero .lab-hero-grid > *{min-width:0}
:where(body.p-lab) .lab-hero .lab-lede{max-width:none}
@media (max-width:960px){:where(body.p-lab) .lab-hero .lab-hero-grid{grid-template-columns:minmax(0,1fr);row-gap:40px}}
.lh-inst{border:1px solid color-mix(in srgb, var(--neutral-50) 14%, transparent);border-radius:12px;background:color-mix(in srgb, var(--neutral-50) 4%, transparent);padding:20px 24px;font-family:var(--ff-mono),ui-monospace,monospace;color:var(--neutral-100)}
.lh-hd{display:flex;justify-content:space-between;gap:16px;align-items:baseline;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--neutral-300);border-bottom:1px solid color-mix(in srgb, var(--neutral-50) 12%, transparent);padding-bottom:12px;margin-bottom:16px}
.lh-tally{margin:0;font-family:var(--ff-display);font-size:clamp(40px,4vw,64px);line-height:1;color:var(--copper-300);letter-spacing:-.02em}
.lh-tally small{font:500 12px/1.6 var(--ff-mono),ui-monospace,monospace;letter-spacing:.06em;color:var(--neutral-200);display:block;margin-top:12px;text-transform:uppercase}
.lh-inst.is-err .lh-tally{color:var(--status-negative,#E17149)}
.lh-log{list-style:none;margin:16px 0 0;padding:0;font-size:12.5px;line-height:1.75}   /* eight lines, all fully painted — a clipped-and-faded tail read as text with no ink (contrast-audit) */
.lh-log li{display:flex;gap:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;opacity:0;animation:lh-in .25s forwards}
.lh-log li.lab-nojs{white-space:normal;opacity:1;animation:none;color:var(--neutral-200)}
.lh-log li b{color:#7FCF9E;font-weight:600;flex:0 0 auto}
.lh-log li span{color:var(--neutral-200);overflow:hidden;text-overflow:ellipsis}
@keyframes lh-in{to{opacity:1}}
@media (prefers-reduced-motion:reduce){.lh-log li{opacity:1;animation:none}}
.lh-foot{margin:16px 0 0;font-size:11px;line-height:1.6;color:var(--neutral-300);letter-spacing:.02em}
.lh-foot a{color:var(--copper-200)}
/* the two-column list bands */
@media (min-width:1024px){
  /* the band that holds a two-column body opens to the inner width — otherwise the columns split a 62ch measure and the right half of the page stays empty */
  :where(body.p-lab) .lab-wrap:has(> .lab-body.lb-two){max-width:var(--inner-max)}
  :where(body.p-lab) .lab-body.lb-two{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);column-gap:64px;align-items:start;max-width:var(--inner-max)}
  :where(body.p-lab) .lab-body.lb-two > .lb-main > p{max-width:none}
  :where(body.p-lab) .lab-body.lb-two > .lb-side{min-width:0}
  :where(body.p-lab) .lab-body.lb-two > .lb-side .lab-note{margin-top:0}
  :where(body.p-lab) .lab-body.lb-two > .lb-side .ev-tiers{margin-top:0}
  /* claim | list, with the closing note under the claim at desktop — in the source it follows the list, so a phone reads claim, list, note */
  :where(body.p-lab) .lab-body.lb-two{grid-template-areas:"main side" "note side"}
  :where(body.p-lab) .lab-body.lb-two > .lb-main{grid-area:main}
  :where(body.p-lab) .lab-body.lb-two > .lb-side{grid-area:side}
  :where(body.p-lab) .lab-body.lb-two > .lab-note{grid-area:note;margin-top:32px}
  /* prose | aside (the "why a lab" essay): the essay takes the wider column and the thresholds note rides beside it */
  :where(body.p-lab) .lab-body.lb-two:has(> aside){grid-template-columns:minmax(0,7fr) minmax(0,5fr)}
  :where(body.p-lab) .lab-body.lb-two > aside.lb-side{position:sticky;top:calc(var(--nav-h) + 24px)}
  :where(body.p-lab) .lab-body.lb-two > aside.lb-side .lab-links{margin-top:24px;flex-direction:column;align-items:stretch}
}
/* ── THE RAILS (2026-09-14, Arpit: "fix the architectural gap across all the pages"; A of two rendered
   directions per family). Seventeen article pages and five Lab tool pages set their text in a 45% centred
   column and left the rest of every band empty. From 1024px the space has a role: the article hero is
   claim | field card, the article body is rail | column (a sticky "on this page" list, built by ia-rail.js
   from the page's own h2s); the Lab hero is claim | instrument, the Lab body is heading | content with the
   heading sticky. Below 1024px nothing here applies — the phone reads in source order. */
.ia-k{margin:0 0 12px;font:600 11px/1.6 var(--ff-mono),ui-monospace,monospace;letter-spacing:.1em;text-transform:uppercase;color:var(--text-faint)}
.ia-toc{list-style:none;margin:0;padding:0;border-left:1px solid var(--border-strong)}
.ia-toc li a{display:block;padding:8px 0 8px 16px;margin-left:-1px;border-left:2px solid transparent;font:500 13px/1.5 var(--ff-sans),system-ui,sans-serif;color:var(--text-muted);text-decoration:none;transition:color var(--dur-quick) var(--ease-standard),border-color var(--dur-quick) var(--ease-standard)}
.ia-toc li a:hover, .ia-toc li a.is-here{color:var(--amber-700);border-left-color:var(--accent-fill)}
.ia-m{margin:16px 0 0;font:400 13px/1.7 var(--ff-sans),system-ui,sans-serif;color:var(--text-muted)}
.ia-m a{color:var(--amber-700);text-decoration:none}   /* amber-600 read 4.46:1 on the tinted act grounds; one stop deeper clears it everywhere */
.ph-card .ia-k, .lh-side .ia-k{color:var(--neutral-300);margin-top:16px}
.ph-card .ia-toc, .lh-side .ia-toc{border-left-color:color-mix(in srgb, var(--neutral-50) 20%, transparent)}
.ph-card .ia-toc li a, .lh-side .ia-toc li a{color:var(--neutral-100);padding:4px 0 4px 16px}
.ph-card .ia-toc li a:hover, .lh-side .ia-toc li a:hover{color:var(--copper-200);border-left-color:var(--copper-300)}
/* below 1024 the card is not a card: its meta lines read inline under the title, exactly as they did before */
.ph-card{margin-top:16px}
@media (min-width:1024px){
  /* article hero: claim | field card */
  :is(body.p-lab-loop,body.p-lab-eval,body.p-lab-teardown,body.p-lab-plugin,body.p-fit) .lab-wrap{max-width:var(--inner-max)}   /* the Lab wrappers had been capped at the reading measure; the grids below need the inner width */
  .page-head > .xi-process-004{max-width:var(--inner-max);display:grid;grid-template-columns:minmax(0,7fr) minmax(0,5fr);column-gap:64px;align-items:end}
  .page-head > .xi-process-004 > *{min-width:0}
  .ph-card{display:block;border:1px solid color-mix(in srgb, var(--neutral-50) 14%, transparent);border-radius:12px;background:color-mix(in srgb, var(--neutral-50) 4%, transparent);padding:20px 24px}
  .ph-card > .lbl-cap{margin:0 0 8px;font-size:12px;line-height:1.7}
  .ph-card:empty{display:none}
  /* article body: rail | column */
  main.has-rail{display:grid;grid-template-columns:minmax(0,3fr) minmax(0,7fr);column-gap:64px;align-items:start;max-width:var(--inner-max);margin-left:auto;margin-right:auto}
  main.has-rail > .xi-process-004{margin:0;max-width:var(--measure)}
  main.has-rail > .ia-rail{position:sticky;top:calc(var(--nav-h) + 24px)}
  /* a diagram beside a rail spills RIGHT into the free margin, never left over the rail — the centred
     1280px breakout ran the page 31px past the viewport at 1440 and put the rail under the drawing */
  main.has-rail figure:has(svg.art-svg), main.has-rail .process-fig, main.has-rail .vid-main{--art-w:min(1280px, calc((min(var(--inner-max), 100vw) - 2 * var(--page-x) - 64px) * 0.7));--vw-w:var(--art-w);width:var(--art-w);max-width:none;margin-left:0;margin-right:calc(100% - var(--art-w))}   /* the figure fills its grid track: (inner width − gap) × 7/10, so it never crosses the inner edge at any width */
  main.has-rail .process-fig{width:var(--vw-w);margin-right:calc(100% - var(--vw-w))}
  main.has-rail .vid-main{transform:none}
  main.has-rail .vid-kick{width:100%;margin-left:0;margin-right:0;transform:none}   /* the film's eyebrow carried the film's old centred breakout */
  /* Lab tool pages: hero claim | instrument; body heading | content */
  :is(body.p-lab-loop,body.p-lab-eval,body.p-lab-teardown,body.p-lab-plugin,body.p-fit) .lab-hero .lab-wrap{display:grid;grid-template-columns:minmax(0,7fr) minmax(0,5fr);column-gap:64px;align-items:center}
  :is(body.p-lab-loop,body.p-lab-eval,body.p-lab-teardown,body.p-lab-plugin,body.p-fit) .lab-hero .lab-wrap > *{min-width:0}
  :is(body.p-lab-loop,body.p-lab-eval,body.p-lab-teardown,body.p-lab-plugin,body.p-fit) .lab-hero .lab-lede{max-width:none}
  :is(body.p-lab-loop,body.p-lab-eval,body.p-lab-teardown,body.p-lab-plugin,body.p-fit) main#main > .section:not(.lab-hero) > .lab-wrap{display:grid;grid-template-columns:minmax(0,3fr) minmax(0,7fr);column-gap:64px;grid-auto-flow:row dense;align-items:start}
  :is(body.p-lab-loop,body.p-lab-eval,body.p-lab-teardown,body.p-lab-plugin,body.p-fit) main#main > .section:not(.lab-hero) > .lab-wrap > *{grid-column:2;max-width:none;min-width:0}
  :is(body.p-lab-loop,body.p-lab-eval,body.p-lab-teardown,body.p-lab-plugin,body.p-fit) main#main > .section:not(.lab-hero) > .lab-wrap > :is(h2.section-title,.eyebrow){grid-column:1}
  :is(body.p-lab-loop,body.p-lab-eval,body.p-lab-teardown,body.p-lab-plugin,body.p-fit) main#main > .section:not(.lab-hero) > .lab-wrap > h2.section-title{position:sticky;top:calc(var(--nav-h) + 24px);margin-top:0}   /* the registered h2 size stays — heading-rank-check owns the scale */
  :is(body.p-lab-loop,body.p-lab-eval,body.p-lab-teardown,body.p-lab-plugin,body.p-fit) main#main > .section:not(.lab-hero) > .lab-wrap:has(> :only-child) > *{grid-column:1 / -1}
  /* instruments, code, tables and test lists need the whole width; prose stays in the reading column */
  :is(body.p-lab-loop,body.p-lab-eval,body.p-lab-teardown,body.p-lab-plugin,body.p-fit) main#main > .section:not(.lab-hero) > .lab-wrap > :is(.lab-fn,.lab-tests,pre,.td-block,.td-scroll,.lint-grid,.rule-list,table,figure,.rcpt-box,.fit-results,.fit-form){grid-column:1 / -1}
  /* a heading stays put in a band that holds a spanning instrument — sticky, it slid over the instrument
     as the reader scrolled and its letters landed inside a pressed button (contrast-audit read them as the
     button's ink: 1.34:1). Sticky only where everything else sits in the reading column. */
  :is(body.p-lab-loop,body.p-lab-eval,body.p-lab-teardown,body.p-lab-plugin,body.p-fit) main#main > .section:not(.lab-hero) > .lab-wrap:has(> :is(.lab-fn,.lab-tests,pre,.td-block,.td-scroll,.lint-grid,.rule-list,table,figure,.rcpt-box,.fit-results,.fit-form)) > h2.section-title{position:static}
}
/* ── THE INSTRUMENT PANEL ON PAPER (2026-09-14, contrast-audit: the Fit check's hero is paper, not a bookend,
   and the panel had declared bookend inks — 1.2:1 to 1.9:1). A component declares its ink on its own ground
   (lesson 4): these are the paper values; the bookend values above stay for every dark hero. */
.lab-hero:not([data-ground="bookend"]) .lh-inst{border-color:var(--border-strong);background:var(--surface-card);color:var(--text-body)}
.lab-hero:not([data-ground="bookend"]) .lh-hd{color:var(--text-muted);border-bottom-color:var(--border-strong)}
.lab-hero:not([data-ground="bookend"]) .lh-tally{color:var(--copper-600)}
.lab-hero:not([data-ground="bookend"]) .lh-tally small{color:var(--text-muted)}
.lab-hero:not([data-ground="bookend"]) .lh-foot{color:var(--text-muted)}
.lab-hero:not([data-ground="bookend"]) .lh-foot a{color:var(--accent-text)}
.lab-hero:not([data-ground="bookend"]) .lh-side .ia-k{color:var(--text-faint)}
.lab-hero:not([data-ground="bookend"]) .lh-side .ia-toc{border-left-color:var(--border-strong)}
.lab-hero:not([data-ground="bookend"]) .lh-side .ia-toc li a{color:var(--text-muted)}
.lab-hero:not([data-ground="bookend"]) .lh-side .ia-toc li a:hover{color:var(--accent-text);border-left-color:var(--accent-fill)}
/* trustlint's pressed preset declares its own ink (lesson 4): it read var(--surface-page), which the
   contrast audit's browser resolved to neutral-800 on the amber-700 fill (1.34:1) while the pane showed
   cream. A control's ink on its own fill is a constant, not a page token. */
:where(body.p-lab-eval) .lint-seg button.on{color:var(--neutral-50);background:var(--amber-700);border-color:var(--amber-700)}
}
