/* =========================================================================
   SIGMA v3 — slides.css
   The HTML slide-deck system for SYSEN 5300. See specs/SLIDES.md.

   STANDALONE ON PURPOSE: a deck must render correctly with this file alone
   (no sigma.css). The brand tokens below are *copies* of the values in
   sigma.css `:root` (specs/DESIGN.md §2) — if the palette moves there, move
   it here too. The one deliberate difference from the 2025 PowerPoint decks:
   the old bright red (#EA4335-ish) becomes Cornell red #B31B1B everywhere.

   Stage model: every slide is authored at exactly 1280×720 (16:9). The deck
   is scaled to the viewport with a single CSS transform (--sc, set by
   slides.js) and letterboxed on a mismatched aspect. Nothing inside a slide
   is responsive — you lay out against a fixed 1280×720 canvas, like a slide.
   ========================================================================= */

/* ---------------------------------------------------------------- fonts --
   Lato, vendored (docs-v3/assets/fonts/lato/). No runtime CDN, ever.
   -------------------------------------------------------------------- */
@font-face{font-family:"Lato";font-style:normal;font-weight:400;font-display:swap;
  src:url("fonts/lato/lato-400.woff2") format("woff2")}
@font-face{font-family:"Lato";font-style:italic;font-weight:400;font-display:swap;
  src:url("fonts/lato/lato-400-italic.woff2") format("woff2")}
@font-face{font-family:"Lato";font-style:normal;font-weight:700;font-display:swap;
  src:url("fonts/lato/lato-700.woff2") format("woff2")}
@font-face{font-family:"Lato";font-style:normal;font-weight:900;font-display:swap;
  src:url("fonts/lato/lato-900.woff2") format("woff2")}

:root{
  /* ---------- brand (copied from sigma.css :root — keep in sync) ---------- */
  --red:#B31B1B; --red-dark:#8f1414; --red-tint:#fbecec; --red-line:#eec9c9;
  --red-tint-2:#f2dada;                    /* deeper warm tint (bubble.rd) */
  --ink:#2a1414; --muted:#8a6a6a; --white:#ffffff;
  --gray:#fff8f6; --gray-2:#fdf0ec; --line:#eddad6;
  /* ---------- the course color scheme (Tim, 2026-08-16) ----------
     "Red and white and gray and tan, with blue, yellow and purple accents."
     Base: carnelian --red family, white, warm grays, TAN (--o / --peach-dk —
     these are the tan tones sampled from the 2025 decks, NOT an orange
     accent). Accents: blue (--b / --b-mid), yellow (--y), purple (--p /
     --p-mid). Supporting tints seen in the decks: berry, rose, lavender.
     Values sampled from the 2025 PDFs; they intentionally diverge from
     sigma.css's Carbon pastels — do not resync. Green is not in the scheme.
     Text on tan uses --peach-ink (= scheme dark red, AA); text on lavender
     uses --navy-ink; text on rose/yellow uses --rose-ink.               */
  --y:#f0c030; --y-soft:#f8e2a0; --o:#f0b068; --o-soft:#f8dcc0;
  --b:#a0c0f0; --b-soft:#dce8f8; --p:#8878c0; --p-soft:#e2ddf0;
  --b-mid:#3880c0; --p-mid:#6048a0;              /* saturated blue / purple */
  /* AA text variant of --b-mid. --b-mid itself is a FILL (pill / circle /
     qhead grounds) and stays exactly as sampled from the 2025 decks; as body
     TEXT it only reaches 3.98:1 on --gray (A11Y F-08). Same hue and
     saturation, lower lightness. Use for color:, never for background. */
  --b-mid-ink:#3070a8;
  --berry:#a04878; --berry-soft:#e8c8da;
  --rose:#d08080; --lav:#b0a8d0; --peach-dk:#f0a880;
  --navy-ink:#302050; --peach-ink:#8f1414;  /* text on tan = the scheme's dark red (AA 4.9:1) — Tim 2026-08-16 */ --rose-ink:#580808;  /* partners */
  --g:#24a148; --g-soft:#d3f0da;    /* NOT part of the decoration scheme */
  --mean:#DC267F; --median:#4589ff;
  --code-bg:#26100f; --code-ink:#e9edf2; --code-cm:#8bd6a4;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;

  /* ---------- slide-system tokens ---------- */
  /* If the vendored woff2s are ever missing, the stack degrades gracefully. */
  --slide-font:"Lato","Calibri","Segoe UI","Inter",-apple-system,Helvetica,Arial,sans-serif;
  --stage-w:1280px; --stage-h:720px;
  --sc:1;                                  /* set by slides.js */
  --letterbox:#1b1010;                     /* bars around the stage */
  --card-bg:#f2f2f2;                       /* the intro-people card gray */

  /* Typography scale (px @ the 1280×720 stage).
     HARD FLOOR: body copy never below --fs-min (26px ≈ 20pt). */
  --fs-min:26px;
  --fs-body:30px;      /* default bullet / paragraph */
  --fs-lead:34px;      /* lead-in line above a list */
  --fs-small:26px;     /* dense two-column lists — still at the floor */
  --fs-sub:44px;       /* red sub-headline under a topbar */
  --fs-h1:96px;        /* s-section title */
  --fs-title:62px;     /* s-title deck title */
  --fs-caption:20px;   /* legacy alias — kept so decks referencing it still work */
  --fs-chrome:24px;    /* HARD CHROME FLOOR: captions, sources, category
                          labels. Not body copy (that floor is --fs-min), but
                          nothing in a deck renders below 24px. */

  --topbar-h:72px;
  --pad-x:56px;        /* standard slide gutter */
}

*{box-sizing:border-box}
html,body{margin:0;padding:0}
html{background:var(--letterbox)}
body{
  background:var(--letterbox);
  color:var(--ink);
  font-family:var(--slide-font);
  line-height:1.4;
  overflow:hidden;                          /* the deck owns the viewport */
  -webkit-font-smoothing:antialiased;
}

/* ================================================================== deck ==
   The stage: one slide visible, centered, scaled, letterboxed.
   ======================================================================== */
/* The single auto track used to be sized to the 1280px slide's max-content, so
   on any viewport NARROWER than the stage the track overflowed to the right and
   the scaled slide was pushed off-screen (fatal on a phone: 390px viewport put
   the slide at x=445). Pinning both tracks to the viewport makes the centered
   overflow symmetric, which is what the scale() transform assumes. */
.deck{position:fixed;inset:0;display:grid;place-items:center;overflow:hidden;
  grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr)}

.slide{
  position:relative;
  width:var(--stage-w);height:var(--stage-h);
  flex:0 0 auto;
  display:none;
  overflow:hidden;
  background:var(--white);
  color:var(--ink);
  font-size:var(--fs-body);
  transform:scale(var(--sc));
  transform-origin:center center;
}
.slide.is-active{display:block}
/* s-agenda is the one archetype whose grid lives on the slide root itself
   (panel | side). .slide.is-active's display:block outranks .s-agenda's
   single class, so the active state must re-assert the grid. */
.slide.is-active.s-agenda{display:grid}
body.is-print .s-agenda{display:grid}

/* The floor rule. Any component may lower --fs locally; it can never push
   real body copy below --fs-min. Captions/sources are divs, not p/li, and
   are therefore exempt by construction (see specs/SLIDES.md §4). */
.slide p,.slide li{
  font-size:max(var(--fs-min), var(--fs, var(--fs-body)));
  margin:0 0 .55em;
}
.slide ul,.slide ol{margin:0 0 .4em;padding-left:1.15em}
.slide li{margin-bottom:.5em}
.slide li::marker{color:var(--red)}
.slide h1,.slide h2,.slide h3{margin:0;font-weight:700;line-height:1.12}
.slide a{color:var(--red-dark);text-decoration:underline;text-underline-offset:2px}
.slide strong{color:var(--red);font-weight:700}     /* red emphasis default */
.slide em{font-style:italic}
.slide code{font-family:var(--mono);background:var(--gray-2);
  border:1px solid var(--line);border-radius:5px;padding:0 5px;font-size:.86em}

/* ============================================================ 1. s-title ==
   Hero image band across the top, cut by a diagonal white wedge; kicker,
   big white title, italic subtitle; presenter block bottom-right with a
   circular headshot straddling the wedge; thin red bar at the very bottom.
   ======================================================================== */
.s-title{background:var(--white)}
.s-title .hero{
  position:absolute;top:0;left:0;right:0;height:58%;
  overflow:hidden;background:var(--ink);
  clip-path:polygon(0 0,100% 0,100% 74%,0 100%);
}
.s-title .hero img{width:100%;height:100%;object-fit:cover;display:block}
.s-title .titlebox{position:absolute;top:34px;left:var(--pad-x);right:120px;z-index:2}
.s-title .kicker{color:#fff;font-size:38px;font-weight:400;letter-spacing:.2px;
  text-shadow:0 1px 10px rgba(0,0,0,.45)}
.s-title h1{color:#fff;font-size:var(--fs-title);font-weight:700;margin:.06em 0 .02em;
  text-shadow:0 2px 14px rgba(0,0,0,.5)}
.s-title .sub{color:#fff;font-size:34px;font-weight:700;font-style:italic;
  text-shadow:0 1px 10px rgba(0,0,0,.45)}

.s-title .headshot{
  position:absolute;left:52px;top:378px;width:190px;height:190px;border-radius:50%;
  object-fit:cover;border:5px solid #fff;box-shadow:0 3px 18px rgba(0,0,0,.22);z-index:3;
}
.s-title .presenter{position:absolute;left:300px;top:472px;right:var(--pad-x)}
.s-title .presenter .who{font-size:27px;font-weight:700;color:var(--ink);margin-bottom:6px}
.s-title .presenter .role{font-size:26px;color:#4a3838;line-height:1.28}
.s-title .presenter .course{font-size:30px;color:var(--red);font-weight:400;margin-top:12px}
.s-title .presenter .tag{font-size:22px;color:#7a6a6a;font-weight:700;margin-top:6px}
.s-title .redbar{position:absolute;left:0;right:0;bottom:0;height:9px;background:var(--red)}

/* ========================================================== 2. s-section ==
   Full-bleed red divider. Huge white title, short white rule, deck-name
   subtitle. `--q` = the big-statement / question variant.
   ======================================================================== */
.s-section{background:var(--red);color:#fff;padding:96px var(--pad-x) 0 64px}
.s-section h1{color:#fff;font-size:var(--fs-h1);font-weight:900;letter-spacing:-1px}
.s-section .rule{width:640px;height:7px;background:#fff;margin:38px 0 34px;border:0}
.s-section .sub{font-size:40px;font-weight:400;color:#fff}
.s-section .cutout{position:absolute;right:24px;bottom:0;max-height:74%;max-width:52%;
  object-fit:contain;z-index:2}

/* --q reserves the bottom-right corner for the .cutout. The statement's
   max-width + the cutout's max-width are set as a matched pair: 700px of text
   column ends at x=764, the cutout starts at x=766. Text and image cannot
   overlap at any wrap count, and the reserve does not depend on font size, so
   it holds when the studio pushes body copy to 1.4×.
   (Tim review 2026-08-16: "text overflows onto image improperly".) */
.s-section--q{padding-top:118px}
.s-section--q h1{font-size:78px;font-weight:700;line-height:1.16;max-width:700px;
  letter-spacing:0}
.s-section--q .sub{max-width:700px}
.s-section--q .cutout{max-width:38%;max-height:66%;right:28px}
.s-section--q h1 em{font-style:italic;font-weight:400}
.s-section--q h1 u{text-decoration-thickness:4px;text-underline-offset:6px}
.s-section--q .rule{width:120px;height:6px;margin-top:44px}

/* =========================================================== 3. s-agenda ==
   Red left panel (title + numbered list) | large image or free content.
   ======================================================================== */
/* display comes from the active/print rules near .slide.is-active — declaring
   it here would out-cascade .slide{display:none} and show every agenda slide */
.s-agenda{grid-template-columns:34% 1fr;grid-template-rows:100%;
  background:var(--white)}
.s-agenda .panel{background:var(--red);color:#fff;padding:82px 34px 40px 44px;overflow:hidden}
.s-agenda .panel h1{color:#fff;font-size:52px;font-weight:700;margin-bottom:34px}
.s-agenda .panel ol,.s-agenda .panel ul{padding-left:1.1em;--fs:28px}
.s-agenda .panel li{color:#fff;margin-bottom:.62em;line-height:1.26}
.s-agenda .panel li::marker{color:#fff}
.s-agenda .side{position:relative;overflow:hidden;padding:0;background:var(--white)}
.s-agenda .side img.fill{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;display:block}
.s-agenda .side img.contain{position:absolute;left:5%;top:7%;width:90%;height:72%;
  object-fit:contain}
.s-agenda .side .caption{position:absolute;left:0;right:0;bottom:26px;text-align:center}

/* =========================================================== 4. s-topbar ==
   The recurring breadcrumb bar + a content region. Everything below is a
   layout helper usable inside ANY slide that has a .content region.
   ======================================================================== */
.topbar{
  position:absolute;top:0;left:0;right:0;height:var(--topbar-h);
  background:var(--red);color:#fff;display:flex;align-items:center;
  padding:0 var(--pad-x);font-size:34px;font-weight:700;letter-spacing:.2px;
}
.slide .content{position:absolute;top:var(--topbar-h);left:0;right:0;bottom:0;
  padding:26px var(--pad-x) 64px}
.subhead{color:var(--red);font-size:var(--fs-sub);font-weight:700;margin-bottom:22px}
.lead{font-size:var(--fs-lead);color:#3a2828;margin-bottom:14px}

/* two-column grids */
.cols{display:grid;grid-template-columns:1fr 1fr;gap:38px;align-items:start}
.cols--21{grid-template-columns:2fr 1fr}
.cols--12{grid-template-columns:1fr 2fr}
.cols.middle{align-items:center}
.cols img{max-width:100%;display:block}
.cols img.fit{width:100%;height:100%;object-fit:cover;border-radius:6px}

/* dense list variant for two-column text (still at the 26px body floor —
   max() so a deck that lowers --fs-small can never take .tight under 24px) */
.tight{--fs:max(var(--fs-chrome), var(--fs-small))}
.tight li{margin-bottom:.36em;line-height:1.28}
.tight .caption,.tight .src{font-size:var(--fs-chrome)}

/* chrome — 24px floor (Tim review 2026-08-16). These are <div>/<a>, exempt
   from the 26px body floor by construction, but they still have to be
   readable from the back of the room. */
.caption{font-size:var(--fs-chrome);color:var(--muted);line-height:1.3;margin-top:10px}
.src{position:absolute;left:var(--pad-x);right:var(--pad-x);bottom:30px;
  font-size:var(--fs-chrome);line-height:1.25;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
/* A11Y F-08: was #c98a8a — 2.8:1 on white, under even the 3:1 large-text
   floor. Same hue and saturation, lower lightness. */
.src a{color:#ad5252;text-decoration:underline}

/* =========================================================== 5. s-twocol ==
   Topbar + two text columns, each with a small gray category label and a
   red pill header (the "Prevention Costs" / "Appraisal Costs" bars).
   ======================================================================== */
.s-twocol .content{padding-top:18px}
.catlabel{font-size:var(--fs-chrome);color:#5c5c5c;margin-bottom:8px}
.pillhead{
  display:block;background:var(--red);color:#fff;font-size:32px;font-weight:400;
  border-radius:12px;padding:14px 24px;margin-bottom:18px;
}
.s-twocol .colbody{padding-left:14px}
.s-twocol .colbody > p{color:#3a2828;--fs:var(--fs-small)}
.s-twocol .colbody ul{list-style:disc;padding-left:1.5em}

/* =========================================================== 6. s-bigimg ==
   Topbar + one large image filling the remaining area.
   ======================================================================== */
.s-bigimg .content{padding:0}
.s-bigimg img.fill{width:100%;height:100%;object-fit:cover;display:block}
/* `contain` letterboxes instead of cropping. The image is absolutely inset
   into the content region so its box is definite — a `max-height:100%` on a
   centered grid item is NOT reliably definite in Chromium and silently
   overflows the stage (caught by verify_slides gate c1, 2026-08-16). */
.s-bigimg.contain .content{padding:0}
.s-bigimg.contain img.fill{position:absolute;left:var(--pad-x);top:22px;
  width:calc(100% - 2 * var(--pad-x));height:calc(100% - 86px);object-fit:contain}
/* The caption on a full-bleed image is the ONLY text on the slide, so it is
   not chrome — it carries the point. 28px, ink, opaque plate (Tim review
   2026-08-16: "slide 8 text is too small"). */
.s-bigimg .content .caption{position:absolute;left:var(--pad-x);right:var(--pad-x);
  bottom:56px;font-size:28px;font-weight:700;color:var(--ink);line-height:1.25;
  background:rgba(255,255,255,.94);padding:12px 20px;border-radius:8px;margin:0;
  box-shadow:0 2px 12px rgba(0,0,0,.18)}

/* ============================================================= 7. s-quad ==
   2×2 grid, tight gutters. Each cell is free: image, text, or both, with an
   optional mini red header.
   ======================================================================== */
.s-quad .content{padding:18px 22px 54px}
.quad{display:grid;grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr;
  gap:12px;height:100%}
.qcell{position:relative;overflow:hidden;border-radius:8px;background:var(--gray);
  border:1px solid var(--line);display:flex;flex-direction:column}
/* tone modifiers — colour the head bar and that cell's body copy together,
   the way the 2025 comparison quads did (workshop-1 p16/p17). */
.qcell.t-o > .qhead{background:var(--o);color:var(--peach-ink)}
.qcell.t-o .qbody{color:var(--peach-ink)}
.qcell.t-pm > .qhead{background:var(--p-mid)} .qcell.t-pm .qbody{color:var(--p-mid)}
.qcell.t-bm > .qhead{background:var(--b-mid)} .qcell.t-bm .qbody{color:var(--b-mid-ink)}
.qcell.t-berry > .qhead{background:var(--berry)} .qcell.t-berry .qbody{color:var(--berry)}
.qcell.t-r .qbody{color:var(--red)}
.qcell > .qhead{background:var(--red);color:#fff;font-size:24px;font-weight:700;
  padding:8px 16px;flex:0 0 auto}
.qcell > .qbody{flex:1 1 auto;padding:14px 18px;overflow:hidden;--fs:var(--fs-min)}
.qcell > img{width:100%;height:100%;object-fit:cover;display:block;flex:1 1 auto;min-height:0}
.qcell.plain{background:var(--white);border-color:transparent}

/* ============================================================ 8. s-cards ==
   2–4 people cards on white: gray rounded card, red bold name, big circular
   photo, role lines, red tagline, tiny gray subline.
   ======================================================================== */
.s-cards .content{padding:28px var(--pad-x) 54px}
.cards{display:grid;gap:26px;height:100%;grid-auto-flow:column;
  grid-auto-columns:1fr;align-items:stretch}
.card{background:var(--card-bg);border-radius:14px;padding:22px 20px 24px;
  text-align:center;display:flex;flex-direction:column;align-items:center;overflow:hidden}
.card .name{color:var(--red);font-size:32px;font-weight:700;margin-bottom:16px}
.card img{width:190px;height:190px;border-radius:50%;object-fit:cover;
  flex:0 0 auto;margin-bottom:18px}
.card .role{font-size:var(--fs-min);color:#2c2c2c;line-height:1.24}
.card .tagline{font-size:var(--fs-caption);color:var(--red);margin-top:12px;font-weight:400}
.card .subline{font-size:16px;color:#8d8d8d;margin-top:4px}
.cards--2{grid-auto-columns:1fr}
.cards--wide .card{text-align:left;align-items:flex-start;flex-direction:row;gap:26px}

/* ============================================================ 9. s-pills ==
   Stack of red pill rows (the weekly checklist) + a right-hand visual.
   ======================================================================== */
.s-pills .content{padding-top:20px}
.pillstack{display:flex;flex-direction:column;gap:14px}
.pillrow{background:var(--red);color:#fff;border-radius:12px;padding:14px 24px;
  font-size:30px;font-weight:400;display:flex;align-items:center;gap:14px}
.pillrow .n{font-weight:700;opacity:.85;font-size:24px}
.pillrow a{color:#fff;text-decoration:underline}
/* "done" is the saturated blue, not green — green is not in the scheme
   (Tim review 2026-08-16). Checked-off blue reads "done" without it. */
.pillrow.done{background:var(--b-mid)}
.pillrow.ghost{background:var(--red-tint);color:var(--red-dark);
  border:2px solid var(--red-line);font-size:max(var(--fs-chrome),30px)}

.circles{display:flex;flex-direction:column;gap:18px;align-items:center;
  justify-content:center}
.circle{width:150px;height:150px;border-radius:50%;display:grid;place-items:center;
  color:#fff;font-size:28px;font-weight:700;text-align:center;padding:10px;
  line-height:1.15;flex:0 0 auto}
/* carnelian */
.circle.r{background:var(--red)} .circle.rd{background:var(--red-dark)}
.circle.tint{background:var(--red-tint);color:var(--red-dark)}
/* 2025 pastel accents — dark partner ink on the light grounds */
.circle.y{background:var(--y);color:var(--rose-ink)}
.circle.o{background:var(--o);color:var(--peach-ink)}
.circle.b{background:var(--b);color:var(--navy-ink)}
.circle.lav{background:var(--lav);color:var(--navy-ink)}
.circle.rose{background:var(--rose);color:var(--rose-ink)}
.circle.peach{background:var(--peach-dk);color:var(--peach-ink)}
/* mid tones carry white, as the 2025 venn had it */
.circle.p{background:var(--p);color:#fff}
.circle.bm{background:var(--b-mid)} .circle.pm{background:var(--p-mid)}
.circle.berry{background:var(--berry)}
.circle.g{background:var(--g)}          /* legacy; not in the deck scheme */
.circles--row{flex-direction:row;gap:18px}

/* =================================================== 10. reusable pieces ==
   Usable inside any slide.
   ======================================================================== */
.pill{display:inline-flex;align-items:center;gap:8px;border-radius:999px;
  padding:5px 18px;font-size:24px;font-weight:700;background:var(--red);color:#fff}
.pill.rd{background:var(--red-dark)}
.pill.tint{background:var(--red-tint);color:var(--red-dark);
  box-shadow:inset 0 0 0 2px var(--red-line)}
.pill.gray{background:#e6e0de;color:#4a3838}
/* 2025 pastel accents — dark partner ink on the light grounds */
.pill.y{background:var(--y);color:var(--rose-ink)}
.pill.o{background:var(--o);color:var(--peach-ink)}
.pill.b{background:var(--b);color:var(--navy-ink)}
.pill.lav{background:var(--lav);color:var(--navy-ink)}
.pill.rose{background:var(--rose);color:var(--rose-ink)}
.pill.p{background:var(--p);color:#fff}
.pill.bm{background:var(--b-mid)} .pill.pm{background:var(--p-mid)}
.pill.berry{background:var(--berry)}
.pill.g{background:var(--g)}            /* legacy; not in the deck scheme */

.chip{display:inline-flex;align-items:center;gap:6px;border-radius:8px;
  padding:3px 12px;font-size:22px;font-weight:700;
  background:var(--red-tint);color:var(--red-dark);border:1px solid var(--red-line)}

/* speech-bubble callout. DEFAULT IS THE SOFT YELLOW, as originally built and
   as the 2025 decks had it (Tim review 2026-08-16 — the warm-only round was
   reverted). Warm variants (.r/.rd/.o) remain available. */
.bubble{position:relative;display:inline-block;max-width:520px;
  background:var(--y-soft);border:2px solid var(--y);border-radius:14px;
  padding:16px 20px;font-size:var(--fs-min);color:#3a2828;line-height:1.3}
.bubble::after{content:"";position:absolute;left:44px;bottom:-17px;width:0;height:0;
  border:15px solid transparent;border-top-color:var(--y);border-bottom:0}
.bubble::before{content:"";position:absolute;left:47px;bottom:-12px;width:0;height:0;
  border:12px solid transparent;border-top-color:var(--y-soft);border-bottom:0;z-index:1}
/* carnelian variants */
.bubble.r{background:var(--red-tint);border-color:var(--red-line);color:#3a2828}
.bubble.r::after{border-top-color:var(--red-line)}
.bubble.r::before{border-top-color:var(--red-tint)}
.bubble.rd{background:var(--red-tint-2);border-color:var(--red-dark);color:#3a1414}
.bubble.rd::after{border-top-color:var(--red-dark)}
.bubble.rd::before{border-top-color:var(--red-tint-2)}
.bubble.o{background:var(--o-soft);border-color:var(--o)}
.bubble.o::after{border-top-color:var(--o)} .bubble.o::before{border-top-color:var(--o-soft)}
.bubble.berry{background:var(--berry-soft);border-color:var(--berry)}
.bubble.berry::after{border-top-color:var(--berry)}
.bubble.berry::before{border-top-color:var(--berry-soft)}
/* pastel accent variants */
.bubble.y{background:var(--y-soft);border-color:var(--y)}
.bubble.y::after{border-top-color:var(--y)} .bubble.y::before{border-top-color:var(--y-soft)}
.bubble.b{background:var(--b-soft);border-color:var(--b)}
.bubble.b::after{border-top-color:var(--b)} .bubble.b::before{border-top-color:var(--b-soft)}
.bubble.p{background:var(--p-soft);border-color:var(--p)}
.bubble.p::after{border-top-color:var(--p)} .bubble.p::before{border-top-color:var(--p-soft)}
.bubble.g{background:var(--g-soft);border-color:var(--g)}
.bubble.g::after{border-top-color:var(--g)} .bubble.g::before{border-top-color:var(--g-soft)}
.bubble.up::after{top:-17px;bottom:auto;border-top:0;border-bottom-color:var(--y)}
.bubble.up::before{top:-12px;bottom:auto;border-top:0;border-bottom-color:var(--y-soft)}

.imgring{border-radius:50%;object-fit:cover;border:4px solid var(--red);
  box-shadow:0 2px 10px rgba(0,0,0,.16)}
.imgring.rd{border-color:var(--red-dark)} .imgring.o{border-color:var(--o)}
.imgring.y{border-color:var(--y)} .imgring.b{border-color:var(--b)}
.imgring.p{border-color:var(--p)} .imgring.bm{border-color:var(--b-mid)}
.imgring.pm{border-color:var(--p-mid)} .imgring.berry{border-color:var(--berry)}
.imgring.lav{border-color:var(--lav)} .imgring.rose{border-color:var(--rose)}

.underline-red{text-decoration:underline;text-decoration-color:var(--red);
  text-decoration-thickness:3px;text-underline-offset:4px}

/* code block for a slide (dark, like the site's code panels) */
.slide pre{background:var(--code-bg);color:var(--code-ink);border-radius:10px;
  padding:18px 22px;font-family:var(--mono);font-size:24px;line-height:1.4;
  overflow:hidden;margin:0 0 14px}
.slide pre .cm{color:var(--code-cm)}

/* ================================================= 11. embeds, media, num ==
   ADDITIVE (SL-3, 2026-08-23). New classes only — nothing above is changed.
   These exist so decks stop inventing per-slide inline styles:
     .embed*   a live page inside a slide (SLIDES-AUDIT finding 2)
     .media--* image height, on the shared scale (finding 3)
     .num/.tbl table cells without hand-kerned padding (finding 4)
   Content-area geometry these are sized against: the stage is 1280x720, the
   topbar takes 72px, .content adds 26px top + 64px bottom padding, so a
   .content region is 1168 x 558 usable.
   ======================================================================== */

/* ---- .embed — an <iframe> of a real page on this site --------------------
   Put the class on the iframe itself. Always pair with a title= (screen
   readers) and loading="lazy" (37 decks x live pages is a lot of fetching).
     <iframe class="embed" title="..." loading="lazy" src="../chapters/x.html">
   Sizes: default sits under a subhead or a short list; --tall fills a content
   region that has nothing else in it; --split fits a .cols cell.
   ------------------------------------------------------------------------ */
.embed{
  display:block;width:100%;height:var(--embed-h,460px);margin-top:10px;
  border:1px solid var(--line);border-radius:8px;
  background:var(--white);                 /* pages with transparent grounds */
  box-shadow:0 1px 6px rgba(0,0,0,.10);
}
.embed--tall{--embed-h:540px}              /* ~the whole 558px content region */
.embed--split{--embed-h:300px}             /* inside .cols / .cols--21 / --12 */

/* ---- .media--* — image sizing on one scale ------------------------------
   Replaces inline height:240/300/320/340/380/400/500px. Use INSTEAD OF .fit
   (these deliberately out-specify .cols img.fit), and keep the alt text.
   contain, not cover: a plot must never be cropped to fill a box.
   ------------------------------------------------------------------------ */
.slide img.media--sm,.slide img.media--md,.slide img.media--lg{
  display:block;width:auto;max-width:100%;margin-left:auto;margin-right:auto;
  object-fit:contain;
}
.slide img.media--sm{height:240px}         /* thumbnail beside a list */
.slide img.media--md{height:380px}         /* the deck-set default */
.slide img.media--lg{height:500px}         /* the slide's whole point */

/* ---- .media--xs — the extra rung below --sm ------------------------------
   For slides that pack 3-4 small figures at once (a 2x2 of plots, a strip of
   thumbnails). Same contract as the rungs above: contain, never cover, and
   never combined with .fit.
   ------------------------------------------------------------------------ */
.slide img.media--xs{
  display:block;width:auto;max-width:100%;margin-left:auto;margin-right:auto;
  object-fit:contain;height:160px;
}

/* ---- .num / .tbl — numeric tables without hand-kerned cells -------------
   .num on a th/td: right-aligned, tabular figures so digits line up.
   .tbl on the table: compact padding at the 24px chrome floor.
   ------------------------------------------------------------------------ */
.slide .num{text-align:right;font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum" 1}
.slide table.tbl{border-collapse:collapse;width:100%;
  font-size:var(--fs-chrome);line-height:1.3}
.slide table.tbl th,.slide table.tbl td{padding:4px 14px;
  border-bottom:1px solid var(--line);vertical-align:baseline}
.slide table.tbl th{text-align:left;color:var(--red);font-weight:700}
.slide table.tbl tr:last-child td{border-bottom:0}

/* ---- .tbl--dense — the rung below .tbl for big lookup tables ------------
   A MODIFIER on table.tbl, not a replacement: keep both classes. Reach for it
   when a table has enough rows that .tbl at the 24px chrome floor runs past
   the 558px content region — a standard-normal or control-chart-constants
   lookup. It goes under the chrome floor deliberately, and only tables get
   that exemption: a projected table is read by scanning to one cell, not by
   reading the back row. Deck 30 inline-styled exactly this three times.
     <table class="tbl tbl--dense">
   ------------------------------------------------------------------------ */
.slide table.tbl--dense{font-size:.62em;line-height:1.25}
.slide table.tbl--dense th,.slide table.tbl--dense td{padding:2px 8px}

/* ---- .ondark — a figure that needs to carry its own white ground --------
   Line art exported with a transparent background disappears on a dark panel
   (s-section, a toned .qcell). This hands the image the white it was drawn
   against, plus enough padding that the ink is not flush to the edge.
   Composes with any .media--* rung: the rung sets the height, this sets the
   ground. Deck 32 inline-styled the background nine times.
     <img class="media--sm ondark" src="..." alt="...">
   ------------------------------------------------------------------------ */
.slide img.ondark{background:#fff;border-radius:6px;padding:4px}

/* =========================================================== deck chrome ==
   Injected by slides.js onto every non-title slide.
   ======================================================================== */
.deckfoot{
  position:absolute;left:var(--pad-x);right:var(--pad-x);bottom:12px;
  display:flex;align-items:center;gap:10px;
  /* A11Y F-08: was #9a8a8a — 3.29:1 on the white slide ground. */
  font-size:17px;color:#786c6c;pointer-events:auto;z-index:5;
}
.deckfoot .df-sep{opacity:.55}
.deckfoot .df-count{margin-left:auto;font-variant-numeric:tabular-nums;font-weight:700}
.deckfoot .df-chap{color:var(--red-dark);text-decoration:none;border:1px solid var(--red-line);
  background:var(--red-tint);border-radius:999px;padding:1px 10px;font-weight:700}
.deckfoot .df-chap:hover{background:var(--red);color:#fff;border-color:var(--red)}
/* on a red ground the footer must invert or it disappears */
/* A11Y F-08: was .72 alpha — composited to #eabfbf on --red, 4.11:1. */
.s-section .deckfoot,.s-agenda .deckfoot{color:rgba(255,255,255,.86)}
.s-section .deckfoot .df-chap,.s-agenda .deckfoot .df-chap{
  color:#fff;background:rgba(255,255,255,.16);border-color:rgba(255,255,255,.35)}

/* click targets for prev/next (slides.js also binds keys).
   Legacy: slides.js v2 no longer creates `.edge` elements — the whole stage is
   the click target now (left 40% back / right 60% forward, bound on document).
   The rules stay so an older cached deck still renders sanely. */
.edge{position:fixed;top:0;bottom:0;width:9vw;z-index:60;cursor:pointer;background:transparent}
.edge.prev{left:0} .edge.next{right:0}
body.is-print .edge{display:none}

/* ======================================================= nav chrome (v2) ==
   Everything below is injected by slides.js v2 and is *additive*: chevron
   buttons, the progress bar, the overview grid, and the slide transition.
   None of it touches an archetype or a token. See specs/SLIDES.md §5.
   ======================================================================== */

/* ---- the n / N counter is a real <button> now (opens the overview) ---- */
.deckfoot .df-count{
  appearance:none;-webkit-appearance:none;background:transparent;border:0;
  font:inherit;color:inherit;cursor:pointer;padding:0 2px;line-height:inherit;
}
.deckfoot .df-count:hover{color:var(--red)}
.s-section .deckfoot .df-count:hover,.s-agenda .deckfoot .df-count:hover{color:#fff}

/* ---- nav landmark ------------------------------------------------------
   A11Y F-09. slides.js puts the two chevrons and the progress bar inside this
   <nav aria-label="Slide navigation"> instead of straight on <body>, so no
   deck content sits outside a landmark. All three children are position:fixed,
   so this element must contribute nothing at all to layout: no size, no
   stacking context, no pointer surface of its own.
   ---------------------------------------------------------------------- */
/* Zero-box on purpose. Must never get transform / filter / contain: those
   would make it the containing block for its position:fixed children. */
.sg-chrome{position:static;display:block;width:0;height:0;margin:0;padding:0;border:0}

/* ---- the active slide is a focus target (A11Y F-04) --------------------
   slides.js parks focus here when the user navigates while tabbing. The ring
   is inset so it can never widen the 1280×720 stage or disturb the letterbox,
   and :focus-visible means a mouse or arrow-key presenter never sees it.
   ---------------------------------------------------------------------- */
.slide:focus{outline:none}
.slide:focus-visible{outline:3px solid var(--red);outline-offset:-3px}

/* ---- chevron buttons -------------------------------------------------- */
.sg-nav{
  position:fixed;top:50%;transform:translateY(-50%);
  width:56px;height:56px;min-width:48px;min-height:48px;
  display:flex;align-items:center;justify-content:center;
  z-index:70;cursor:pointer;padding:0;
  border:1px solid rgba(179,27,27,.28);border-radius:999px;
  background:rgba(255,255,255,.80);
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);
  color:var(--red);font-family:var(--slide-font);font-size:34px;line-height:1;
  font-weight:700;
  box-shadow:0 2px 10px rgba(0,0,0,.22);
  opacity:1;transition:opacity .22s ease, background-color .15s ease;
}
.sg-nav span{display:block;margin-top:-4px}
.sg-nav.sg-prev{left:14px}
.sg-nav.sg-next{right:14px}
.sg-nav:hover{background:rgba(255,255,255,.96)}
.sg-nav:focus-visible{outline:3px solid var(--red);outline-offset:2px}
/* Fine pointers only: fade the chrome out when the mouse is idle. Coarse /
   touch pointers keep it at full opacity — that is the whole point. */
@media (hover:hover) and (pointer:fine){
  body.is-nav-idle .sg-nav{opacity:.25}
}
body.is-print .sg-nav{display:none}

/* ---- progress bar ----------------------------------------------------- */
.sg-progress{
  position:fixed;left:0;right:0;bottom:0;height:3px;z-index:71;
  background:rgba(255,255,255,.14);pointer-events:none;
}
.sg-progress-fill{
  height:100%;width:0;background:var(--red);
  transition:width .18s ease;
}
@media (prefers-reduced-motion:reduce){ .sg-progress-fill{transition:none} }
body.is-print .sg-progress{display:none}

/* ---- overview grid ----------------------------------------------------
   No clone and no second DOM: the real slides are re-laid-out at --ovs
   (set by slides.js). The negative margins shrink each slide's margin box
   to its scaled size so a plain flex-wrap grid does the layout.
   ---------------------------------------------------------------------- */
body.is-overview .deck{
  position:fixed;inset:0;display:flex;flex-wrap:wrap;
  align-content:flex-start;justify-content:center;gap:14px;
  padding:18px;overflow-y:auto;overflow-x:hidden;
  -webkit-overflow-scrolling:touch;background:var(--letterbox);
}
body.is-overview .slide{
  display:block;
  transform:scale(var(--ovs,.2));transform-origin:top left;
  margin:0 calc(var(--stage-w) * (var(--ovs,.2) - 1))
           calc(var(--stage-h) * (var(--ovs,.2) - 1)) 0;
  cursor:pointer;animation:none;
  outline:6px solid rgba(255,255,255,.22);outline-offset:0;
}
/* the one archetype whose grid lives on the slide root (see §4) */
body.is-overview .slide.s-agenda{display:grid}
body.is-overview .slide.is-active{outline:16px solid var(--red)}
/* a thumbnail is a jump target, not a live page: swallow inner clicks */
body.is-overview .slide *{pointer-events:none}
body.is-overview .sg-nav{display:none}

/* ---- slide transition (direction-aware, ~180ms) -----------------------
   Composed with the stage scale, so the keyframes re-apply scale(--sc).
   ---------------------------------------------------------------------- */
@keyframes sg-in-next{
  from{opacity:0;transform:scale(var(--sc)) translateX(46px)}
  to  {opacity:1;transform:scale(var(--sc)) translateX(0)}
}
@keyframes sg-in-prev{
  from{opacity:0;transform:scale(var(--sc)) translateX(-46px)}
  to  {opacity:1;transform:scale(var(--sc)) translateX(0)}
}
.slide.sg-in-next{animation:sg-in-next .18s ease-out both}
.slide.sg-in-prev{animation:sg-in-prev .18s ease-out both}
@media (prefers-reduced-motion:reduce){
  .slide.sg-in-next,.slide.sg-in-prev{animation:none}
  .sg-nav{transition:none}
}
body.is-print .slide.sg-in-next,body.is-print .slide.sg-in-prev{animation:none}

/* ============================================================ print view ==
   `?print` / the `p` key: every slide stacked and scrollable, for PDF export.
   ======================================================================== */
body.is-print{overflow:auto;background:#3a2a2a}
body.is-print .deck{position:static;display:block;overflow:visible;padding:24px 0}
body.is-print .slide{display:block;transform:none;margin:0 auto 22px;
  box-shadow:0 2px 14px rgba(0,0,0,.4)}

/* WK2.8 — every selector below is written to out-specify the `body.is-print`
   SCREEN rules directly above. That matters: the Download PDF button (and the
   `p` key) put `is-print` on <body> before opening the dialog, and
   `body.is-print .slide` (0,2,1) beats a bare `body .slide` (0,1,1) however
   late the print block appears. Until this was fixed the stacked view's 22px
   bottom margin and 24px deck padding survived into the printed page, pushing
   a 720px slide past the 720px page box and spilling EVERY slide onto a second
   sheet. The dark #3a2a2a stacked-view ground is screen-only and stays that
   way — the !important white below is what holds it there. */
@media print{
  /* `size: <length>{2} || <orientation>` is not a legal combination; the
     trailing `landscape` invalidated the whole declaration and the printer
     fell back to Letter portrait. 1280x720 is landscape by its own ratio. */
  @page{size:1280px 720px;margin:0}
  html,body,body.is-print{background:#fff !important;overflow:visible !important}
  body .deck,body.is-print .deck{position:static;display:block;padding:0;margin:0}
  body .slide,body.is-print .slide{
    display:block !important;transform:none !important;
    margin:0 !important;
    width:var(--stage-w);height:var(--stage-h);overflow:hidden;
    page-break-after:always;break-after:page;
    page-break-inside:avoid;break-inside:avoid;
    box-shadow:none !important;outline:none;
  }
  body .slide:last-child,body.is-print .slide:last-child{
    page-break-after:auto;break-after:auto}
  /* the one archetype whose layout lives on the slide root (see §3) — the
     blanket display:block above would otherwise collapse its two columns */
  body .slide.s-agenda,body.is-print .slide.s-agenda{display:grid !important}
  /* position:fixed chrome would otherwise repeat on every sheet. */
  .edge,.deckfoot .df-count,.sg-nav,.sg-progress,.sg-pdf-btn{display:none !important}
  body .slide.sg-in-next,body .slide.sg-in-prev{animation:none}
  *{-webkit-print-color-adjust:exact !important;print-color-adjust:exact !important}
}

/* Bold inside red-ground regions must stay white — the global red <strong>
   default is invisible on the panel/section carnelian (lesson-7 catch). */
.s-agenda .panel strong,.s-section strong,.s-topbar .topbar strong{color:#fff}

/* ================================================ contents + search (WK2.10) ==
   A toggleable table-of-contents sidebar with an in-deck filter box, built by
   slides.js for every deck. Colours come from the deck tokens declared at the
   top of this file — no new literals except the two shadows, which match the
   existing chrome. Off-screen (and out of the tab order) until body.is-toc.
   ============================================================================ */
:root{ --toc-w:336px; --toc-thumb-sc:0.22; }

/* ---- the toggle button (top-left, mirrors the .sg-nav chrome) ---------- */
.sg-toc-btn{
  position:fixed;top:14px;left:14px;z-index:72;
  width:48px;height:48px;min-width:48px;min-height:48px;
  display:flex;align-items:center;justify-content:center;
  padding:0;cursor:pointer;
  border:1px solid rgba(179,27,27,.28);border-radius:12px;
  background:rgba(255,255,255,.80);
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);
  color:var(--red);font-family:var(--slide-font);font-size:22px;line-height:1;
  box-shadow:0 2px 10px rgba(0,0,0,.22);
  transition:opacity .22s ease, background-color .15s ease, left .22s ease;
}
.sg-toc-btn:hover{background:rgba(255,255,255,.96)}
.sg-toc-btn:focus-visible{outline:3px solid var(--red);outline-offset:2px}
@media (hover:hover) and (pointer:fine){
  body.is-nav-idle .sg-toc-btn{opacity:.25}
}
body.is-toc .sg-toc-btn{opacity:1;left:calc(var(--toc-w) + 14px)}
body.is-toc .sg-nav.sg-prev{left:calc(var(--toc-w) + 14px)}
body.is-print .sg-toc-btn{display:none}

/* ---- the panel -------------------------------------------------------- */
.sg-toc{
  position:fixed;top:0;left:0;bottom:0;width:var(--toc-w);max-width:86vw;
  z-index:75;display:flex;flex-direction:column;
  background:var(--white);color:var(--ink);
  font-family:var(--slide-font);
  border-right:1px solid var(--line);
  box-shadow:4px 0 18px rgba(0,0,0,.28);
  overflow:hidden;
  transform:translateX(-102%);visibility:hidden;
  transition:transform .22s ease, visibility .22s;
}
body.is-toc .sg-toc{transform:translateX(0);visibility:visible}
body.is-print .sg-toc{display:none}

.sg-toc-head{padding:14px;border-bottom:1px solid var(--line);background:var(--gray)}
.sg-toc-lab{display:block;margin:0 0 6px;font-size:13px;font-weight:700;
  letter-spacing:.05em;text-transform:uppercase;color:var(--red)}
.sg-toc-q{
  width:100%;box-sizing:border-box;padding:9px 10px;
  font-family:inherit;font-size:15px;color:var(--ink);background:var(--white);
  border:1px solid var(--red-line);border-radius:8px;
}
.sg-toc-q:focus{outline:3px solid var(--red);outline-offset:1px}
.sg-toc-status{margin:8px 0 0;font-size:13px;color:var(--muted)}
.sg-toc.is-empty .sg-toc-status{color:var(--red-dark);font-weight:700}

/* ---- the list --------------------------------------------------------- */
.sg-toc-list{
  list-style:none;margin:0;padding:6px 0 18px;
  flex:1 1 auto;overflow-y:auto;-webkit-overflow-scrolling:touch;
}
.sg-toc-item[hidden]{display:none}
.sg-toc-link{
  display:flex;gap:10px;align-items:baseline;width:100%;
  padding:8px 14px;border:0;background:none;cursor:pointer;
  font-family:inherit;font-size:15px;line-height:1.3;
  color:var(--ink);text-align:left;
}
.sg-toc-link:hover{background:var(--red-tint)}
.sg-toc-link:focus-visible{outline:3px solid var(--red);outline-offset:-3px}
.sg-toc-n{flex:0 0 2.2em;text-align:right;font-size:13px;font-weight:700;
  color:var(--muted);font-variant-numeric:tabular-nums}
.sg-toc-t{flex:1 1 auto}
.sg-toc-item.is-current .sg-toc-link{
  background:var(--red-tint-2);box-shadow:inset 4px 0 0 var(--red);
  font-weight:700;color:var(--red-dark);
}
.sg-toc-item.is-current .sg-toc-n{color:var(--red-dark)}

/* ---- nested section groups ------------------------------------------- */
.sg-toc-group{list-style:none;margin:0;padding:0}
.sg-toc-group[hidden]{display:none}
.sg-toc-sec{
  display:block;width:100%;padding:10px 14px 4px;
  border:0;background:none;cursor:pointer;text-align:left;
  font-family:inherit;font-size:11px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--red);line-height:1.3;
}
.sg-toc-sec:hover{color:var(--red-dark)}
.sg-toc-sec:focus-visible{outline:3px solid var(--red);outline-offset:-3px}
.sg-toc-sub{list-style:none;margin:0;padding:0 0 8px}
.sg-toc-sub .sg-toc-link{padding-left:22px}
.sg-toc-sub .sg-toc-n{flex:0 0 1.8em}

/* ---- panes (Contents / Thumbs / Links) -------------------------------- */
.sg-toc-tabs{
  display:flex;gap:4px;margin-top:10px;
}
.sg-toc-tab{
  flex:1 1 0;padding:6px 4px;cursor:pointer;
  border:1px solid var(--red-line);border-radius:8px;
  background:var(--white);color:var(--muted);
  font-family:inherit;font-size:12px;font-weight:700;letter-spacing:.02em;
}
.sg-toc-tab.is-on{background:var(--red);color:#fff;border-color:var(--red)}
.sg-toc-tab:focus-visible{outline:3px solid var(--red);outline-offset:1px}
.sg-toc [data-pane]{display:none;flex:1 1 auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch}
.sg-toc.tab-toc [data-pane="toc"]{display:block}
.sg-toc.tab-thumbs [data-pane="thumbs"]{display:flex}
.sg-toc.tab-links [data-pane="links"]{display:block}

/* ---- thumbnail scroller ---------------------------------------------- */
.sg-toc-thumbs{
  flex-direction:column;gap:10px;padding:10px 12px 18px;
}
.sg-toc-thumb{
  position:relative;display:block;width:100%;padding:0;margin:0;
  border:1px solid var(--line);border-radius:8px;overflow:hidden;
  background:var(--letterbox);cursor:pointer;
  aspect-ratio:16/9;flex:0 0 auto;
}
.sg-toc-thumb[hidden]{display:none}
.sg-toc-thumb.is-current{outline:3px solid var(--red);outline-offset:0;border-color:var(--red)}
.sg-toc-thumb:focus-visible{outline:3px solid var(--red);outline-offset:2px}
.sg-toc-thumb-stage{
  position:absolute;top:0;left:0;
  width:1280px;height:720px;
  transform-origin:top left;
  transform:scale(var(--toc-thumb-sc, .22));
  pointer-events:none;
}
.sg-toc-thumb .slide,
.sg-toc-thumb .sg-thumb-slide{
  display:block !important;
  transform:none !important;
  animation:none !important;
  margin:0 !important;
  width:1280px;height:720px;
}
.sg-toc-thumb .slide.s-agenda,
.sg-toc-thumb .sg-thumb-slide.s-agenda{display:grid !important}
.sg-toc-thumb-n{
  position:absolute;top:6px;left:6px;z-index:2;
  background:var(--red);color:#fff;
  font-size:12px;font-weight:700;line-height:1;
  padding:3px 7px;border-radius:999px;
  font-variant-numeric:tabular-nums;
}
.sg-toc-thumb-ph{
  display:flex;align-items:center;justify-content:center;
  width:100%;height:100%;min-height:120px;
  background:var(--gray-2);color:var(--muted);font-size:28px;font-weight:700;
}

/* ---- links chips ----------------------------------------------------- */
.sg-toc-chips{
  display:flex;flex-wrap:wrap;gap:4px;
  padding:0 14px 8px 22px;
}
.sg-toc-chip{
  display:inline-block;max-width:100%;
  padding:3px 8px;border-radius:999px;
  font-size:11px;font-weight:700;line-height:1.3;
  text-decoration:none;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;
}
.sg-toc-chip.kind-hw{background:#5c0a0a;color:#fff}          /* homework: dark red */
.sg-toc-chip.kind-activity{background:var(--red);color:#fff} /* activity: red */
.sg-toc-chip.kind-canvas{background:var(--red-tint);color:var(--red-dark);
  border:1px solid var(--red-line)}                          /* Canvas page: light red */
.sg-toc-chip.kind-site{background:var(--o-soft);color:var(--peach-ink)} /* textbook: tan */
.sg-toc-chip.kind-other{background:var(--gray-2);color:#6a5858;
  border:1px solid var(--line)}                              /* generic: grey */

/* ---- desktop push layout (do not overlay the 16:9 stage) ------------- */
@media (min-width:900px){
  body.is-toc-push .deck{
    left:var(--toc-w);right:0;width:auto;
  }
  body.is-toc-push .sg-progress{left:var(--toc-w)}
  body.is-toc-push .sg-toc{
    box-shadow:none;border-right:1px solid var(--line);max-width:none;
  }
}

@media (max-width:640px){
  :root{ --toc-w:300px; }
  /* the panel covers the chevrons at this width — get them out of the way */
  body.is-toc .sg-toc-btn{left:auto;right:14px}
  body.is-toc .sg-nav{opacity:0;pointer-events:none}
}
@media (prefers-reduced-motion:reduce){
  .sg-toc,.sg-toc-btn{transition:none}
}
@media print{
  .sg-toc,.sg-toc-btn{display:none !important}
}

/* ================================================== download PDF (WK2.8) ==
   Top-RIGHT, mirroring the ☰ contents button across the top edge. Top-left is
   WK2.10's, and the chevrons own the vertical middle of both sides, so the
   top-right corner is the only fixed slot with nothing in it. Same tokens,
   same 48px minimum hit target, same idle-fade as the rest of the chrome.
   Hidden in the stacked print view AND in @media print, so it can never end
   up on a page. Also in NO_NAV and activationTarget() in slides.js.
   ========================================================================= */
.sg-pdf-btn{
  position:fixed;top:14px;right:14px;z-index:72;
  height:48px;min-height:48px;
  display:flex;align-items:center;gap:7px;
  padding:0 15px;cursor:pointer;
  border:1px solid rgba(179,27,27,.28);border-radius:12px;
  background:rgba(255,255,255,.80);
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);
  color:var(--red);font-family:var(--slide-font);font-size:15px;line-height:1;
  font-weight:700;letter-spacing:.02em;
  box-shadow:0 2px 10px rgba(0,0,0,.22);
  transition:opacity .22s ease, background-color .15s ease;
}
.sg-pdf-btn .sg-pdf-ico{font-size:19px;line-height:1}
.sg-pdf-btn:hover{background:rgba(255,255,255,.96)}
.sg-pdf-btn:focus-visible{outline:3px solid var(--red);outline-offset:2px}
@media (hover:hover) and (pointer:fine){
  body.is-nav-idle .sg-pdf-btn{opacity:.25}
}
body.is-print .sg-pdf-btn{display:none}
body.is-overview .sg-pdf-btn{display:none}
@media (max-width:640px){
  /* the label is the first thing to go, then the whole button once the
     contents panel has pushed the ☰ into this same corner */
  .sg-pdf-btn .sg-pdf-lab{display:none}
  .sg-pdf-btn{padding:0;width:48px;min-width:48px;justify-content:center}
  body.is-toc .sg-pdf-btn{opacity:0;pointer-events:none}
}
@media (prefers-reduced-motion:reduce){ .sg-pdf-btn{transition:none} }
@media print{ .sg-pdf-btn{display:none !important} }
