/* ONOTO presentation framework — deck.css
   Shared stylesheet for every deck under /present/<slug>/.
   Dark editorial presentation pages: Manrope display, IBM Plex Mono numerals,
   ink ground, mint/cyan/orange accents, 2px radius, hairline rules.
   Load AFTER the Google Fonts link. Pair with ../assets/deck.js. */

:root{
  --ink:#070c0b;
  --ink-soft:#111817;
  --paper:#f1f0e9;
  --white:#fafaf4;
  --mint:#69dfcf;
  --mint-deep:#16a795;
  --cyan:#70d6ef;
  --orange:#ff7047;
  --muted:#68706d;
  --line:rgba(255,255,255,.14);
  --line-2:rgba(255,255,255,.07);
  --radius:2px;
  --head:60px;
  --max:1240px;
  --sans:'Manrope',Inter,ui-sans-serif,system-ui,-apple-system,sans-serif;
  --mono:'IBM Plex Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
}

*{box-sizing:border-box}
/* Snap per slide so a presenter's step is one screen. proximity, not
   mandatory — mandatory fights trackpads when a slide overflows the viewport. */
html{scroll-behavior:smooth;scroll-snap-type:y proximity}
body{margin:0;background:var(--ink);color:var(--paper);font-family:var(--sans);
  line-height:1.5;-webkit-font-smoothing:antialiased}

/* Horizontal-overflow guard. Decorative pseudo-elements bleed past the right
   edge on a narrow viewport (a hero glow at inset:-140px -60px -80px hangs
   out 60px), which made the page scroll 60px sideways at 390px.
   overflow-x:hidden on <body> alone was not enough: it propagates to the
   viewport but STILL leaves a scrollable overflow area — scrollWidth stays
   wide and scrollTo(60,0) really moves the page; a stray trackpad swipe or a
   focus scroll exposes the 60px. overflow-x:clip removes the overflow area
   outright, and — unlike hidden — does not turn the box into a scroll
   container, so it cannot steal the vertical scroll-snap from <html>, cannot
   trap position:fixed chrome, and cannot make <body> monolithic (i.e.
   unfragmentable, one page only) when printing.
   hidden stays as the first declaration on <body> for Safari < 16, which
   drops clip as an invalid value; that is exactly today's behaviour, so old
   Safari cannot regress. It is deliberately NOT restated on <html>: there it
   would add nothing (body already propagates) while risking the old iOS
   "page stops scrolling" bug. */
html{overflow-x:clip}
body{overflow-x:hidden;overflow-x:clip}

a{color:inherit}
img,video{max-width:100%;display:block}
::selection{background:var(--mint);color:var(--ink)}

/* ---------------------------------------------------------------- chrome */
.deck-prog{position:fixed;top:0;left:0;height:2px;z-index:60;width:0;
  background:linear-gradient(90deg,var(--mint),var(--cyan));transition:width .12s linear}

.deck-top{position:fixed;top:0;left:0;right:0;z-index:50;height:var(--head);
  display:flex;align-items:center;gap:18px;padding:0 clamp(16px,3vw,36px);
  background:linear-gradient(180deg,rgba(7,12,11,.95),rgba(7,12,11,.68) 70%,transparent);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px)}
.deck-mark{display:flex;align-items:center;gap:9px;font-weight:800;font-size:14.5px;
  letter-spacing:-.01em;text-decoration:none;flex:none;color:var(--white)}
.deck-mark .dot{width:7px;height:7px;border-radius:50%;background:var(--mint);
  box-shadow:0 0 0 4px rgba(105,223,207,.16)}
.deck-name{font-size:13px;color:var(--muted);flex:none;padding-left:16px;
  border-left:1px solid var(--line-2);white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;max-width:26ch}
/* Long decks overflow this strip; the mask is the only hint that it scrolls. */
.deck-jump{display:flex;gap:1px;margin-left:auto;overflow:auto;scrollbar-width:none;min-width:0;
  scroll-behavior:smooth;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 14px,#000 calc(100% - 14px),transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 14px,#000 calc(100% - 14px),transparent 100%)}
.deck-jump::-webkit-scrollbar{display:none}
.deck-jump a{flex:none;font-size:12px;color:var(--muted);text-decoration:none;
  padding:6px 9px;border-radius:var(--radius);white-space:nowrap;
  transition:color .18s,background .18s}
.deck-jump a:hover{color:var(--paper);background:rgba(255,255,255,.06)}
.deck-jump a.on{color:var(--ink);background:var(--mint);font-weight:700}
@media(max-width:1120px){.deck-jump{display:none}.deck-lang{margin-left:auto}}
@media(max-width:640px){.deck-name{display:none}}

.deck-lang{display:flex;flex:none;gap:2px;padding:3px;border:1px solid var(--line);
  border-radius:var(--radius);background:rgba(255,255,255,.03)}
.deck-lang button{appearance:none;border:0;background:transparent;color:var(--muted);
  cursor:pointer;font:inherit;font-size:12px;font-weight:700;padding:4px 10px;
  border-radius:var(--radius);transition:color .18s,background .18s}
.deck-lang button:hover{color:var(--paper)}
.deck-lang button[aria-pressed="true"]{background:var(--mint);color:var(--ink)}

/* Slide counter — presenter sees where they are and how much is left. */
.deck-count{position:fixed;right:clamp(14px,3vw,32px);bottom:18px;z-index:45;
  font-family:var(--mono);font-size:12px;color:var(--muted);pointer-events:none}
.deck-count b{color:var(--mint);font-weight:600}
@media(max-width:760px){.deck-count{display:none}}

/* ---------------------------------------------------------------- slide */
.wrap{max-width:var(--max);margin:0 auto;width:100%;padding:0 clamp(18px,3.4vw,40px)}
/* overflow-x:clip is the second half of the horizontal-overflow guard at the
   top of this file. A slide box is exactly viewport-wide, so clipping here
   only removes what was already off-screen — no visual change — but it means
   no deck can retrip the bug by overriding html/body overflow. No hidden
   fallback here on purpose: hidden would make every slide a scroll container,
   which would break the vertical scroll-snap and make each slide monolithic
   in print. Browsers without clip just fall back to the body-level guard. */
.slide{position:relative;min-height:100svh;display:flex;align-items:center;
  padding:calc(var(--head) + 14px) 0 30px;scroll-snap-align:start;overflow-x:clip}
.slide+.slide{border-top:1px solid var(--line-2)}
.slide>.wrap{position:relative;z-index:2}

.kicker{display:flex;align-items:baseline;gap:11px;font-size:13px;color:var(--muted);margin-bottom:14px}
.kicker b{font-family:var(--mono);font-size:11.5px;font-weight:600;color:var(--mint)}
.kicker::after{content:"";flex:1;max-width:110px;height:1px;background:var(--line-2);transform:translateY(-4px)}

h1,h2{margin:0;font-weight:750;letter-spacing:-.035em;line-height:1.05}
h2{font-size:clamp(24px,3vw,42px);max-width:26ch}
.lead{font-size:clamp(15px,1.2vw,17.5px);color:#c9cec9;max-width:62ch;margin:16px 0 0;line-height:1.55}
.lead b{color:var(--white);font-weight:700}
.note{font-size:12.5px;color:var(--muted);max-width:80ch;margin:14px 0 0;line-height:1.5}
.num{font-family:var(--mono);font-variant-numeric:tabular-nums}

/* Reveal on enter. deck.js adds .in to the slide; children stagger.
   Forced visible for print and reduced motion below. */
.rv{opacity:0;transform:translateY(16px);
  transition:opacity .55s cubic-bezier(.22,1,.36,1),transform .55s cubic-bezier(.22,1,.36,1)}
.slide.in .rv{opacity:1;transform:none}
.slide.in .rv:nth-child(2){transition-delay:.06s}
.slide.in .rv:nth-child(3){transition-delay:.12s}
.slide.in .rv:nth-child(4){transition-delay:.18s}
.slide.in .rv:nth-child(5){transition-delay:.24s}
.slide.in .rv:nth-child(6){transition-delay:.3s}
@media(prefers-reduced-motion:reduce){.rv{opacity:1;transform:none;transition:none}}

/* ---------------------------------------------------------- title slide */
.slide-title::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(880px 540px at 76% 20%,rgba(105,223,207,.13),transparent 68%),
             radial-gradient(720px 500px at 12% 86%,rgba(112,214,239,.09),transparent 66%)}
.slide-title h1{font-size:clamp(38px,5.4vw,76px);max-width:22ch;font-weight:800;line-height:1.0}
.slide-title h1 em{font-style:normal;color:var(--mint)}
.slide-title .lead{font-size:clamp(16px,1.5vw,20px);margin-top:24px;max-width:54ch}
.title-meta{display:flex;flex-wrap:wrap;gap:8px 26px;margin-top:34px;font-size:13px;color:var(--muted)}
.title-meta i{font-style:normal;color:var(--mint)}
.title-meta .num{font-size:12.5px}

/* ------------------------------------------------------ section divider */
.slide-divider{align-items:center}
.slide-divider .wrap{display:flex;flex-direction:column;gap:10px}
.divider-no{font-family:var(--mono);font-size:clamp(60px,10vw,140px);font-weight:500;
  line-height:1;color:transparent;-webkit-text-stroke:1px rgba(105,223,207,.4)}
.slide-divider h2{font-size:clamp(30px,4.4vw,58px);max-width:20ch}
.slide-divider .lead{max-width:52ch}

/* -------------------------------------------------------------- stat row */
.stat-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
  gap:clamp(18px,3vw,44px);margin-top:34px}
.stat{border-top:1px solid var(--line);padding-top:18px}
.stat .v{font-family:var(--mono);font-size:clamp(30px,3.4vw,50px);font-weight:600;
  letter-spacing:-.04em;line-height:1;color:var(--mint);font-variant-numeric:tabular-nums}
.stat .v small{font-size:.52em;font-weight:500;color:var(--mint-deep);margin-left:2px}
.stat.orange .v{color:var(--orange)}
.stat.orange .v small{color:rgba(255,112,71,.7)}
.stat.plain .v{color:var(--white)}
.stat .l{margin-top:10px;font-size:14.5px;font-weight:650;line-height:1.35;color:var(--paper)}
.stat .s{margin-top:6px;font-size:12.5px;color:var(--muted);line-height:1.45}

/* --------------------------------------------------- two-column media+text */
.two-col{display:grid;grid-template-columns:1.02fr .98fr;gap:clamp(24px,4vw,56px);
  align-items:center;margin-top:30px}
.two-col.flip>.col-media{order:2}
@media(max-width:860px){.two-col{grid-template-columns:1fr;gap:24px}
  .two-col.flip>.col-media{order:0}}
.col-media{border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;
  background:var(--ink-soft)}
.col-media img,.col-media video{width:100%;height:100%;object-fit:cover;aspect-ratio:16/10}
.col-text h3{margin:0;font-size:clamp(19px,1.9vw,26px);font-weight:750;letter-spacing:-.025em;line-height:1.15}
.col-text p{font-size:14.5px;color:#c9cec9;line-height:1.6;margin:12px 0 0}
.col-list{list-style:none;margin:18px 0 0;padding:0}
/* Bullet is absolutely positioned rather than a flex sibling: as a flex item it
   made every inline tag inside the <li> its own column, so <b>/<span> broke the
   sentence apart. */
.col-list li{padding:11px 0 11px 18px;border-top:1px solid var(--line-2);font-size:14px;
  color:#c9cec9;line-height:1.5;position:relative}
.col-list li::before{content:"";position:absolute;left:0;top:18px;width:6px;height:6px;
  border-radius:50%;background:var(--mint)}

/* -------------------------------------------------- full-bleed video slide */
.slide-video{padding:0;display:block}
.slide-video .bleed{position:absolute;inset:0;overflow:hidden;background:var(--ink)}
.slide-video .bleed video,.slide-video .bleed img{width:100%;height:100%;object-fit:cover}
.print-poster{display:none}
.slide-video .bleed::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(7,12,11,.42),transparent 32%,transparent 62%,rgba(7,12,11,.72))}
.slide-video .over{position:absolute;left:0;right:0;bottom:0;z-index:2;
  padding:0 clamp(18px,3.4vw,40px) clamp(26px,4vh,48px)}
.slide-video .over .wrap{padding:0}
.slide-video h2{max-width:22ch;text-shadow:0 2px 24px rgba(7,12,11,.6)}
.caption-chip{display:inline-flex;align-items:center;gap:9px;margin-bottom:14px;
  padding:7px 12px;border:1px solid var(--line);border-radius:var(--radius);
  background:rgba(7,12,11,.7);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  font-family:var(--mono);font-size:11.5px;color:#c9cec9;white-space:nowrap}
.caption-chip .dot{width:6px;height:6px;border-radius:50%;background:var(--mint);flex:none}
.caption-chip.rec .dot{background:var(--orange)}
.caption-chip b{color:var(--white);font-weight:600}

/* -------------------------------------------- phase / pricing cards (3-up) */
.tri{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;margin-top:30px;
  background:var(--line-2);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}
@media(max-width:860px){.tri{grid-template-columns:1fr}}
.pcard{background:var(--ink);padding:24px 22px;display:flex;flex-direction:column;min-height:100%}
.pcard.hi{background:linear-gradient(180deg,rgba(105,223,207,.07),rgba(105,223,207,.015));
  box-shadow:inset 0 2px 0 var(--mint)}
.pcard .tag{font-family:var(--mono);font-size:11.5px;color:var(--muted);margin-bottom:12px}
.pcard.hi .tag{color:var(--mint)}
.pcard .name{font-size:18px;font-weight:750;letter-spacing:-.02em;line-height:1.2}
.pcard .price{font-family:var(--mono);font-size:clamp(24px,2.4vw,34px);font-weight:600;
  letter-spacing:-.03em;color:var(--white);margin-top:12px;font-variant-numeric:tabular-nums}
.pcard .price em{font-style:normal;font-size:13px;color:var(--muted);font-weight:500;margin-left:6px}
.pcard .price.orange{color:var(--orange)}
.pcard ul{list-style:none;margin:16px 0 0;padding:0;flex:1}
.pcard li{padding:9px 0;border-top:1px solid var(--line-2);font-size:13px;
  color:#c9cec9;line-height:1.5}
.pcard li b{color:var(--white);font-weight:650}
.pcard .foot{margin-top:16px;padding-top:12px;border-top:1px solid var(--line-2);
  font-size:11.5px;color:var(--muted);line-height:1.45}

/* ---------------------------------------------------------- evidence card */
.evidence{margin-top:26px;border-left:2px solid var(--mint);padding:4px 0 4px 22px}
.evidence .ev-v{font-family:var(--mono);font-size:clamp(26px,3vw,42px);font-weight:600;
  letter-spacing:-.035em;line-height:1.05;color:var(--mint);font-variant-numeric:tabular-nums}
.evidence.orange{border-left-color:var(--orange)}
.evidence.orange .ev-v{color:var(--orange)}
.evidence .ev-l{margin-top:9px;font-size:15px;font-weight:650;color:var(--paper);line-height:1.4;max-width:56ch}
.evidence .ev-d{margin-top:7px;font-size:13px;color:#c9cec9;line-height:1.55;max-width:66ch}
.evidence .ev-src{margin-top:11px;font-size:11.5px;color:var(--muted)}
.ev-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
  gap:clamp(18px,2.6vw,36px);margin-top:8px}
.ev-grid .evidence{margin-top:18px}

/* --------------------------------------------------------------- timeline */
.timeline{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;margin-top:38px}
@media(max-width:820px){.timeline{grid-auto-flow:row;grid-auto-columns:auto}}
.tl-item{position:relative;padding:22px 22px 0 0;border-top:1px solid var(--line)}
.tl-item::before{content:"";position:absolute;top:-4px;left:0;width:7px;height:7px;
  border-radius:50%;background:var(--mint);box-shadow:0 0 0 4px rgba(105,223,207,.14)}
.tl-item.next::before{background:var(--ink);border:1px solid var(--mint)}
@media(max-width:820px){
  .tl-item{border-top:0;border-left:1px solid var(--line);padding:0 0 26px 22px}
  .tl-item::before{top:0;left:-4px}}
.tl-when{font-family:var(--mono);font-size:12px;color:var(--mint);font-weight:500}
.tl-what{margin-top:7px;font-size:15px;font-weight:700;letter-spacing:-.015em;line-height:1.3}
.tl-d{margin-top:6px;font-size:12.5px;color:var(--muted);line-height:1.5;max-width:30ch}

/* ------------------------------------------------------- comparison table */
.table-wrap{margin-top:28px;overflow-x:auto;border:1px solid var(--line);
  border-radius:var(--radius);-webkit-overflow-scrolling:touch}
table.compare{width:100%;border-collapse:collapse;min-width:640px;background:var(--ink)}
.compare th{text-align:left;font-size:12.5px;font-weight:650;color:var(--muted);
  padding:13px 18px;border-bottom:1px solid var(--line);white-space:nowrap}
.compare th.hi{color:var(--mint)}
.compare td{font-size:13.5px;color:#c9cec9;padding:13px 18px;border-bottom:1px solid var(--line-2);
  line-height:1.45;vertical-align:top}
.compare tr:last-child td{border-bottom:0}
.compare td:first-child{color:var(--paper);font-weight:650}
.compare td.num{font-family:var(--mono);font-size:13px;white-space:nowrap}
.compare .yes{color:var(--mint);font-weight:650}
.compare .no{color:var(--muted)}
.compare .warn{color:var(--orange);font-weight:650}
.compare td.cell-hi{background:rgba(105,223,207,.05)}

/* --------------------------------------------------- BI dashboard panel */
.bi-panel{margin-top:28px;background:var(--ink-soft);border:1px solid var(--line);
  border-radius:var(--radius);overflow:hidden}
.bi-head{display:flex;align-items:center;gap:12px;padding:13px 18px;
  border-bottom:1px solid var(--line-2)}
.bi-head .t{font-size:13.5px;font-weight:700;letter-spacing:-.01em}
.bi-head .live{display:inline-flex;align-items:center;gap:6px;font-family:var(--mono);
  font-size:11px;color:var(--mint)}
.bi-head .live::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--mint);
  animation:bi-pulse 2.2s ease-in-out infinite}
@keyframes bi-pulse{0%,100%{opacity:1}50%{opacity:.35}}
@media(prefers-reduced-motion:reduce){.bi-head .live::before{animation:none}}
.bi-head .ts{margin-left:auto;font-family:var(--mono);font-size:11px;color:var(--muted)}
/* Separators come from the tiles, not from a coloured grid showing through the
   gaps: a tile count that doesn't divide evenly (5 tiles across 4 columns) left
   the unused cells drawn as bordered empty boxes, which read as a broken panel.
   Now an unused cell is just more panel. */
.bi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:1px;
  background:var(--ink-soft);overflow:hidden}
.bi-tile{background:var(--ink-soft);padding:15px 18px 14px;
  box-shadow:1px 0 0 var(--line-2),0 1px 0 var(--line-2)}
.bi-tile .k{font-size:11.5px;color:var(--muted);line-height:1.3}
.bi-tile .v{font-family:var(--mono);font-size:clamp(19px,1.8vw,25px);font-weight:600;
  letter-spacing:-.02em;color:var(--white);margin-top:7px;font-variant-numeric:tabular-nums}
.bi-tile .v small{font-size:.58em;color:var(--muted);font-weight:500}
.bi-tile .d{font-family:var(--mono);font-size:11px;margin-top:6px}
.bi-tile .d.up{color:var(--mint)}
.bi-tile .d.down{color:var(--orange)}
.bi-rows{border-top:1px solid var(--line-2)}
.bi-row{display:grid;grid-template-columns:minmax(130px,1.4fr) minmax(90px,1fr) minmax(80px,1fr) auto;
  gap:14px;align-items:center;padding:10px 18px;border-bottom:1px solid var(--line-2);
  font-size:12.5px;color:#c9cec9}
.bi-row:last-child{border-bottom:0}
.bi-row .who{font-weight:650;color:var(--paper)}
.bi-row .num{font-family:var(--mono);font-size:11.5px;color:var(--muted)}
.bi-row .chip{justify-self:end;font-family:var(--mono);font-size:10.5px;padding:3px 8px;
  border-radius:var(--radius);white-space:nowrap}
.bi-row .chip.ok{background:rgba(105,223,207,.13);color:var(--mint)}
.bi-row .chip.warn{background:rgba(255,112,71,.13);color:var(--orange)}
.bi-row .chip.idle{background:rgba(255,255,255,.06);color:var(--muted)}
@media(max-width:680px){.bi-row{grid-template-columns:1fr auto}
  .bi-row .num:nth-child(3),.bi-row .num:nth-child(2){display:none}}

/* ------------------------------------------------ inline-SVG chart block */
.chart{margin-top:28px}
.chart svg{display:block;width:100%;height:auto}
.chart .c-title{font-size:13px;font-weight:700;color:var(--paper);margin:0 0 14px}
.chart .c-src{font-size:11.5px;color:var(--muted);margin:10px 0 0}
/* Utility classes for the SVG itself — mint/cyan/orange on dark, mono axis
   numerals, no gridline clutter (one baseline, hairline ticks at most). */
svg .ax{font-family:var(--mono);font-size:11px;fill:var(--muted)}
svg .ax-b{font-family:var(--mono);font-size:11px;fill:var(--paper)}
svg .lbl{font-family:var(--sans);font-size:12px;fill:#c9cec9}
svg .val{font-family:var(--mono);font-size:13px;font-weight:600;fill:var(--white)}
svg .val-mint{font-family:var(--mono);font-size:13px;font-weight:600;fill:var(--mint)}
svg .val-orange{font-family:var(--mono);font-size:13px;font-weight:600;fill:var(--orange)}
svg .ln-mint{stroke:var(--mint);fill:none;stroke-width:2;stroke-linecap:round}
svg .ln-cyan{stroke:var(--cyan);fill:none;stroke-width:2;stroke-linecap:round}
svg .ln-orange{stroke:var(--orange);fill:none;stroke-width:2;stroke-linecap:round}
svg .ln-base{stroke:var(--line);stroke-width:1}
svg .ln-hair{stroke:var(--line-2);stroke-width:1}
svg .bar-mint{fill:rgba(105,223,207,.75)}
svg .bar-cyan{fill:rgba(112,214,239,.75)}
svg .bar-orange{fill:rgba(255,112,71,.8)}
svg .bar-dim{fill:rgba(255,255,255,.10)}
svg .area-mint{fill:rgba(105,223,207,.12)}
svg .dot-mint{fill:var(--mint)}
svg .dot-orange{fill:var(--orange)}

/* ------------------------------------------------------------------ quote */
.quote{margin:30px 0 0;max-width:34ch}
.quote p{margin:0;font-size:clamp(22px,2.8vw,38px);font-weight:700;
  letter-spacing:-.03em;line-height:1.18;color:var(--white)}
.quote p em{font-style:normal;color:var(--mint)}
.quote footer{margin-top:20px;font-size:13.5px;color:var(--paper);font-weight:650}
.quote footer span{display:block;margin-top:3px;font-size:12.5px;color:var(--muted);font-weight:450}

/* -------------------------------------------------------------- CTA slide */
.slide-cta .wrap{display:flex;flex-direction:column;align-items:center;text-align:center}
.slide-cta h2{max-width:19ch;font-size:clamp(30px,4.6vw,56px)}
.slide-cta .lead{margin-top:20px;max-width:48ch}
.btn{display:inline-flex;align-items:center;gap:10px;margin-top:32px;padding:15px 30px;
  border-radius:var(--radius);background:var(--mint);color:var(--ink);font-weight:750;
  font-size:15px;text-decoration:none;transition:transform .2s,box-shadow .2s}
.btn:hover{transform:translateY(-2px);box-shadow:0 14px 40px rgba(105,223,207,.22)}
.btn.ghost{background:transparent;color:var(--paper);border:1px solid var(--line)}
.btn.ghost:hover{box-shadow:none;border-color:var(--mint);color:var(--mint)}
.cta-foot{margin-top:46px;display:flex;gap:10px 26px;flex-wrap:wrap;justify-content:center;
  font-size:12px;color:var(--muted)}

/* -------------------------------------------------- short laptop screens */
@media(max-height:790px){
  .slide{padding:calc(var(--head) + 10px) 0 22px}
  h2{font-size:clamp(22px,2.5vw,34px)}
  .slide-title h1{font-size:clamp(34px,4.6vw,60px)}
  .slide-title .lead{margin-top:18px}
  .lead{margin-top:12px}
  .stat-row{margin-top:24px}
  .stat .v{font-size:clamp(26px,3vw,42px)}
  .tri,.two-col,.timeline,.bi-panel,.table-wrap,.chart{margin-top:20px}
  .pcard{padding:18px 18px 16px}
  .bi-tile{padding:12px 15px 11px}
}

/* -------------------------------------------------------------------- print
   The PDF leave-behind: one slide per page. The deck stays dark on paper on
   purpose — the panels, charts and chips are all authored light-on-dark.
   Written defensively: a slide must never print BLANK (a .rv element that was
   never revealed), BLACK (a <video> with no poster still) or TRUNCATED (a
   scroll container is monolithic in paged media and can swallow every page
   after the first). */

/* ------------------------------------------------ app window (product UI)
   A real SaaS application screenshot: browser chrome, a left nav rail, a page
   header with breadcrumb and actions, a filter toolbar, KPI cards with deltas
   and sparklines, and a sortable data table with status pills and pagination.
   The earlier version framed a flat slide block in a browser bar and still read
   as a slide — the interior is what makes it read as software, not the frame.
   Markup contract: docs/PRESENT-APP-UI.md. No JavaScript: these print to PDF. */
.app{margin-top:12px;border:1px solid rgba(255,255,255,.13);border-radius:9px;
  overflow:hidden;background:#0c1211;
  box-shadow:0 22px 50px rgba(0,0,0,.55),0 1px 0 rgba(255,255,255,.045) inset}

/* browser chrome */
.app-bar{display:flex;align-items:center;gap:13px;padding:7px 12px;
  background:linear-gradient(180deg,#171e1d,#121918);border-bottom:1px solid rgba(255,255,255,.07)}
.app-dots{display:flex;gap:6px;flex:none}
.app-dots i{width:9px;height:9px;border-radius:50%;display:block}
.app-dots i:nth-child(1){background:#e0564f}
.app-dots i:nth-child(2){background:#dda32c}
.app-dots i:nth-child(3){background:#28a745}
.app-url{flex:1;min-width:0;display:flex;align-items:center;gap:7px;
  background:rgba(0,0,0,.4);border:1px solid rgba(255,255,255,.07);border-radius:5px;
  padding:4px 11px;font-family:var(--mono);font-size:11px;color:#8d9994;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.app-url::before{content:"";flex:none;width:7px;height:9px;border-radius:1.5px;
  border:1.3px solid #76837e;border-top-width:4.5px;border-top-left-radius:4px;border-top-right-radius:4px}
.app-url b{color:#dfe5e1;font-weight:600}
.app-bar .app-tools{flex:none;display:flex;gap:8px;opacity:.45}
.app-bar .app-tools i{width:12px;height:2px;background:#8b968f;border-radius:2px;display:block}

/* two-pane application body */
.app-shell{display:flex;align-items:stretch}
.ic{width:15px;height:15px;flex:none;stroke:currentColor;fill:none;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round}

/* left nav rail */
.app-side{width:186px;flex:none;background:#0a100f;border-right:1px solid rgba(255,255,255,.06);
  display:flex;flex-direction:column;padding:9px 8px 8px}
.side-ws{display:flex;align-items:center;gap:8px;padding:5px 7px 9px;
  border-bottom:1px solid rgba(255,255,255,.06);margin-bottom:8px}
.side-ws .mk{width:19px;height:19px;border-radius:5px;background:var(--mint);
  color:#04100d;font-weight:800;font-size:11px;display:flex;align-items:center;
  justify-content:center;flex:none}
.side-ws .nm{font-size:12.5px;font-weight:700;color:var(--white);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.side-ws .cv{margin-left:auto;width:0;height:0;border:3.5px solid transparent;
  border-top-color:#5e6b66;flex:none;margin-top:3px}
.side-q{display:flex;align-items:center;gap:6px;margin:0 1px 10px;padding:5px 8px;
  border:1px solid rgba(255,255,255,.07);border-radius:6px;background:rgba(255,255,255,.02);
  font-size:11.5px;color:#5e6b66}
.side-q kbd{margin-left:auto;font-family:var(--mono);font-size:9.5px;color:#4e5a56;
  border:1px solid rgba(255,255,255,.08);border-radius:3px;padding:1px 4px}
.side-sec{font-size:10px;color:#4e5a56;letter-spacing:.04em;padding:8px 8px 4px;font-weight:600}
.side-nav{display:flex;flex-direction:column;gap:1px}
.side-nav a{display:flex;align-items:center;gap:9px;padding:6px 8px;border-radius:6px;
  font-size:12.5px;color:#93a09a;text-decoration:none;position:relative}
.side-nav a .ic{opacity:.8}
.side-nav a.on{background:rgba(255,255,255,.065);color:var(--white);font-weight:600}
.side-nav a.on::before{content:"";position:absolute;left:-8px;top:6px;bottom:6px;width:2px;
  background:var(--mint);border-radius:0 2px 2px 0}
.side-nav a.on .ic{opacity:1;color:var(--mint)}
.side-nav .ct{margin-left:auto;font-family:var(--mono);font-size:10px;color:#6c7873;
  background:rgba(255,255,255,.06);border-radius:9px;padding:1px 6px}
.side-nav a.on .ct{background:rgba(105,223,207,.16);color:var(--mint)}
.side-foot{margin-top:auto;display:flex;align-items:center;gap:8px;padding:8px 7px 2px;
  border-top:1px solid rgba(255,255,255,.06)}
.side-foot .av{width:22px;height:22px;border-radius:50%;background:rgba(105,223,207,.16);
  color:var(--mint);font-family:var(--mono);font-size:9.5px;font-weight:600;
  display:flex;align-items:center;justify-content:center;flex:none}
.side-foot .who{min-width:0;line-height:1.25}
.side-foot .who b{display:block;font-size:11.5px;color:#dfe5e1;font-weight:600;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.side-foot .who span{display:block;font-size:10px;color:#5e6b66}

/* main pane */
.app-main{flex:1;min-width:0;display:flex;flex-direction:column;background:#0c1211}
.app-head{display:flex;align-items:flex-end;gap:14px;padding:11px 16px 10px;
  border-bottom:1px solid rgba(255,255,255,.06)}
.app-crumb{font-size:10.5px;color:#5e6b66;margin-bottom:3px}
.app-crumb i{font-style:normal;padding:0 5px;opacity:.6}
.app-h1{font-size:16.5px;font-weight:700;letter-spacing:-.015em;color:var(--white);margin:0}
.app-head .hact{margin-left:auto;display:flex;align-items:center;gap:7px;flex:none}
.btn-s{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;font-weight:600;
  color:#c2cac6;border:1px solid rgba(255,255,255,.11);border-radius:6px;padding:5px 10px;
  background:rgba(255,255,255,.02);white-space:nowrap}
.btn-s.pri{background:var(--mint);border-color:var(--mint);color:#04100d}
.btn-s .cv{width:0;height:0;border:3.5px solid transparent;border-top-color:currentColor;
  margin-top:3px;opacity:.7}

/* filter toolbar */
.app-tb{display:flex;align-items:center;gap:8px;padding:9px 16px;
  border-bottom:1px solid rgba(255,255,255,.06);background:rgba(255,255,255,.012)}
.seg{display:flex;border:1px solid rgba(255,255,255,.1);border-radius:6px;overflow:hidden;flex:none}
.seg span{font-size:11.5px;color:#93a09a;padding:4px 10px;font-weight:600}
.seg span+span{border-left:1px solid rgba(255,255,255,.08)}
.seg span.on{background:rgba(255,255,255,.08);color:var(--white)}
.fchip{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;color:#a9b3ae;
  border:1px dashed rgba(255,255,255,.16);border-radius:6px;padding:4px 9px;white-space:nowrap}
.fchip.set{border-style:solid;border-color:rgba(105,223,207,.4);color:var(--mint);
  background:rgba(105,223,207,.07)}
.app-tb .tbr{margin-left:auto;display:flex;align-items:center;gap:8px;flex:none}
.tsearch{display:flex;align-items:center;gap:6px;border:1px solid rgba(255,255,255,.1);
  border-radius:6px;padding:4px 9px;font-size:11.5px;color:#5e6b66;min-width:132px}

/* content area */
.app-ct{padding:11px 16px 12px;display:flex;flex-direction:column;gap:10px}

/* KPI cards */
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));gap:9px}
.kpi{border:1px solid rgba(255,255,255,.075);border-radius:8px;padding:10px 12px 9px;
  background:linear-gradient(180deg,rgba(255,255,255,.028),rgba(255,255,255,.012));
  display:flex;flex-direction:column;gap:3px;min-width:0}
.kpi .l{font-size:11px;color:#8d9994;display:flex;align-items:center;gap:5px}
.kpi .vrow{display:flex;align-items:baseline;gap:7px;flex-wrap:wrap}
.kpi .v{font-family:var(--mono);font-size:23px;font-weight:600;letter-spacing:-.03em;
  color:var(--white);line-height:1.1;font-variant-numeric:tabular-nums}
.kpi .v small{font-size:.5em;font-weight:500;color:#8d9994;margin-left:1px}
.kpi .dlt{display:inline-flex;align-items:center;gap:3px;font-family:var(--mono);
  font-size:10.5px;font-weight:600;border-radius:4px;padding:1px 5px}
.kpi .dlt.up{color:#4ad3b4;background:rgba(74,211,180,.12)}
.kpi .dlt.dn{color:#ef8a5f;background:rgba(239,138,95,.12)}
.kpi .dlt.fl{color:#8d9994;background:rgba(255,255,255,.06)}
.kpi .sub{font-size:10.5px;color:#6c7873;margin-top:1px}
.kpi .spark{margin-top:4px;height:20px;width:100%;display:block;overflow:visible}
.kpi .spark path{fill:none;stroke:var(--mint);stroke-width:1.5;
  stroke-linecap:round;stroke-linejoin:round}
.kpi .spark path.fill{fill:rgba(105,223,207,.11);stroke:none}
.kpi.warn .v{color:#ffb08a}

/* data table */
.dtw{border:1px solid rgba(255,255,255,.075);border-radius:8px;overflow:hidden;
  background:rgba(255,255,255,.012)}
.dth{display:flex;align-items:center;gap:9px;padding:9px 13px;
  border-bottom:1px solid rgba(255,255,255,.06)}
.dth .t{font-size:12.5px;font-weight:700;color:#dfe5e1}
.dth .ct{font-family:var(--mono);font-size:10.5px;color:#6c7873;
  background:rgba(255,255,255,.06);border-radius:9px;padding:1px 7px}
.dth .r{margin-left:auto;display:flex;gap:7px;align-items:center}
.dt{width:100%;border-collapse:collapse}
.dt th{text-align:left;font-size:10.5px;font-weight:600;color:#6c7873;padding:7px 13px;
  border-bottom:1px solid rgba(255,255,255,.055);white-space:nowrap}
.dt th .cv{display:inline-block;width:0;height:0;border:3px solid transparent;
  border-top-color:#5e6b66;margin-left:5px;vertical-align:middle}
.dt th.num,.dt td.num{text-align:right;font-family:var(--mono);font-variant-numeric:tabular-nums}
.dt td{font-size:12.5px;color:#c2cac6;padding:7px 13px;
  border-bottom:1px solid rgba(255,255,255,.035);white-space:nowrap}
.dt tr:last-child td{border-bottom:0}
.dt tbody tr.hl{background:rgba(255,255,255,.022)}
.dt td b{color:var(--white);font-weight:600}
.dt td .mut{color:#6c7873}
.dt .who{display:flex;align-items:center;gap:8px}
.dt .who .av{width:20px;height:20px;border-radius:50%;flex:none;
  background:rgba(255,255,255,.07);color:#a9b3ae;font-family:var(--mono);
  font-size:9px;display:flex;align-items:center;justify-content:center}
.pill{display:inline-flex;align-items:center;gap:5px;font-size:10.5px;font-weight:600;
  border-radius:11px;padding:2px 8px;white-space:nowrap}
.pill::before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor}
.pill.ok{color:#4ad3b4;background:rgba(74,211,180,.12)}
.pill.warn{color:#f0b463;background:rgba(240,180,99,.13)}
.pill.bad{color:#ef8a5f;background:rgba(239,138,95,.13)}
.pill.neu{color:#93a09a;background:rgba(255,255,255,.07)}
.rowact{color:#5e6b66;letter-spacing:1px;font-weight:700}
.dtf{display:flex;align-items:center;gap:10px;padding:8px 13px;
  border-top:1px solid rgba(255,255,255,.055);font-size:11px;color:#6c7873}
.dtf .pg{margin-left:auto;display:flex;gap:5px;align-items:center}
.dtf .pg i{font-style:normal;border:1px solid rgba(255,255,255,.1);border-radius:5px;
  padding:2px 7px;color:#93a09a}
.dtf .pg i.on{background:rgba(255,255,255,.07);color:var(--white)}

/* caption under the window */
.app-cap{margin-top:9px;font-size:12.5px;color:var(--muted);line-height:1.5}
.app-cap b{color:#c9cec9;font-weight:600}

/* legacy: a plain .bi-panel dropped inside the window keeps working */
.app .bi-panel{margin-top:0;border:0;border-radius:0;background:transparent}
.app .bi-head{background:rgba(255,255,255,.012);padding:11px 18px}
.app .bi-tile{padding:12px 16px 11px}

@media(max-width:820px){
  .app-side{display:none}
  .app-tb{flex-wrap:wrap}
  .app-url{font-size:10px}
}


/* ------------------------------------------------------------ lightbox */
.slide img:not(.print-poster),.slide video{cursor:zoom-in}
.deck-lightbox{position:fixed;inset:0;z-index:90;display:none;align-items:center;justify-content:center;
  background:rgba(4,8,7,.94);padding:clamp(16px,4vw,48px);cursor:zoom-out;
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.deck-lightbox.on{display:flex}
.deck-lightbox .lb-inner{max-width:100%;max-height:100%;display:flex}
.deck-lightbox img{max-width:min(96vw,1600px);max-height:92vh;width:auto;height:auto;
  object-fit:contain;border-radius:4px;box-shadow:0 30px 80px rgba(0,0,0,.7)}
.deck-lightbox .lb-hint{position:fixed;top:16px;right:20px;font-family:var(--mono);font-size:11px;
  color:var(--muted);border:1px solid var(--line);border-radius:4px;padding:3px 7px}
@media print{.deck-lightbox{display:none !important}.slide img,.slide video{cursor:auto}}

@media print{
  /* Slide layouts are wide — ask for landscape; the print dialog can still
     override it. It is also what makes the 640px comparison table and the
     3-up card row fit a page without reflowing. */
  @page{size:landscape;margin:12mm}

  html{scroll-snap-type:none;scroll-behavior:auto}
  /* Ground on both boxes: the root background becomes the page canvas, and
     body's own box still covers the content area of every page if a browser
     declines to paint that canvas. */
  html,body{background:var(--ink) !important}
  /* Drop the screen-side overflow-x:hidden for paper. hidden makes the box a
     scroll container and a scroll container is monolithic — on <body> that can
     cut the deck down to its first page. clip keeps the horizontal guard with
     no scroll container; browsers without clip simply print overflow:visible,
     which at worst lets a decorative glow run to the page edge. */
  html,body{overflow:visible !important;overflow-x:clip !important}
  *{print-color-adjust:exact;-webkit-print-color-adjust:exact}
  /* Nothing may be captured mid-transition on paper. */
  *,*::before,*::after{transition:none !important}
  /* Hairlines and the muted grey are tuned for a backlit screen — 7% white on
     ink is invisible in ink. Restate the three tokens once and every border,
     table rule, tile separator, caption and chart axis follows. */
  :root{--line:rgba(255,255,255,.32);--line-2:rgba(255,255,255,.17);--muted:#949b97}

  .deck-top,.deck-count,.deck-prog{display:none !important}

  /* One slide per page. Break BEFORE every slide except the first, never
     after. The old rule broke AFTER every slide and cancelled it with
     .slide:last-child — which never matched, because the last child of <body>
     is the <script> tag, not a slide, so every deck printed a trailing blank
     page. `.slide ~ .slide` is exactly "every slide but the first", whatever
     element type a deck used, so there is no leading blank page either.
     display:block because flex fragmentation is unreliable; with min-height:0
     the flex centring was a no-op anyway. */
  .slide{min-height:0;padding:28px 0;border-top:0;display:block;
    scroll-snap-align:none;
    break-before:auto;page-break-before:auto;
    break-after:auto;page-break-after:auto}
  /* .slide{border-top:0} above cannot reach this — .slide+.slide outranks a
     lone .slide — so every page after the first was ruled at the very top. */
  .slide+.slide{border-top:0}
  .slide ~ .slide{break-before:page;page-break-before:always}

  /* overflow:hidden makes these scroll containers, and a scroll container is
     monolithic in paged media: it cannot be split, so a tall one is clipped at
     the page edge instead of flowing on. clip clips identically (rounded
     corners included) without becoming a scroll container. */
  .tri,.col-media,.bi-panel,.bi-grid{overflow:clip}

  /* Keep a component whole rather than sliced by a page break. */
  .stat,.pcard,.evidence,.tl-item,.quote,.chart,.bi-panel,.bi-row,.col-media,
  .caption-chip,.two-col,.table-wrap{break-inside:avoid;page-break-inside:avoid}
  .compare tr{break-inside:avoid;page-break-inside:avoid}
  h1,h2,.col-text h3,.kicker,.bi-head{break-after:avoid;page-break-after:avoid}
  p,li,.lead,.note{orphans:2;widows:2}

  /* The single biggest print risk. .rv is opacity:0 until deck.js adds .in to
     its slide, so every slide that was never scrolled past would otherwise
     print as an empty page. Force the revealed end state, and force it hard:
     !important also beats a deck's inline style="opacity:0". Descendants are
     deliberately left alone so genuinely translucent decoration keeps its
     opacity — only the reveal state itself is overridden. */
  .rv{opacity:1 !important;transform:none !important;filter:none !important;
    visibility:visible !important;transition:none !important;animation:none !important}

  /* A <video> prints as a black box, so each one carries a sibling
     <img class="print-poster"> of its poster frame (see
     docs/PRESENT-FRAMEWORK.md) and print swaps the two —
     everywhere, not just in full-bleed video slides. Both halves of the swap
     are !important: the video is force-hidden, so anything still holding the
     poster hidden would leave an empty well. */
  video{display:none !important}
  .print-poster{display:block !important;width:100%;height:auto;max-height:58vh;
    object-fit:cover;margin-inline:auto}
  /* Inside a two-column media well the poster inherits the video's framing.
     Stated explicitly so it does not depend on .col-media img out-specifying
     .print-poster. */
  .col-media .print-poster{width:100%;height:100%;max-height:none;
    aspect-ratio:16/10;object-fit:cover}

  /* Full-bleed video slide becomes a still above its headline. The bleed is
     height:auto, not a fixed 60vh: it sizes to the poster (capped so still +
     headline stay on one page) and, if a deck ever ships a video with no
     poster sibling, it collapses to nothing and the slide prints its chip and
     headline instead of a black rectangle. clip, not hidden, so the bleed
     never becomes a monolithic scroll container. */
  .slide-video{padding:28px 0}
  .slide-video .bleed{position:relative;inset:auto;height:auto;max-height:58vh;
    overflow:clip;background:var(--ink)}
  .slide-video .bleed::after{display:none}
  .slide-video .bleed .print-poster{width:auto;max-width:100%;height:auto;
    max-height:58vh;object-fit:contain;margin-inline:auto}
  .slide-video .over{position:relative;padding:16px 0 0}
  /* The screen rule zeroes this .wrap's padding because the .over strip
     carries it; once .over is in flow the text would sit flush to the page
     edge, out of line with every other slide. */
  .slide-video .over .wrap{padding:0 clamp(18px,3.4vw,40px)}
  .slide-video h2{text-shadow:none}
  /* backdrop-filter has no backdrop to sample on paper and can render as a
     grey or black plate. */
  .caption-chip{backdrop-filter:none;-webkit-backdrop-filter:none;
    background:rgba(7,12,11,.9)}

  /* .table-wrap is a horizontal scroll container on screen, so in print it is
     monolithic: everything past the page edge would be silently cut off, and
     the table's own min-width:640px guarantees that on portrait paper. Unroll
     the scroller and let the table reflow to the page. */
  .table-wrap{overflow:visible !important;-webkit-overflow-scrolling:auto}
  table.compare{min-width:0;width:100%}
  .compare th,.compare td{padding:9px 12px;white-space:normal}
  .compare th{font-size:11.5px}
  .compare td{font-size:12px}
  .compare td.num{white-space:nowrap}

  /* Charts: keep the SVG inside the page box whatever width it was authored
     at. The axis/label colours ride on --muted, lightened above. */
  .chart svg{max-width:100%;height:auto}

  /* The live dot animates between opacity 1 and .35 — a print snapshot can
     catch it faded. The tile separators are box-shadows, which print because
     of print-color-adjust:exact above and are now drawn with the stronger
     --line-2. */
  .bi-head .live::before{animation:none !important;opacity:1 !important}

  /* Transparent text with a -webkit-text-stroke is unreliable on paper —
     several engines print nothing at all, leaving a numberless divider
     slide. Fill it instead. */
  .divider-no{-webkit-text-stroke:0;color:rgba(105,223,207,.62)}


  /* App window on paper: keep the chrome (it is the point of the component),
     drop the shadow, and stop the tab strip clipping if it is mid-scroll. */
  .app{box-shadow:none;break-inside:avoid;page-break-inside:avoid}
  .app-tabs{overflow:visible}
  .btn{box-shadow:none}
}

/* ==========================================================================
   CHART SYSTEM
   Validated categorical palette. The five slots were generated in OKLCH at
   L=0.665 and pass all six checks against this deck surface (#070c0b):
   lightness band, chroma floor, CVD separation, normal-vision floor, contrast.
   Re-validate before adding any colour:
     node validate_palette.js "#05ab96,#e26c3b,#3d96f2,#a39615,#d766a8" \
       --mode dark --surface "#070c0b"

   Why not the brand mint/cyan: as two adjacent series they measure deltaE 6.0
   for NORMAL vision (floor is 15) and 1.3 under tritanopia — genuinely
   indistinguishable. Mint keeps its job as the UI/text accent; it is not a
   series fill. Text always wears text tokens, never a series colour.
   ========================================================================== */
:root{
  --c1:#05ab96; --c2:#e26c3b; --c3:#3d96f2; --c4:#a39615; --c5:#d766a8;
  /* Status is reserved — never reused as "series 5", always shipped with a label. */
  --st-good:#05ab96; --st-warn:#a39615; --st-bad:#e26c3b; --st-crit:#ff5c5c;
  --grid:rgba(255,255,255,.09);
}
/* Series slots are assigned in FIXED ORDER and follow the entity, never its
   rank — a filter that drops a series must not repaint the survivors. */
.s1{--c:var(--c1)} .s2{--c:var(--c2)} .s3{--c:var(--c3)}
.s4{--c:var(--c4)} .s5{--c:var(--c5)}
.good{--c:var(--st-good)} .warn{--c:var(--st-warn)}
.bad{--c:var(--st-bad)} .crit{--c:var(--st-crit)}
/* Legacy aliases so decks authored before this system keep rendering. */
.bar-mint{--c:var(--c1)} .bar-orange{--c:var(--c2)}

/* ---------------------------------------------------------- figure wrapper */
.fig{margin-top:26px}
.fig-h{font-size:14px;font-weight:700;color:var(--paper);margin:0}
.fig-sub{font-size:12.5px;color:var(--muted);margin:5px 0 0;line-height:1.45}
.fig-plot{margin-top:16px}
.fig-note{margin-top:12px;font-size:11.5px;color:var(--muted);line-height:1.45}
.fig svg{display:block;width:100%;height:auto;overflow:visible}

/* Legend: always present for 2+ series, so identity is never colour-alone. */
.fig-key{display:flex;flex-wrap:wrap;gap:8px 20px;margin-top:14px}
.fig-key span{display:inline-flex;align-items:center;gap:8px;font-size:12px;color:#c9cec9}
.fig-key i{width:10px;height:10px;border-radius:2px;background:var(--c);flex:none}

/* --------------------------------------------- horizontal bars (magnitude)
   HTML/CSS rather than SVG: it reflows, it never mis-scales, and it prints
   reliably. Sort rows by value; the width is set inline as a percentage. */
.hbar{display:grid;gap:11px}
.hbar-row{display:grid;grid-template-columns:minmax(96px,20ch) 1fr auto;
  align-items:center;gap:14px}
.hbar-l{font-size:13px;color:#c9cec9;line-height:1.3}
.hbar-track{position:relative;height:16px;background:rgba(255,255,255,.05);
  border-radius:2px;overflow:hidden}
.hbar-fill{position:absolute;inset:0 auto 0 0;background:var(--c);
  border-radius:0 3px 3px 0}
.hbar-v{font-family:var(--mono);font-size:13px;font-weight:600;color:var(--white);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.hbar-row.muted .hbar-fill{background:rgba(255,255,255,.16)}
.hbar-row.muted .hbar-v{color:var(--muted)}

/* ------------------------------------------- dumbbell (before vs after)
   The most persuasive form for "today vs with ONOTO": one row per measure,
   two dots joined by a connector, both ends labelled. */
.dmb{display:grid;gap:16px}
.dmb-row{display:grid;grid-template-columns:minmax(96px,22ch) 1fr;
  align-items:center;gap:16px}
.dmb-l{font-size:13px;color:#c9cec9;line-height:1.3}
.dmb-track{position:relative;height:38px}
.dmb-track::before{content:"";position:absolute;left:0;right:0;top:22px;height:1px;
  background:var(--grid)}
.dmb-line{position:absolute;top:21px;height:3px;border-radius:2px;
  background:linear-gradient(90deg,var(--st-bad),var(--c1))}
.dmb-pt{position:absolute;top:16px;width:13px;height:13px;border-radius:50%;
  transform:translateX(-50%);
  /* 2px surface ring so overlapping marks stay separable */
  box-shadow:0 0 0 2px var(--ink)}
.dmb-pt.a{background:var(--st-bad)} .dmb-pt.b{background:var(--c1)}
.dmb-cap{position:absolute;top:-3px;font-family:var(--mono);font-size:11.5px;
  font-variant-numeric:tabular-nums;transform:translateX(-50%);white-space:nowrap}
.dmb-cap.a{color:var(--st-bad)} .dmb-cap.b{color:var(--c1)}

/* --------------------------------------------------- columns (few periods) */
.cols{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;
  align-items:end;gap:clamp(6px,1vw,14px);height:150px;
  border-bottom:1px solid var(--grid);padding-bottom:0}
.col-b{position:relative;display:flex;flex-direction:column;justify-content:flex-end;height:100%}
.col-fill{background:var(--c);border-radius:3px 3px 0 0;min-height:2px;
  width:100%;max-width:74px;margin-inline:auto}
.col-v{font-family:var(--mono);font-size:11.5px;color:var(--white);
  font-variant-numeric:tabular-nums;text-align:center;margin-bottom:5px}
.col-x{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;
  gap:clamp(6px,1vw,14px);margin-top:8px}
.col-x span{font-family:var(--mono);font-size:11px;color:var(--muted);text-align:center}

/* ------------------------------------------------------------ donut (share)
   Only for <=4 slices with one dominant; beyond that a bar reads better.
   r=54 so the circumference is 339.29 — dasharray is (share*339.29) 339.29. */
.donut-wrap{display:flex;align-items:center;gap:clamp(18px,3vw,40px);flex-wrap:wrap}
/* Specificity guard: `.fig svg{width:100%}` outranks a bare `.donut`, which
   stretched the donut to the full column width. Qualify it so it cannot. */
.donut,.fig .donut{flex:none;width:150px;height:150px;min-width:150px;
  transform:rotate(-90deg)}
.donut circle{fill:none;stroke-width:18}
.donut .bg{stroke:rgba(255,255,255,.06)}
.donut-list{display:grid;gap:9px;min-width:190px;flex:1}
.donut-item{display:grid;grid-template-columns:auto 1fr auto;align-items:center;
  gap:10px;font-size:12.5px;color:#c9cec9}
.donut-item i{width:10px;height:10px;border-radius:2px;background:var(--c)}
.donut-item b{font-family:var(--mono);font-weight:600;color:var(--white);
  font-variant-numeric:tabular-nums}

/* ------------------------------------------------- line / area (over time) */
.plot-grid line{stroke:var(--grid);stroke-width:1}
.plot-axis text{font-family:var(--mono);font-size:11px;fill:var(--muted)}
.plot-line{fill:none;stroke:var(--c);stroke-width:2;
  stroke-linejoin:round;stroke-linecap:round}
.plot-area{fill:var(--c);opacity:.14}
.plot-dot{fill:var(--c);stroke:var(--ink);stroke-width:2}
.plot-lbl{font-family:var(--mono);font-size:11.5px;fill:var(--white);
  font-variant-numeric:tabular-nums}

/* ------------------------------------------------------- small multiples */
.smul{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
  gap:clamp(14px,2vw,26px);margin-top:18px}
.smul .fig{margin-top:0}
.smul .fig-h{font-size:12.5px}

/* ------------------------------------ diagram surface (process / flow / zone)
   For a system or a process — which is a diagram, not a chart. */
.diagram{margin-top:24px;border:1px solid var(--line-2);border-radius:var(--radius);
  background:rgba(255,255,255,.015);padding:clamp(16px,2.4vw,28px)}
.diagram svg{display:block;width:100%;height:auto}
.dg-box{fill:var(--ink-soft);stroke:var(--line)}
.dg-box.on{fill:rgba(5,171,150,.12);stroke:var(--c1)}
.dg-t{font-family:var(--sans);font-size:12.5px;font-weight:650;fill:var(--paper)}
.dg-s{font-family:var(--sans);font-size:11px;fill:var(--muted)}
.dg-flow{stroke:var(--c1);stroke-width:1.5;fill:none;marker-end:url(#dg-arrow)}
.dg-flow.dim{stroke:var(--line);}

@media print{
  /* Charts must survive pagination: keep a figure whole and keep its ink. */
  .fig,.diagram,.donut-wrap,.hbar,.dmb,.cols{break-inside:avoid;page-break-inside:avoid}
  .fig svg,.diagram svg{max-width:100%;height:auto}
  .hbar-track{background:rgba(255,255,255,.09)}
  .cols{border-bottom-color:rgba(255,255,255,.28)}
  .plot-grid line{stroke:rgba(255,255,255,.22)}
}
