@import url('fonts.css');

/* =========================================================================
   Enterprise AI Summit 2026 — "Xây dựng AI chuyên biệt cho doanh nghiệp"
   Task 04 · design skeleton

   Structure comes from `Keynote 2-v1.pptx`.
   Visual language comes from the sibling summit keynote (Keynote 4).

   House position: this is a scientific keynote, not a product launch.
   Evidence regions are sized for model names, benchmark names, metrics and
   experimental conditions — not for one large number. The table is a
   first-class layout, not a fallback.
   ========================================================================= */

*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

:root {
  /* ---- canvas -------------------------------------------------------
     2:1, matching the summit reference deck. The PPTX is 16:9; if the
     venue confirms 16:9, change --canvas-h to 1440 and nothing else. */
  --canvas-w: 2560;
  --canvas-h: 1280;

  /* ---- colour -------------------------------------------------------
     Restrained on purpose. Blue carries structure, amber carries emphasis
     and appears rarely, grey carries everything secondary. No semantic
     green/red in the base system — result slides decide that per case. */
  --ink:       #FFFFFF;
  --ink-2:     #D5DEEA;
  --ink-3:     #9FB4CF;
  --ink-4:     #6E839E;

  --blue:      #1E88E5;
  --blue-lt:   #66B4F0;
  --amber:     #F0A23B;

  --bg-deep:   #061530;
  --bg:        radial-gradient(120% 90% at 50% 0%, #123A78 0%, #0A1F44 45%, #061530 100%);
  --bg-grid:   radial-gradient(rgba(255,255,255,.07) 1.5px, transparent 1.5px) 0 0 / 48px 48px;

  --surface:   rgba(255,255,255,.05);
  --line:      rgba(255,255,255,.12);
  --line-2:    rgba(255,255,255,.20);

  /* ---- type ---------------------------------------------------------
     Be Vietnam Pro ships 400/500/700/800 — never request 600, the browser
     would synthesise it and display text would smear. Slide titles sit at
     700 rather than 800: editorial weight, not advertising weight. */
  --sans: 'Be Vietnam Pro', Inter, system-ui, -apple-system, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, monospace;

  --t-display:  128px;
  --t-divider:  112px;
  --t-title:     64px;   /* slide title */
  --t-title-sm:  54px;   /* long slide title */
  --t-eyebrow:   28px;
  --t-lead:      36px;
  --t-body:      30px;
  --t-table:     30px;
  --t-caption:   24px;
  --t-micro:     21px;

  /* ---- space -------------------------------------------------------- */
  --pad-x:     140px;
  --pad-y:     104px;
  --gap:        48px;
  --radius:     14px;
}

/* =========================================================================
   Stage — fixed canvas scaled to the viewport
   ========================================================================= */

html, body { height: 100%; background: var(--bg-deep); overflow: hidden; }
body {
  font-family: var(--sans); color: var(--ink);
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
}

#stage-wrap { position: fixed; inset: 0; display: flex; align-items: center; justify-content: center; }

#stage {
  position: relative; flex: none;
  width: calc(var(--canvas-w) * 1px);
  height: calc(var(--canvas-h) * 1px);
  transform-origin: center center;
  background: var(--bg-deep);
  overflow: hidden;
}

/* =========================================================================
   Slide shell
   ========================================================================= */

.slide {
  position: absolute; inset: 0;
  display: none; flex-direction: column;
  padding: var(--pad-y) var(--pad-x);
  background: var(--bg);
}
.slide.is-active { display: flex; }

/* running foot — quiet, and never on title or divider slides */
.slide__foot {
  position: absolute; left: var(--pad-x); right: var(--pad-x); bottom: 46px;
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: var(--t-micro); font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-4);
}
.slide__foot .num { font-family: var(--mono); letter-spacing: .06em; }

/* =========================================================================
   Heads
   ========================================================================= */

.slide-head { display: flex; flex-direction: column; gap: 16px; margin-bottom: var(--gap); }

.eyebrow {
  font-size: var(--t-eyebrow); font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--blue-lt);
}
.eyebrow--amber { color: var(--amber); }

.slide-title {
  font-size: var(--t-title); font-weight: 700;
  letter-spacing: -.015em; line-height: 1.14;
  max-width: 2000px; text-wrap: balance;
}
.slide-title--sm { font-size: var(--t-title-sm); }
/* An untitled PPTX slide leaves this element in place but empty, so the
   grid below it does not shift. See report §5. */
.slide-title:empty { min-height: 0; }

.slide-intro { font-size: var(--t-lead); line-height: 1.4; color: var(--ink-2); max-width: 1900px; }

/* =========================================================================
   Slide type 1 — Title
   ========================================================================= */

.slide--title, .slide--divider, .slide--conclusion {
  background: var(--bg-grid), var(--bg);
  align-items: flex-start; justify-content: center;
}
.slide--title .title-block { display: flex; flex-direction: column; gap: 40px; max-width: 2100px; }
.display {
  font-size: var(--t-display); font-weight: 800;
  letter-spacing: -.03em; line-height: 1.04;
}
.subtitle { font-size: 52px; font-weight: 500; color: var(--ink-3); letter-spacing: -.01em; }
.title-rule { width: 160px; height: 2px; background: var(--line-2); }

/* =========================================================================
   Slide type 2 — Section divider
   ========================================================================= */

.slide--divider .divider-block {
  display: flex; align-items: baseline; gap: 64px;
}
.divider-num {
  font-family: var(--mono); font-size: 220px; font-weight: 500;
  line-height: .9; color: var(--blue); opacity: .55; letter-spacing: -.04em;
}
.divider-title {
  font-size: var(--t-divider); font-weight: 800;
  letter-spacing: -.02em; line-height: 1.05;
}

/* Transition slide — replaces the numbered Part divider. Carries the handover
   explicitly: what the previous part was about, then the new subject. */
.transition { display: flex; flex-direction: column; gap: 30px; max-width: 2100px; }
.transition__from  { font-size: 38px; line-height: 1.4; color: var(--ink-4); }
.transition__rule  { width: 120px; height: 3px; background: var(--amber); opacity: .8; border-radius: 2px; }
.transition__title { font-size: 150px; font-weight: 800; letter-spacing: -.03em; line-height: 1; }
.transition__to    { font-size: 48px; font-weight: 500; color: var(--amber); letter-spacing: -.01em; }

/* =========================================================================
   Slide type 3 — Statement
   Defined for completeness; no PPTX slide is a pure statement (report §5).
   ========================================================================= */

.slide--statement { align-items: flex-start; justify-content: center; }
.statement {
  font-size: 92px; font-weight: 800; letter-spacing: -.025em;
  line-height: 1.12; max-width: 2150px; text-wrap: balance;
}
.statement-sub { font-size: var(--t-lead); color: var(--ink-3); margin-top: 36px; max-width: 1700px; }

/* =========================================================================
   Slide type 4 — Scientific text
   ========================================================================= */

.rows { display: flex; flex-direction: column; }
.row {
  display: grid; grid-template-columns: 72px 1fr;
  align-items: baseline; gap: 32px;
  padding: 26px 0; border-top: 1px solid var(--line);
}
.rows .row:last-child { border-bottom: 1px solid var(--line); }
.row__n { font-family: var(--mono); font-size: var(--t-caption); color: var(--ink-4); }
.row__t { font-size: var(--t-body); line-height: 1.4; color: var(--ink-2); }

.rows--spaced { margin-top: 34px; }

.takeaway {
  margin-top: auto; padding-top: 32px;
  border-top: 2px solid var(--line-2);
  font-size: var(--t-lead); line-height: 1.35; color: var(--ink);
  max-width: 2100px;
}

/* =========================================================================
   Slide type 5 — Scientific result
   Head · benchmark label · large evidence region · takeaway · source.
   The evidence region accepts a table, a figure or a chart; the layout
   makes no assumption that a result reduces to a single number.
   ========================================================================= */

.slide--result .result-meta {
  display: flex; align-items: baseline; gap: 28px; flex-wrap: wrap;
  margin-bottom: 26px; min-height: 34px;
  font-size: var(--t-caption); color: var(--ink-3);
}
.result-meta .bench {
  font-family: var(--mono); letter-spacing: .04em; color: var(--ink-2);
}
.result-meta .sep { color: var(--ink-4); }

.result-area {
  flex: 1; min-height: 0;
  display: flex; flex-direction: column; justify-content: flex-start;
}
.result-area--split { display: grid; grid-template-columns: 1fr 1fr; gap: 64px; }
/* a short table reads better balanced in the space than pinned to the top */
.result-area--center { justify-content: center; }

.result-foot {
  display: flex; justify-content: space-between; align-items: baseline; gap: 48px;
  margin-top: 30px; padding-top: 26px; border-top: 1px solid var(--line);
}
.result-takeaway { font-size: 34px; line-height: 1.35; color: var(--ink); max-width: 1600px; }
.result-source   { font-size: var(--t-micro); color: var(--ink-4); font-family: var(--mono);
                   letter-spacing: .04em; text-align: right; white-space: nowrap; }

/* =========================================================================
   Slide type 6 — Scientific table  (first-class, not a fallback)
   ========================================================================= */

.sci-table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }

.sci-table caption {
  caption-side: top; text-align: left;
  font-size: var(--t-caption); font-weight: 700; color: var(--ink-3);
  letter-spacing: .14em; text-transform: uppercase;
  padding-bottom: 18px;
}

/* grouped header band: <tr class="group"><th colspan="n">…  */
.sci-table thead tr.group th {
  font-size: var(--t-micro); font-weight: 700; color: var(--ink-4);
  letter-spacing: .16em; text-transform: uppercase;
  padding: 0 20px 12px; text-align: center;
  border-bottom: 1px solid var(--line);
}
.sci-table thead tr.group th.spacer { border-bottom: none; }

.sci-table thead th {
  font-size: var(--t-caption); font-weight: 700; color: var(--ink-3);
  letter-spacing: .10em; text-transform: uppercase;
  padding: 16px 20px; text-align: right; vertical-align: bottom;
  border-bottom: 2px solid var(--line-2);
}
.sci-table thead th:first-child { text-align: left; }

.sci-table tbody td {
  font-size: var(--t-table); color: var(--ink-2);
  padding: 18px 20px; text-align: right;
  border-bottom: 1px solid var(--line);
}
.sci-table tbody td:first-child {
  text-align: left; color: var(--ink); font-weight: 500;
  white-space: nowrap;
}

/* row-group label spanning several rows (Level 1 / Level 2 …) */
.sci-table td.rowgroup {
  font-size: var(--t-caption); font-weight: 700; color: var(--ink-3);
  letter-spacing: .12em; text-transform: uppercase;
  vertical-align: middle; border-right: 1px solid var(--line);
}

/* states the result slides will need in Task 05 */
.sci-table .is-best     { color: var(--ink); font-weight: 700; }
.sci-table .is-missing  { color: var(--ink-4); }            /* render as – */
.sci-table .is-gain     { color: var(--blue-lt); }
.sci-table .is-loss     { color: var(--amber); }
.sci-table tbody tr.is-ours td { background: rgba(30,136,229,.10); }
.sci-table tbody tr.is-ours td:first-child { box-shadow: inset 3px 0 0 var(--blue); }
.sci-table--tight tbody td { padding: 13px 18px; font-size: var(--t-caption); }
.sci-table--tight thead th { padding: 12px 18px; }

/* ---- fine-tuning result table (slide 10) ---------------------------------
   Eight columns, and three of the task names are long. The names are fixed by
   the source and may not be shortened, so the headers wrap instead — renaming
   a task to save width would delete an experimental dimension. */

.sci-table--finetune { table-layout: fixed; }
.sci-table--finetune th:first-child,
.sci-table--finetune td:first-child { width: 440px; }

.sci-table--finetune thead th {
  font-size: 22px; letter-spacing: .08em;
  white-space: normal; line-height: 1.3;
  padding: 14px 16px; vertical-align: bottom;
}

/* Two-line column head: the benchmark identifier above the verified task
   name. The identifier stays because it is how the source labels the column;
   the name is what makes it readable from the back of the room. */
.th-id {
  display: block; font-family: var(--mono);
  font-size: 20px; font-weight: 500; color: var(--ink-4);
  letter-spacing: .04em; text-transform: none; margin-bottom: 7px;
}
.th-name { display: block; font-size: 23px; font-weight: 700; letter-spacing: .06em; }

/* =========================================================================
   Benchmark chart — two panels, one bar group per task
   Height = score (0–100, zero baseline, never truncated).
   Width  = model size, on a compressed scale so 70B does not swamp the plot;
            the legend says "theo kích thước", not "proportional", because the
            scale is ordinal rather than linear.
   Each task keeps its own group: the two panels hold several tasks measured on
   different metrics, so a single averaged bar per panel would be a number that
   exists nowhere in the source.
   ========================================================================= */

.bench { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.bench__div   { background: var(--line-2); }
.bench__panel { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.bench__label {
  font-size: 28px; font-weight: 700; color: var(--ink-3);
  letter-spacing: .14em; text-transform: uppercase;
  margin-bottom: 30px;
}
/* One benchmark per slide: the plot is centred and each group is capped so
   three groups do not stretch into three lonely islands. */
/* Groups are TOP-aligned, not bottom-aligned: .bgroup__bars is a fixed height,
   so this puts every group's zero line at the same y. Bottom-aligning instead
   let a two-line task label push its whole group upward, which made the bars
   of one-line groups sit lower than the rest for no data-related reason. */
.bench__plot { display: flex; align-items: flex-start; justify-content: center; position: relative; }
/* One continuous axis across the whole plot. Four abutting per-group borders
   left a visible seam where the groups met, which reads as a rendering fault
   on a projected slide. */
.bench__plot::after {
  content: ''; position: absolute; left: 0; right: 0; top: 620px;
  height: 1px; background: var(--line-2);
}

.bgroup { flex: 1; max-width: 560px; display: flex; flex-direction: column; min-width: 0; }
/* A tinted zone per task. Inset by a margin so the zones do not tile into one
   continuous field, and kept very low-alpha so it reads as a background zone
   rather than a panel sitting on top of the chart. */
.bgroup__bars {
  background: rgba(255,255,255,.04);
  border-radius: 12px 12px 0 0;
  margin: 0 30px;
  height: 620px; padding-top: 58px;
  /* Tight inside a group, loose between groups — the four bars have to read
     as one task before the eye compares tasks. The empty 70B slot in the
     product groups otherwise splits each group visually down the middle. */
  display: flex; align-items: flex-end; justify-content: center; gap: 28px;
}
.bgroup__name {
  margin-top: 22px; text-align: center;
  font-size: 26px; font-weight: 700; line-height: 1.3; color: var(--ink-2);
  letter-spacing: .04em;
}

.bar {
  position: relative; border-radius: 4px 4px 0 0;
  height: calc(var(--v) * 1%); min-height: 3px;
}
.bar__v {
  position: absolute; left: 50%; bottom: 100%; transform: translateX(-50%);
  margin-bottom: 12px;
  font-size: 24px; font-weight: 500; font-variant-numeric: tabular-nums;
  white-space: nowrap; color: var(--ink-3);
}

/* three baselines share one grey family — width already separates them;
   the fine-tuned model is the only one in brand blue */
.bar--7b  { width: 50px; background: rgba(159,180,207,.30); }
.bar--32b { width: 88px; background: rgba(159,180,207,.45); }
.bar--70b { width: 126px; background: rgba(159,180,207,.60); }
.bar--ft  { width: 50px; background: var(--blue); }
.bar--ft .bar__v { color: var(--ink); font-weight: 700; }

/* A task with no result keeps its slot, so the absence stays visible — now
   labelled "updating" rather than left as a bare dash. */
.bar--none { height: 0; min-height: 0; background: none; }

.pending {
  position: absolute; bottom: 0; left: 0; right: 0;
  margin: 0 auto; width: fit-content;
  padding: 7px 9px;
  border: 1px dashed rgba(159,180,207,.38); border-radius: 7px;
  font-size: 13px; font-weight: 500; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-4); white-space: nowrap; line-height: 1;
}
/* The slot has zero height, so without this the next bar — later in DOM order
   — paints straight over the box. */
.bar--none { z-index: 3; }
/* When every model on a task is unmeasured, one box for the task reads better
   than four identical ones. */
.pending--group {
  position: static; transform: none; align-self: flex-end;
  padding: 16px 28px; font-size: 22px; letter-spacing: .14em;
}

.bench__legend {
  display: flex; align-items: center; flex-wrap: wrap; gap: 36px;
  margin-top: 34px; padding-top: 24px; border-top: 1px solid var(--line);
  font-size: var(--t-caption); color: var(--ink-3);
}
.lg { display: inline-flex; align-items: center; gap: 12px; white-space: nowrap; }
.lg .sw { height: 22px; border-radius: 3px; flex: none; display: block; }
.sw--7b  { width: 10px; background: rgba(159,180,207,.30); }
.sw--32b { width: 18px; background: rgba(159,180,207,.45); }
.sw--70b { width: 26px; background: rgba(159,180,207,.60); }
.sw--ft  { width: 10px; background: var(--blue); }
.lg--note { margin-left: auto; color: var(--ink-4); }

/* compact experiment setup, one restrained line above the table */
.setup-strip {
  display: flex; align-items: baseline; flex-wrap: wrap;
  gap: 18px; margin-bottom: 56px;
  font-size: 28px; color: var(--ink-2);
}
.setup-strip .arrow { color: var(--ink-4); font-size: 26px; }
.sci-table--finetune tbody td { font-size: 34px; padding: 22px 16px; }
.sci-table--finetune tbody td:first-child { font-size: 30px; }

/* the one stronger rule in the table: the boundary between task families */
.sci-table--finetune .colsep { border-left: 1px solid var(--line-2); padding-left: 26px; }
.sci-table--finetune thead tr.group th.colsep { border-left: 1px solid var(--line-2); }

/* small descriptive apparatus note under the table — not a takeaway */
.result-note {
  font-size: var(--t-micro); color: var(--ink-4);
  letter-spacing: .04em;
}

/* =========================================================================
   Slide type 7 — Diagram / architecture
   ========================================================================= */

.diagram-area { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; }
.diagram-caption {
  margin-top: 28px; padding-top: 24px; border-top: 1px solid var(--line);
  font-size: var(--t-caption); color: var(--ink-3); max-width: 2000px;
}

/* Four-stage conceptual chain. Equal weight across all four: the PPTX does not
   single one out, so neither does the slide. */
.stages { display: flex; align-items: flex-start; width: 100%; }
.stage  { flex: 1; display: flex; flex-direction: column; gap: 20px; min-width: 0; }
/* Stroke-only, no fill, currentColor — the glyph is a small diagram of the
   idea (graph, branch, validated mark, loop), not an emblem. */
.stage__icon {
  width: 88px; height: 88px; display: block; margin-bottom: 10px;
  fill: none; stroke: var(--blue-lt); stroke-width: 2.2;
  stroke-linecap: round; stroke-linejoin: round;
}
.stage__name { font-size: 52px; font-weight: 800; letter-spacing: -.02em; line-height: 1.1; }
.stage__desc { font-size: 28px; line-height: 1.5; color: var(--ink-3); max-width: 460px; }
.stage__arrow {
  flex: none; padding: 26px 30px 0;
  font-size: 40px; line-height: 1.1; color: var(--ink-4);
}

/* =========================================================================
   Slide type 8 — Comparison / before-after
   ========================================================================= */

.compare { flex: 1; min-height: 0; display: grid; grid-template-columns: 1fr 1px 1fr; gap: 72px; }
.compare__rule { background: var(--line-2); }
.compare__side { display: flex; flex-direction: column; gap: 24px; min-height: 0; }
.compare__label {
  font-size: var(--t-caption); font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3);
}
.compare__side--b .compare__label { color: var(--blue-lt); }
.compare__body { flex: 1; min-height: 0; }

/* from → to, stacked. Two parallel tracks, numbered like the reference deck:
   blue for the first, amber for the second. The destination carries the
   weight; the origin is deliberately quieter. */
.path { display: flex; flex-direction: column; gap: 24px; justify-content: center; height: 100%; }
.path__num {
  font-family: var(--mono); font-size: 104px; font-weight: 500;
  line-height: 1; letter-spacing: -.03em; margin-bottom: 12px;
}
.compare__side--a .path__num { color: var(--blue-lt); }
.compare__side--b .path__num { color: var(--amber); }
.path__from  { font-size: 44px; font-weight: 500; color: var(--ink-3); letter-spacing: -.01em; }
.path__arrow { font-size: 44px; line-height: 1; color: var(--ink-4); }
.path__to    { font-size: 66px; font-weight: 800; letter-spacing: -.02em; line-height: 1.12; text-wrap: balance; }

/* =========================================================================
   Slide type 9 — Conclusion
   ========================================================================= */

.slide--conclusion .conclusion-block { display: flex; flex-direction: column; gap: 44px; max-width: 2200px; }
.conclusion-title { font-size: 84px; font-weight: 800; letter-spacing: -.02em; line-height: 1.1; }

/* =========================================================================
   Slide type 10 — Reference / appendix
   ========================================================================= */

.ref-list { display: grid; grid-template-columns: 1fr 1fr; gap: 20px 72px; align-content: start; }
.ref {
  display: grid; grid-template-columns: 360px 1fr; gap: 28px;
  align-items: baseline; padding: 20px 0; border-top: 1px solid var(--line);
}
.ref__k { font-size: var(--t-caption); font-weight: 700; color: var(--ink-2); letter-spacing: .04em; }
.ref__v { font-family: var(--mono); font-size: var(--t-micro); color: var(--ink-3);
          word-break: break-all; line-height: 1.5; }

/* =========================================================================
   Card — supporting container, used sparingly
   ========================================================================= */

.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 40px;
  display: flex; flex-direction: column; gap: 14px;
}
.card__label {
  font-size: var(--t-caption); font-weight: 700; color: var(--ink-3);
  letter-spacing: .14em; text-transform: uppercase;
}

/* four paired concepts — name, arrow, meaning (slide 19) */
.own-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 32px; margin-top: 52px; }
.own { gap: 14px; padding: 44px 40px; justify-content: flex-start; }
.own__name  { font-size: 42px; font-weight: 800; letter-spacing: -.02em; line-height: 1.1; }
.own__arrow { font-size: 30px; color: var(--ink-4); line-height: 1; }
.own__val   { font-size: 30px; line-height: 1.4; color: var(--ink-3); }

/* closing slide (slide 20) — the four lines carry more weight than a normal
   body list, and the final sentence is the last thing said in the talk. */
.close__rows { display: flex; flex-direction: column; }
.close__row {
  display: grid; grid-template-columns: 86px 1fr; align-items: baseline; gap: 30px;
  padding: 26px 0; border-top: 1px solid var(--line);
}
.close__rows .close__row:last-child { border-bottom: 1px solid var(--line); }
.close__n { font-family: var(--mono); font-size: var(--t-caption); color: var(--ink-4); }
.close__t { font-size: 44px; font-weight: 500; letter-spacing: -.01em; line-height: 1.25; }
.close__end {
  margin-top: 12px; font-size: 54px; font-weight: 500;
  line-height: 1.3; letter-spacing: -.02em; max-width: 2150px; text-wrap: balance;
}
.close__arrow { color: var(--amber); padding: 0 6px; }

/* Group reveal with an internal stagger: the band arrives as one gesture,
   but its items cascade rather than popping together. */
.statgrid .stat-item:nth-child(1) { transition-delay: 0ms; }
.statgrid .stat-item:nth-child(2) { transition-delay: 80ms; }
.statgrid .stat-item:nth-child(3) { transition-delay: 160ms; }
.statgrid .stat-item:nth-child(4) { transition-delay: 240ms; }
.statgrid .stat-item:nth-child(5) { transition-delay: 320ms; }
.statgrid .stat-item:nth-child(6) { transition-delay: 400ms; }

/* the first band animates in on slide entry, same cascade */
.slide.is-active .statgrid--lead .stat-item { animation: rise 460ms cubic-bezier(.16,1,.3,1) both; }
.slide.is-active .statgrid--lead .stat-item:nth-child(1) { animation-delay: .16s; }
.slide.is-active .statgrid--lead .stat-item:nth-child(2) { animation-delay: .26s; }
.slide.is-active .statgrid--lead .stat-item:nth-child(3) { animation-delay: .36s; }
body.is-static .statgrid--lead .stat-item { animation: none !important; opacity: 1 !important; transform: none !important; }
@media print { .statgrid--lead .stat-item { animation: none !important; opacity: 1 !important; transform: none !important; } }

/* benchmark name stated under the chart rather than as a heading above it */
.bench__caption { margin-top: 30px; text-align: center;
                  font-size: var(--t-caption); font-weight: 700;
                  letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3); }

/* source attribution inside a caption — kept out of the uppercase transform
   so a citation does not shout */
.bench__cite { text-transform: none; font-weight: 500; letter-spacing: .02em; color: var(--ink-4); }

/* work-in-progress marker. Deliberately visible on the canvas so an unfinished
   slide cannot be presented by accident; remove the div when the slide is done. */
.wip {
  position: absolute; top: 54px; right: var(--pad-x);
  display: inline-flex; align-items: center; gap: 10px;
  padding: 10px 20px; border-radius: 999px;
  border: 1px dashed rgba(240,162,59,.55); background: rgba(240,162,59,.10);
  font-size: var(--t-micro); font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase; color: var(--amber);
}
.wip::before { content: ""; width: 10px; height: 10px; border-radius: 50%; background: currentColor; }
body.is-static .wip { display: none; }

/* two bands on one slide: scale above, diversity below */
.band { display: flex; flex-direction: column; gap: 8px; }
.band + .band { margin-top: 70px; }
.band__label { font-size: var(--t-micro); font-weight: 700; letter-spacing: .18em;
               text-transform: uppercase; color: var(--ink-4); }
.band .statgrid { margin-top: 24px; gap: 76px; }
.band .stat-item__icon { width: 44px; height: 44px; }
.band .stat-item { gap: 12px; }
.band .stat-item__v { font-size: 44px; }
.band .stat-item__l { font-size: 24px; }
/* the scale band has three items, so it can carry larger values */
.statgrid--lead .stat-item__v { font-size: 56px; }
.statgrid--lead .stat-item__icon { width: 50px; height: 50px; }
.statgrid--lead .stat-item__l { font-size: 26px; }

.statgrid--tight { row-gap: 68px; }
.statgrid--tight .stat-item__v { font-size: 30px; }
.statgrid--tight .stat-item__l { font-size: 22px; }
.band ~ .spec-note { margin-top: 40px; }

/* Icon stat grid (slides 17-18). Replaces the spec tables on the author's
   instruction. Glyphs are stroke-only, matching the slide-4 set. */
.statgrid { display: grid; gap: 44px; margin-top: 56px; width: 100%; }
.statgrid--5 { grid-template-columns: repeat(5, 1fr); }
.statgrid--3 { grid-template-columns: repeat(3, 1fr); row-gap: 72px; }

.stat-item { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.stat-item__icon { width: 54px; height: 54px; display: block;
                   fill: none; stroke: var(--blue-lt); stroke-width: 2;
                   stroke-linecap: round; stroke-linejoin: round; }
.stat-item__v { font-size: 54px; font-weight: 800; letter-spacing: -.02em;
                line-height: 1.1; font-variant-numeric: tabular-nums; }
.stat-item__l { font-size: 26px; line-height: 1.35; color: var(--ink-3); }

/* the diversity grid carries compound text rather than magnitudes */
.statgrid--3 .stat-item__v { font-size: 34px; font-weight: 700; letter-spacing: -.01em; line-height: 1.3; }
.statgrid--3 .stat-item__l { font-size: 24px; }

/* Two-column spec tables (slides 17-18). Same geometry on both so the pair
   reads as one exhibit; column 2 is right-aligned for pure magnitudes and
   left-aligned where the value is compound text. */
.sci-table--spec { table-layout: fixed; max-width: 1640px; }
.sci-table--spec th:first-child,
.sci-table--spec td:first-child { width: 600px; }
.sci-table--spec thead th { font-size: var(--t-caption); padding: 0 0 22px; }
.sci-table--spec tbody td { font-size: 40px; padding: 30px 0; color: var(--ink);
                            font-variant-numeric: tabular-nums; }
.sci-table--spec tbody td:first-child { font-size: 34px; font-weight: 500;
                            color: var(--ink-2); white-space: nowrap; }
.sci-table--spec-l tbody td:last-child,
.sci-table--spec-l thead th:last-child { text-align: left; }
.sci-table--spec-l tbody td:last-child { font-size: 34px; white-space: normal; line-height: 1.35; }
.spec-note { margin-top: 34px; font-size: var(--t-micro); color: var(--ink-4); letter-spacing: .02em; }

/* build steps: hidden until revealed; always visible in static/print */
[data-build] { opacity: 0; transform: translateY(14px);
               transition: opacity 420ms cubic-bezier(.16,1,.3,1), transform 420ms cubic-bezier(.16,1,.3,1); }
[data-build].is-revealed { opacity: 1; transform: none; }
@media print { [data-build] { opacity: 1 !important; transform: none !important; } }

/* Knowledge Graph figure (slide 8) — paper-style node/edge diagram drawn from
   the live corpus. Node and edge facts come from documents + doc_relations. */
.kg-q { margin-top: 22px; font-size: 34px; color: var(--ink-2); display: flex; align-items: baseline; gap: 20px; }
.kg-q__label { font-size: var(--t-micro); font-weight: 700; letter-spacing: .16em;
               text-transform: uppercase; color: var(--ink-4); }

.kg-split { display: grid; grid-template-columns: 560px 1px 1fr; gap: 52px;
            flex: 1; min-height: 0; margin-top: 22px; }
.kg-split__rule  { background: var(--line-2); }
.kg-split__left, .kg-split__right { display: flex; flex-direction: column; gap: 14px; min-height: 0; }
.compare__label--b { color: var(--blue-lt); }
.kgfig, .ragfig { width: 100%; height: 100%; flex: 1; min-height: 0; display: block; }

/* --- nodes --- */
.kgfig .n        { fill: rgba(255,255,255,.05); stroke: var(--line); stroke-width: 1.6; }
.kgfig .n--law   { fill: rgba(30,136,229,.12); stroke: rgba(30,136,229,.5); }
.kgfig .n--sm    { fill: rgba(255,255,255,.04); }
.kgfig .n--dead  { fill: none; stroke: rgba(248,113,113,.55); stroke-dasharray: 7 6; }
.kgfig .n--live  { fill: rgba(30,136,229,.14); stroke: rgba(30,136,229,.6); }
.kgfig .n--bad   { fill: rgba(248,113,113,.10); stroke: rgba(248,113,113,.5); }
.kgfig .n--good  { fill: rgba(74,222,128,.12);  stroke: rgba(74,222,128,.55); }

.kgfig .nt  { font-family: var(--mono); font-size: 25px; fill: var(--ink);
              text-anchor: middle; letter-spacing: .01em; }
.kgfig .nt--sm   { font-size: 22px; fill: var(--ink-2); }
.kgfig .nt--dead { fill: var(--ink-3); }
.kgfig .nt--bad  { font-family: var(--sans); font-weight: 700; fill: #F87171; }
.kgfig .nt--good { font-family: var(--sans); font-weight: 700; fill: #4ADE80; }
.kgfig .ns  { font-family: var(--sans); font-size: 20px; fill: var(--ink-4); text-anchor: middle; }
.kgfig .ns--dead { fill: #F87171; }
.kgfig .ns--live { fill: var(--blue-lt); }
.kgfig .ns--bad  { fill: rgba(248,113,113,.8); }
.kgfig .ns--good { fill: rgba(74,222,128,.85); }

/* --- edges --- */
.kgfig .cap { font-family: var(--sans); font-size: 21px; text-anchor: middle; }
.kgfig .cap--bad  { fill: #F87171; }
.kgfig .cap--good { fill: #4ADE80; }

.kgfig .e        { fill: none; stroke: var(--ink-4); stroke-width: 2; }
.kgfig .e--own   { stroke-dasharray: 6 6; }
.kgfig .e--amend { stroke: var(--amber); stroke-width: 2.4; }
.kgfig .e--repl  { stroke: var(--blue); stroke-width: 4; }
.kgfig .et       { font-family: var(--mono); font-size: 20px; fill: var(--ink-4); text-anchor: middle; }
.kgfig .et--amend{ fill: var(--amber); }
.kgfig .et--repl { fill: var(--blue-lt); font-weight: 500; letter-spacing: .12em; }
.kgfig g[transform] .et { text-anchor: start; }

/* --- the RAG side: chunks with no edges --- */
.ragfig .chunkbox rect { fill: rgba(255,255,255,.04); stroke: rgba(255,255,255,.12); stroke-width: 1.6; }
.ragfig .chunkbox line { stroke: rgba(255,255,255,.13); stroke-width: 5; stroke-linecap: round; }
.ragfig .chunkbox--hit rect { fill: rgba(248,113,113,.10); stroke: rgba(248,113,113,.55); stroke-width: 2; }
.ragfig .ct     { font-family: var(--mono); font-size: 22px; fill: var(--ink-2); }
.ragfig .ct--sub{ font-family: var(--sans); font-size: 24px; font-weight: 700; fill: var(--ink); }
.ragfig .ct--sim{ font-family: var(--sans); font-size: 19px; fill: #F87171; }
.ragfig .ragnote{ font-family: var(--sans); font-size: 22px; fill: var(--ink-4); }

/* =========================================================================
   BLUEPRINT MODE
   Makes empty regions legible so the skeleton can be reviewed for rhythm,
   alignment and capacity. Carries no content and no TODO/PENDING wording.
   Toggle with B. Off  =  the production canvas, which is genuinely empty.
   ========================================================================= */

/* A region must show the space it will actually get, otherwise the skeleton
   cannot be reviewed for capacity — so regions stretch to fill their slot
   rather than collapsing to their (empty) content. */
[data-region] { min-height: 0; }
.diagram-area  > [data-region] { flex: 1; align-self: stretch; }
.compare__body > [data-region] { flex: 1; }
.result-area   > [data-region] { flex: 1; }
.title-block   > [data-region] { align-self: flex-start; min-width: 720px; }
.compare__body { display: flex; flex-direction: column; }

body.blueprint [data-region] {
  position: relative;
  border: 1px dashed rgba(159,180,207,.28);
  border-radius: 10px;
  min-height: 90px;
}
body.blueprint [data-region]::before {
  content: attr(data-region);
  position: absolute; top: 8px; left: 12px;
  font-family: var(--mono); font-size: 17px; letter-spacing: .12em;
  text-transform: uppercase; color: rgba(159,180,207,.50);
}
body.blueprint [data-region="result"],
body.blueprint [data-region="diagram"] { min-height: 220px; }

/* Empty table cells get a neutral grey bar so column rhythm and density are
   reviewable. Bars are not data and disappear with blueprint mode. */
body.blueprint .sci-table td:empty::after,
body.blueprint .sci-table th:empty::after {
  content: ''; display: inline-block; height: 12px; width: 72px;
  border-radius: 3px; background: rgba(159,180,207,.20);
}
body.blueprint .sci-table td:first-child:empty::after,
body.blueprint .sci-table th:first-child:empty::after { width: 300px; }

body.blueprint .slide-title:empty::after {
  content: 'không có tiêu đề trong PPTX';
  font-size: 30px; font-weight: 400; color: rgba(159,180,207,.45);
  font-style: italic; letter-spacing: 0;
}

/* =========================================================================
   Motion — restrained, and never required to understand a slide
   ========================================================================= */

@keyframes rise { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: none; } }
.slide.is-active .slide-head,
.slide.is-active .title-block,
.slide.is-active .divider-block,
.slide.is-active .conclusion-block { animation: rise 380ms cubic-bezier(.16,1,.3,1) both; }

/* Freeze only what animates. This used to be `.slide *`, which also stripped
   layout transforms (e.g. a translate-centred label) in screenshot and PDF
   output while looking correct live. */
body.is-static .slide-head,
body.is-static .title-block,
body.is-static .divider-block,
body.is-static .conclusion-block { animation: none !important; opacity: 1 !important; transform: none !important; }
@media (prefers-reduced-motion: reduce) {
  .slide-head, .title-block, .divider-block, .conclusion-block {
    animation: none !important; opacity: 1 !important; transform: none !important; }
}

/* =========================================================================
   Presenter chrome
   ========================================================================= */

#notes {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
  max-height: 30vh; overflow: auto; padding: 20px 30px;
  background: rgba(6,21,48,.96); border-top: 1px solid var(--line);
  font-size: 16px; line-height: 1.55; color: var(--ink-2); display: none;
}
#notes.is-open { display: block; }
#notes b { display: block; margin-bottom: 8px; font-size: 12px; color: var(--blue-lt);
           letter-spacing: .12em; text-transform: uppercase; }

#hud {
  position: fixed; right: 14px; bottom: 12px; z-index: 40;
  font-family: var(--mono); font-size: 12px; color: var(--ink-3); opacity: .45;
  display: flex; gap: 16px;
}
#hud kbd { border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px; }
body.is-static #hud, body.is-static #notes { display: none !important; }

/* =========================================================================
   Print / PDF — one slide per page, everything revealed
   ========================================================================= */

@media print {
  @page { size: 2560px 1280px; margin: 0; }
  html, body { overflow: visible; }
  #stage-wrap { position: static; display: block; }
  #stage { width: 2560px; height: auto; transform: none !important; }
  .slide {
    position: relative; display: flex !important;
    width: 2560px; height: 1280px;
    break-after: page; page-break-after: always;
  }
  .slide-head, .title-block, .divider-block, .conclusion-block {
    animation: none !important; opacity: 1 !important; transform: none !important; }
  #notes, #hud { display: none !important; }
}


/* =========================================================================
   MERGED IN from docs/slide/output/07-content-pass (Task 08).
   Additive only — nothing above this line was changed.
   Supports slide 8 (VietLegal benchmark, five mini-tables). Slides 9 and 10
   are untouched and do not use any of these rules.
   ========================================================================= */

/* left-aligned cell/header utility the merged table needs */
.sci-table td.t-left, .sci-table th.t-left { text-align: left; }

/* =========================================================================
   TASK 08 — VietLegal benchmark as five mini-tables on one slide

   The 23 metric rows used to sit in one dense block, which is unreadable
   from the back of a room. They are now five small tables that share one
   column system, so a level can be scanned on its own while the numbers
   still line up across all five.

   Task 07's .sci-table--dense rules are no longer used by any slide; they
   are left in place rather than deleted so nothing else can shift.
   ========================================================================= */

/* This slide earns its margins back — five tables need the width. */
.slide--bench5 { --pad-x: 80px; }

.bench5 {
  flex: 1; min-height: 0;
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 40px 40px;          /* the panels do the separating now, so the gutters shrink */
  align-content: start;
}
/* top row: three levels, two grid columns each.
   bottom row: two levels, three grid columns each — no dead cell, and the
   numeric columns stay the same width in both rows (only TASK grows). */
.bench5__group       { grid-column: span 2; min-width: 0; position: relative; }
.bench5__group--wide { grid-column: span 3; }

/* Each level sits on its own panel. Whitespace alone was not separating them
   at projection distance. This is the deck's existing .card fill (5% white,
   1px hairline, 14px radius) — a wash, not a heavy container — and the
   horizontal padding is kept small so the panels cost the task names almost
   nothing. */
.bench5__group {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px 18px 14px;
}

.bench5__level {
  font-size: var(--t-caption); font-weight: 700; color: var(--blue-lt);
  letter-spacing: .14em; text-transform: uppercase;
  padding-bottom: 12px; margin-bottom: 10px;
  border-bottom: 1px solid var(--line-2);
}
/* The capability name each level actually tests. Sentence case and lighter
   weight so the heading reads "index, then meaning" rather than as one long
   shouted string. Names come from the VietLegal-Bench spec, not the PPTX. */
.bench5__level .bench5__name {
  text-transform: none; letter-spacing: 0; font-weight: 700;
  color: var(--ink);
}
.bench5__level .bench5__sep { color: var(--ink-4); padding: 0 12px; font-weight: 400; }

/* Fixed layout is what keeps CMC-Legal / Ours / Δ identical in width across
   all five tables; TASK absorbs whatever is left. */
.bench-mini { table-layout: fixed; }
.bench-mini col.c-cmc    { width: 142px; }
.bench-mini col.c-ours   { width: 112px; }
.bench-mini col.c-delta  { width: 126px; }

/* Column headers are the lowest readability priority of the five, so they
   give up the millimetres that the task names need. Sentence case rather
   than the deck's usual uppercase: "CMC-Legal" fits its column on one line
   where "CMC-LEGAL" does not, and a wrapped header costs a line of height
   in all five tables at once. It also reads closer to a paper figure. */
.bench-mini thead th {
  font-size: 20px; font-weight: 700; letter-spacing: .02em;
  color: var(--ink-4); text-transform: none; white-space: nowrap;
  padding: 0 12px 10px; vertical-align: bottom;
  border-bottom: 1px solid var(--line-2);
}
.bench-mini thead th.t-left { text-align: left; }

.bench-mini tbody td {
  font-size: 24px; line-height: 1.28; padding: 11px 12px;
  color: var(--ink-2); border-bottom: 1px solid var(--line);
}
.bench-mini tbody tr:last-child td { border-bottom: none; }
.bench-mini tbody td:first-child {
  white-space: normal;                 /* long task names may take two lines */
  color: var(--ink); font-weight: 500;
  text-align: left;
}
/* The METRIC column is gone (it cost ~120px in every table and repeated
   "Accuracy" 16 times). The metric now rides with the task name as a quiet
   qualifier, so nothing is lost — including the two rows of task 3.4, which
   differ only by metric. */
.bench-mini .mx {
  font-size: 20px; color: var(--ink-4); font-weight: 400;
  white-space: nowrap; margin-left: 12px;
}
/* continuation row: same task, second metric */
.bench-mini td.cont { padding-left: 34px; color: var(--ink-3); font-weight: 400; }

/* Δ is the column the audience should scan. Blue = improved, amber =
   regressed; both restrained, and CMC-Legal / Ours stay neutral so neither
   baseline nor ours reads as the highlighted one. */
.bench-mini td.d { font-weight: 500; }
.bench-mini td.d.is-gain { color: var(--blue-lt); }
.bench-mini td.d.is-loss { color: var(--amber); }


/* -------------------------------------------------------------------------
   Title-slide speaker line. Fills the `speaker` region the Task 04 skeleton
   reserved on slide 1. Name at display-adjacent weight, role quiet beneath.
   ------------------------------------------------------------------------- */
.speaker { display: flex; flex-direction: column; gap: 10px; }
.speaker__name {
  font-size: 44px; font-weight: 700; color: var(--ink); letter-spacing: -.015em;
}
.speaker__role {
  font-size: 28px; font-weight: 400; color: var(--ink-3); letter-spacing: .01em;
}


/* =========================================================================
   MERGED IN from docs/slide/output/07-content-pass (Task 07 components).
   Additive only. Needed by the Knowledge Graph slide: the structure chain,
   the relation chips and the named A-vs-B pair.
   ========================================================================= */

/* ---- chain: a process/progression stated with arrows in the PPTX ------- */
.chain {
  display: flex; align-items: stretch; justify-content: center;
  gap: 28px; flex-wrap: wrap; width: 100%;
}
.chain__node {
  flex: 1 1 0; min-width: 240px;
  display: flex; flex-direction: column; justify-content: center; gap: 10px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 40px 36px;
  font-size: 38px; font-weight: 700; line-height: 1.2; letter-spacing: -.01em;
}
.chain__node .chain__sub {
  font-size: var(--t-caption); font-weight: 500; color: var(--ink-3);
  letter-spacing: .04em;
}
.chain__node--start { border-color: var(--line-2); }
.chain__node--end   { border-color: rgba(30,136,229,.45); background: rgba(30,136,229,.10); }
.chain__arrow {
  flex: none; align-self: center;
  font-family: var(--mono); font-size: 40px; color: var(--blue-lt); opacity: .85;
}

/* compact chain — used where the chain is one line inside a text slide */
.chain--inline { justify-content: flex-start; gap: 20px; }
.chain--inline .chain__node {
  flex: 0 1 auto; min-width: 0; padding: 22px 28px; font-size: 32px;
}
.chain--inline .chain__arrow { font-size: 30px; }

/* trailing set of relation labels (slide 11: dẫn chiếu / sửa đổi / …) */
.chip-set { display: flex; flex-wrap: wrap; gap: 14px; }

/* larger chip set used where the chips are the slide's main content */
/* Constrained width so the set wraps into a block rather than a single thin
   line across the canvas. */
.chip-set--spread { margin-top: 48px; gap: 20px; max-width: 1560px; }
/* scoped rather than a bare .chip--lg: the base .chip rule is declared later
   in this file and would otherwise win on equal specificity */
.chip-set--spread .chip { font-size: 40px; padding: 24px 38px; color: var(--ink); }

/* shared core beneath the domain chain (slide 14) */
.core__label { margin-top: 44px; font-size: var(--t-lead); color: var(--ink-3); }
.core__row   { margin-top: 20px; align-items: center; }
.core__row .chip { font-size: 30px; padding: 16px 30px; color: var(--ink); }
.core__plus  { font-size: 30px; color: var(--ink-4); }
.chip {
  border: 1px solid var(--line); border-radius: 999px;
  padding: 12px 24px; font-size: var(--t-caption); font-weight: 500;
  color: var(--ink-2); letter-spacing: .02em; white-space: nowrap;
}

/* ---- versus pair: two named approaches, as the PPTX states them -------- */
.vs-pair { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 48px; }
.vs-pair__plate {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); padding: 44px 40px;
  font-size: 44px; font-weight: 700; letter-spacing: -.01em; text-align: center;
}
.vs-pair__plate--b { border-color: rgba(30,136,229,.45); background: rgba(30,136,229,.10); }
.vs-pair__vs {
  font-family: var(--mono); font-size: var(--t-caption); color: var(--ink-4);
  letter-spacing: .18em; text-transform: uppercase;
}


.arr { color: var(--blue-lt); font-family: var(--mono); padding: 0 12px; }


/* =========================================================================
   Retrieval slide — two-series variant of the existing bar kit.
   Reuses .bench / .bgroup / .bar unchanged; adds only the second series
   colour and a shorter plot, since this slide carries five groups and a
   per-group Δ where the fine-tuning slides carry three or four.
   ========================================================================= */
.slide--retr .bgroup__bars      { height: 540px; padding-top: 52px; }
.slide--retr .bench__plot::after{ top: 540px; }
.slide--retr .bgroup            { max-width: 460px; }

.bar--base { width: 84px; background: rgba(159,180,207,.38); }
.bar--kg   { width: 84px; background: var(--blue); }
.bar--kg .bar__v { color: var(--ink); font-weight: 700; }

/* Δ is the reason this slide exists, so each group states it under its name. */
.bgroup__delta {
  margin-top: 10px; text-align: center;
  font-size: 26px; font-weight: 700; color: var(--blue-lt);
  font-variant-numeric: tabular-nums;
}
.sw--base { width: 22px; background: rgba(159,180,207,.38); }
.sw--kg   { width: 22px; background: var(--blue); }


/* =========================================================================
   End-to-end comparison — one panel per metric, four systems in each.
   Grouping by metric rather than by system so the audience compares like
   with like: all four citation scores against each other, then all four
   answer scores. Same bar kit; colour still means "whose system".
   ========================================================================= */
.bench--dual { flex-direction: row; gap: 80px; align-items: stretch; }
.bench--dual .bench__div { width: 1px; flex: none; }
.bench--dual .bench__panel { flex: 1; min-width: 0; }

.slide--e2e .bgroup__bars       { height: 500px; padding-top: 52px; margin: 0 14px;
                                  background: none; border-radius: 0; }
.slide--e2e .bench__plot::after { top: 500px; }

/* One tinted field per metric, not per system: the grouping that matters here
   is citation vs answer, and four separate zones inside a panel implied the
   systems were the groups. Drawn as a band behind the bars only, stopping at
   the axis, so it never sits behind the logos or names. */
.slide--e2e .bench__plot        { position: relative; }
.slide--e2e .bench__plot::before {
  content: ''; position: absolute; left: 0; right: 0; top: 0; height: 500px;
  background: rgba(255,255,255,.04); border-radius: 12px 12px 0 0; z-index: 0;
}
.slide--e2e .bgroup { position: relative; z-index: 1; }
/* capped so the four systems cluster instead of spreading across the panel;
   .bench__plot centres them, so a smaller cap pulls the columns together */
.slide--e2e .bgroup             { max-width: 200px; }
.slide--e2e .bgroup__name       { margin-top: 24px; font-size: 24px; }
.slide--e2e .bench__label       { margin-bottom: 26px; color: var(--ink-2); }

.bar--sys  { width: 104px; background: rgba(159,180,207,.42); }
.bar--ours { width: 104px; background: var(--blue); }
.bar--ours .bar__v { color: var(--ink); font-weight: 700; }
.bgroup--ours .bgroup__name { color: var(--ink); font-weight: 700; }

/* Vendor marks under each column. Files supplied by the author and copied
   into assets/logos so the deck stays self-contained offline.
   The OpenAI mark ships solid black, which is invisible on the navy, so it
   is inverted to white — a tone change only, the mark itself is untouched.
   Gemini and Claude ship in colour and are used as-is. */
.slide--e2e .bgroup__logo {
  height: 46px; margin-top: 24px;
  display: flex; align-items: center; justify-content: center;
}
.slide--e2e .bgroup__logo img { height: 46px; width: auto; display: block; }
.logo--invert { filter: invert(1); }
.slide--e2e .bgroup__name { margin-top: 16px; }

/* second line of a table header: the metric and its direction */
.sci-table thead th .unit {
  display: block; margin-top: 5px;
  font-size: var(--t-micro); font-weight: 500; letter-spacing: .06em;
  color: var(--ink-4); text-transform: none;
}

/* Speech table: "best" needs a colour of its own here. White-bold was the
   deck default, but three of the five winners sit on the blue "ours" row,
   where bold white barely separates from the other values. Light blue reads
   as "best result" consistently with the gain colour used elsewhere, and
   still carries on the blue row wash. */
.slide--speech .sci-table .is-best { color: var(--blue-lt); font-weight: 700; }

/* =========================================================================
   ASR domain slides. Same bar kit. One important difference from every
   other chart in this deck: CER is an ERROR RATE, so the SHORTEST bar wins.
   Blue therefore marks the lowest value in each panel — not "our" model.
   Colouring ours blue here would put a tall blue bar on the code-switching
   slide, where our model is in fact the worse of the two.
   Bar heights are normalised within each panel (zero baseline kept), because
   the panels span 1.61 to 85.82 and one shared scale would flatten the
   meeting results into invisible stubs.
   ========================================================================= */
.slide--asr .bgroup__bars        { height: 620px; padding-top: 56px; margin: 0 14px;
                                   background: none; border-radius: 0; }
.slide--asr .bench__plot         { position: relative; }
.slide--asr .bench__plot::after  { top: 620px; }
.slide--asr .bench__plot::before {
  content: ''; position: absolute; left: 0; right: 0; top: 0; height: 620px;
  background: rgba(255,255,255,.04); border-radius: 12px 12px 0 0; z-index: 0;
}
.slide--asr .bgroup       { position: relative; z-index: 1; max-width: none; }
/* Groups stretched across the available width left the bars stranded from
   each other. Every plot shrinks to its content so the columns sit together
   — and so the tinted band and axis stop with them instead of running on to
   the panel edge. The plot is then centred in its panel, with the panel
   label centred over it so the two read as one block. */
.slide--asr .bench__plot            { width: max-content; max-width: 100%; }
.slide--asr .bench__panel           { align-items: center; }
.slide--asr .bench__label           { text-align: center; }
.slide--asr .bgroup                 { flex: 0 0 300px; }
.slide--asr .bench--dual .bgroup    { flex: 0 0 316px; }
/* Three models to a panel leaves the longest names nearly touching at the
   old width; the panels have the room, so spend it on the gaps. */
/* Model names stay on one line — the columns give up the width instead,
   and they sit clear of the bars rather than crowding the axis. */
.slide--asr .bgroup__name { margin-top: 44px; font-size: 24px; white-space: nowrap; }
.slide--asr .bench__label { margin-bottom: 26px; color: var(--ink-2); }
.bar--asr { width: 104px; background: rgba(159,180,207,.42); }
.bar--asr.is-lowest,
.bar--asr.is-top { background: var(--blue); }
.bar--asr.is-lowest .bar__v,
.bar--asr.is-top .bar__v { color: var(--ink); font-weight: 700; }
.hint-lower {
  font-size: var(--t-caption); color: var(--ink-4); letter-spacing: .04em;
  margin-top: -8px; margin-bottom: 26px;
}

/* =========================================================================
   Agent self-improvement slide — same two-series grouped bars as the
   retrieval slide, tightened and centred to match the ASR slides.
   Zero baseline is kept: these are 0-100 scores, so a truncated axis would
   inflate gains of +2 into something they are not. The Δ under each group
   carries the precision the bar heights deliberately do not exaggerate.
   ========================================================================= */
/* Slide 12 uses a ZOOMED y-axis (55-85) rather than 0-100. The gains are
   +2 to +5 points, which are invisible on a full-height axis. The truncation
   is legitimate only because it is disclosed: the axis is drawn with ticks
   and the floor is stated on the slide. --v still carries the true value. */
/* Zero baseline, never truncated: the gains here are +2 to +5 and the chart
   must show them at that size. A cut axis would inflate them. */
.slide--agent .bar { height: calc(var(--v) * 1%); }

/* Slide 19 uses a ZOOMED axis (15-24 CER) for the same reason as slide 12:
   the spread is ~4 CER points and vanishes on a 0-based axis. Disclosed on
   the slide. --v carries the true CER value. */
/* One bar formula for all ASR slides. Each slide declares its own --floor and
   --k, so a dual-panel slide shares ONE scale across both panels — otherwise a
   lower CER can render taller than a higher one, which is what happened here. */
.slide--asr .bar { height: calc((var(--v) - var(--floor, 0)) * var(--k, 1) * 1%); }

.slide--agent .bgroup__bars       { height: 470px; padding-top: 52px; }
.slide--agent .bench__plot::after { top: 470px; }
.slide--agent .bench__plot        { width: max-content; max-width: 100%; }
.slide--agent .bench__panel       { align-items: center; }
.slide--agent .bgroup             { flex: 0 0 372px; max-width: none; }
/* Four task groups were reading as one block; the plot has the room, so
   spend it on the gaps between tasks rather than on wider bars. */
.slide--agent .bgroup__name       { font-size: 24px; }




/* =========================================================================
   Legal Expert Agent map (slide 11), third pass.

   Straight orthogonal arrows, no ring. The five runtime steps are drawn as
   icons rather than labelled rectangles — a magnifier retrieves, a check
   verifies — so the row reads as a process at a glance instead of as five
   identical boxes. Only the two real components keep a container.

   Blue      = the per-question path.
   Dashed    = knowledge supplied from outside that path.
   Blue icon = where structured / expert knowledge enters (Verify).
   ========================================================================= */
.agentmap { width: 100%; height: 100%; display: block; font-family: var(--sans); }

.agentmap .nd-key { fill: rgba(30,136,229,.15); stroke: rgba(30,136,229,.55); stroke-width: 1.5; }

/* Three zones, so it is obvious at a glance which layer each element belongs
   to: what the system knows, what it does per question, and what the humans
   contribute. Tints are deliberately close in value — they group, they do not
   compete with the content sitting on them. */
.agentmap .zone        { stroke-width: 1; }
.agentmap .zone-know   { fill: rgba(102,180,240,.06); stroke: rgba(102,180,240,.22); }
.agentmap .zone-agent  { fill: rgba(255,255,255,.055); stroke: rgba(255,255,255,.16); }
.agentmap .zone-expert { fill: rgba(159,180,207,.05);  stroke: rgba(159,180,207,.20); }
.agentmap .zone-user   { fill: rgba(255,255,255,.03);  stroke: rgba(255,255,255,.12); }
.agentmap .zone-agent  { fill: rgba(255,255,255,.06);  stroke: rgba(255,255,255,.20); }
.agentmap .t-zone      { font-size: 14px; font-weight: 700; letter-spacing: .2em; text-anchor: start; }
.agentmap .t-zone-k    { fill: rgba(102,180,240,.85); }
.agentmap .t-zone-a    { fill: rgba(255,255,255,.70); }
.agentmap .t-zone-e    { fill: rgba(159,180,207,.85); }
.agentmap .t-zone-u    { fill: rgba(255,255,255,.55); }

/* The model is not a step — it is what every step runs on, so it is drawn as
   a substrate under the pipeline rather than as another node in the row. */
.agentmap .modelbar   { fill: rgba(30,136,229,.12); stroke: rgba(30,136,229,.40); stroke-width: 1.2; }
.agentmap .t-model    { fill: var(--ink); font-size: 19px; font-weight: 700; text-anchor: start; }
.agentmap .t-model-sm { fill: var(--ink-3); font-size: 15px; font-weight: 500; text-anchor: start; }
.agentmap .ln-loop    { stroke: var(--blue-lt); stroke-width: 2; stroke-dasharray: 9 6; fill: none; }
/* Verification can fail. Amber, the deck's colour for a negative result, so
   the retry path is legible as "something went wrong" and not as a second
   happy path. */
.agentmap .ln-retry   { stroke: var(--amber); stroke-width: 2; stroke-dasharray: 7 5; fill: none; }
.agentmap .t-retry    { fill: var(--amber); font-size: 14px; font-weight: 700;
                        letter-spacing: .04em; text-anchor: middle; }
.agentmap .t-loop     { fill: var(--blue-lt); font-size: 14px; font-weight: 700;
                        letter-spacing: .06em; text-anchor: middle; }

.agentmap .t       { fill: var(--ink); font-size: 19px; font-weight: 700; text-anchor: middle; }
.agentmap .t-step  { fill: var(--ink); font-size: 20px; font-weight: 700; text-anchor: middle; }
.agentmap .t-sm    { fill: var(--ink-3); font-size: 14px; font-weight: 500; text-anchor: middle; }
.agentmap .t-num   { fill: var(--ink-4); font-size: 13px; font-weight: 700;
                     font-family: var(--mono); letter-spacing: .12em; text-anchor: middle; }
.agentmap .t-src   { fill: var(--ink-2); font-size: 16px; font-weight: 500; text-anchor: middle; }
.agentmap .t-actor { fill: var(--ink); font-size: 18px; font-weight: 700; text-anchor: middle; }
.agentmap .t-edge  { fill: var(--ink-4); font-size: 13px; font-weight: 500; text-anchor: middle; }

.agentmap .ic       { fill: none; stroke: var(--ink-2); stroke-width: 1.7;
                      stroke-linecap: round; stroke-linejoin: round; }
.agentmap .ic-step  { stroke: var(--ink); stroke-width: 1.6; }
.agentmap .ic-actor { stroke: var(--ink); stroke-width: 1.6; }
.agentmap .ic-key   { stroke: var(--blue-lt); }
.agentmap .ic-dotk  { fill: var(--blue-lt); stroke: none; }
.agentmap .ic-fill  { fill: var(--ink); stroke: none; }

.agentmap .ln-main { stroke: var(--blue-lt); stroke-width: 2.5; fill: none; }
.agentmap .ln-back { stroke: rgba(102,180,240,.45); stroke-width: 2; fill: none; }
.agentmap .ln-feed { stroke: var(--ink-4); stroke-width: 1.8; stroke-dasharray: 6 5; fill: none; }

/* Panel caption under the columns rather than over them: the bars and the
   model names read first, the benchmark name identifies what was just read. */
.agentmap-none {}
.bench__label--bottom {
  margin-bottom: 0; margin-top: 28px; padding-top: 20px;
  border-top: 1px solid var(--line); text-align: center;
}

/* Reduction against the first baseline in the panel, printed under the value
   it belongs to. Blue, because on an error rate a drop is the good direction —
   amber would read as a regression. Computed from the two printed numbers, so
   it cannot drift away from them. */
.agentmap-none2 {}
.bar__drop {
  position: absolute; left: 50%; bottom: 100%; transform: translateX(-50%);
  margin-bottom: 14px;
  font-size: 19px; font-weight: 700; color: var(--blue-lt);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
/* stack the value above the reduction so neither sits on the bar */
.bar--drop .bar__v { margin-bottom: 44px; }
