/* KT Trainer — Cream + Orange palette, Apple-card surfaces */
:root {
  --cream: #FAF7F2;
  --cream-2: #F2EDE4;
  --ink: #1B1B1B;
  --ink-soft: #4A4A4A;
  --orange: #E87722;
  --orange-soft: #F4A261;
  --line: rgba(27,27,27,0.08);
  --shadow: 0 12px 40px rgba(27,27,27,0.10);
  /* THE STAGE CONSTANT. Every stage, every rendered chain, every source frame
     is this size. Nothing else may set the stage's size. */
  --stage-w: 1376px;
  --stage-h: 545px;
  --stage-ratio: 1376 / 545;
  /* Phase 2 shell (2026-09-21, Option C brief): the ON-SCREEN .step .stage
     BOX height inside the 1280x800 canvas, not the render size above - the
     box keeps the same --stage-ratio, so it is a scaled-down window onto
     the same 1376x545 content and every data-cx/data-cy percentage still
     lands on the same pixel. */
  --kt-stage-h: 420px;
}

.reveal { font-family: -apple-system, "SF Pro Text", "Inter", system-ui, sans-serif; color: var(--ink); }
.reveal .slides { text-align: left; }
body, .reveal-viewport { background: var(--cream) !important; }

.reveal h1, .reveal h2, .reveal h3 { font-family: -apple-system, "SF Pro Display", "Inter", sans-serif; color: var(--ink); font-weight: 600; letter-spacing: -0.02em; }
.reveal h1 { font-size: 2.6em; }
.reveal h2 { font-size: 1.9em; }
.reveal h3 { font-size: 1.3em; color: var(--orange); }
.reveal p, .reveal li { color: var(--ink-soft); font-size: 0.85em; line-height: 1.5; }

.reveal a { color: var(--orange); }

/* Chapter title slide */
.chapter-title {
  display: flex; flex-direction: column; justify-content: center; align-items: flex-start;
  height: 100%; padding: 2rem 3rem; box-sizing: border-box;
}
.chapter-title .num {
  font-size: 0.7em; letter-spacing: 0.3em; color: var(--orange); text-transform: uppercase; margin-bottom: 0.6rem;
}
.chapter-title h1 { font-size: 2.8em; line-height: 1.05; margin: 0; }
.chapter-title p.lead { font-size: 22px; color: var(--ink-soft); max-width: 48%; margin-top: 1rem; line-height: 1.5; }

/* Step slide layout (Phase 2, 2026-09-21): stage on top, caption below it
   reading like a transcript. Reordered with CSS `order` only - the DOM
   still has caption before stage (index.html untouched), so nothing that
   reads the document order (Reveal, the chain-slide JS, the a11y tree)
   has to change. The stage is pinned to the ~420px tall/~1060px wide box
   Errol picked; --stage-w/--stage-h stay the true 1376x545 render size
   used for the cue math (data-cx/data-cy are percentages of the stage
   BOX, not px, so shrinking the box does not move a single arrow). */
.step {
  display: flex; flex-direction: column; gap: 0;
  height: 100%; padding: 0.8rem 1rem;
  box-sizing: border-box;
  align-items: center;
}
.step .stage {
  order: 1;
  flex: 0 0 auto;
  width: auto;
  height: var(--kt-stage-h, 420px);
  max-width: 100%;
  max-height: var(--kt-stage-h, 420px);
  aspect-ratio: var(--stage-ratio);
  display: block;
}
.step .caption {
  order: 2;
  flex: 1 1 auto;
  display: block;
  width: 100%;
  max-width: var(--stage-w);
  /* Reserves the strip js/trainer.js's positionTransportBar() floats the
     fused transport bar into. FIX 2026-09-21 (narrow-screen overlap, JOB 2):
     the bar itself lives OUTSIDE the Reveal-scaled .reveal tree (position:
     fixed, real screen px), but this margin lives INSIDE the scaled
     .reveal tree, so a fixed logical px here does NOT track the bar's real
     height once Reveal's scale drops below 1 (e.g. ~0.543 at 1024x768):
     the reserved gap shrinks with the canvas while the bar's real height
     does not, and the bar overlaps the caption. positionTransportBar()
     now measures the bar's real height, divides by Reveal.getScale(), and
     writes the result to --kt-transport-clearance on <html> every time it
     repositions the bar, so this margin always matches the bar's actual
     footprint at the current width. 84px is only the pre-JS fallback. */
  margin-top: var(--kt-transport-clearance, 84px);
  background: white; border: 1px solid var(--line); border-radius: 12px;
  padding: 0.6rem 1rem; box-shadow: var(--shadow);
  overflow-y: auto;
}
/* 2026-09-28 (9/10 plan step 1): compact caption card so the stage keeps
   the height. On a tall canvas (phone, narrow lesson box) there is room to
   spare under the stage, so the transcript reads larger there instead. */
.step .caption { flex: 0 1 auto; }
.step .caption .step-num {
  display: block;
  font-size: 0.6em; letter-spacing: 0.2em; color: var(--orange); text-transform: uppercase;
  margin: 0 0 0.3rem;
}
.step .caption h2 { font-size: 0.9em; margin: 0 0 0.3rem; line-height: 1.2; }
/* Transcript line: the spoken caption, styled like a quoted transcript
   rather than a UI label, since it now reads underneath the stage instead
   of squeezed beside a hint column. */
.step .caption p {
  font-size: 0.64em; line-height: 1.45; margin: 0; color: var(--ink);
}
/* Hint becomes an inline "Tip" line under the transcript, not a separate
   side panel - the CSS ::before label keeps the word "Tip" out of the
   hint's own text node, so the caption/hint copy in index.html is never
   touched by this reflow (only the JS-neutral, text-untouched box below
   moved where it sits). */
.step .caption .hint {
  display: block;
  margin: 0.4rem 0 0; padding: 0.35rem 0 0;
  background: none; border: none; border-top: 1px solid var(--line);
  border-radius: 0;
  font-size: 0.64em; color: var(--ink-soft); line-height: 1.4;
}
.step .caption .hint::before {
  content: "Tip: "; font-weight: 700; color: var(--orange);
}

/* ROOT-CAUSE FIX 2026-09-04 (Errol: "it should fill the screen", not small cards
   in the top left). The stage used to size itself off whichever frame was left in
   normal flow, which was the BEFORE image. A before frame under the stage constant
   shrank the entire stage and then stretched the absolutely-positioned AFTER frame
   into that wrong box, so data-cx / data-cy stopped pointing at the same pixel on
   both frames. The stage now sizes off the STAGE CONSTANT alone (--stage-w x
   --stage-h = 1376 x 545) and BOTH frames fill it. No image can resize the stage. */
.stage {
  position: relative; border-radius: 14px; overflow: hidden;
  background: white; box-shadow: var(--shadow); border: 1px solid var(--line);
  width: 100%; max-width: var(--stage-w);
  aspect-ratio: var(--stage-ratio);
  line-height: 0;
}
.stage img.shot.before,
.stage img.shot.after {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center top;
  transition: opacity 600ms ease, transform 1200ms ease;
}
.stage img.shot.before { opacity: 1; }
.stage img.shot.after { opacity: 0; }
.stage.clicked img.shot.before { opacity: 0; }
.stage.clicked img.shot.after { opacity: 1; }

/* The c6-s1b hand override that used to live here (swap which frame drives the
   stage size) is gone: with the stage sized off the stage constant, no frame drives
   the size and nothing is left to work around. */

/* Ken Burns zoom — apply scale to the IMAGES (not the stage) so it stays clipped by stage overflow:hidden */
.stage.zoom img.shot {
  transform-origin: var(--zx, 50%) var(--zy, 50%);
  transition: opacity 600ms ease, transform 1200ms ease;
}
.stage.zoom.clicked img.shot { transform: scale(1.6); }

/* Click highlight ring + pulse — visible indicator at click target */
.stage .target-ring {
  position: absolute;
  width: 56px; height: 56px;
  border: 3px solid var(--orange);
  border-radius: 50%;
  box-shadow: 0 0 0 4px rgba(232, 119, 34, 0.25), 0 4px 16px rgba(232, 119, 34, 0.35);
  background: rgba(232, 119, 34, 0.08);
  transform: translate(-50%, -50%);
  z-index: 5;
  pointer-events: none;
  opacity: 0;
  transition: opacity 350ms ease 200ms;
}
.stage .target-pulse {
  position: absolute;
  width: 56px; height: 56px;
  border: 3px solid var(--orange);
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(1);
  z-index: 4;
  pointer-events: none;
  opacity: 0;
}
.stage .cursor { display: none !important; }
/* Show ring on slide enter; pulse on click moment */
.stage .target-ring { opacity: 1; }
.stage.clicked .target-pulse {
  animation: ring-pulse 900ms ease-out 1;
}
@keyframes ring-pulse {
  0%   { opacity: 0.7; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0;   transform: translate(-50%, -50%) scale(2.4); }
}
/* Hide rings on after-state */
.stage.clicked .target-ring { opacity: 0; transition: opacity 250ms ease; }

/* Click highlight ARROW: tip lands exactly on the click target (same data-cx/data-cy the
   ring used). Shaft + head point in from one of four diagonal bearings, chosen in JS so the
   full arrow stays on-stage and clear of the before/after badge. Replaces .target-ring above
   as the active indicator; the ring rules are left in place, just unused. */
.stage .target-arrow {
  position: absolute;
  width: 0; height: 0;
  z-index: 5;
  pointer-events: none;
  opacity: 0;
  transition: opacity 350ms ease 200ms;
}
.stage .target-arrow .target-arrow-shaft {
  position: absolute;
  left: -34px; top: -3px;
  width: 12px; height: 6px;
  background: var(--orange);
  border-radius: 3px;
  box-shadow: 0 2px 8px rgba(232, 119, 34, 0.35);
}
.stage .target-arrow .target-arrow-head {
  position: absolute;
  left: -22px; top: -11px;
  width: 0; height: 0;
  border-top: 11px solid transparent;
  border-bottom: 11px solid transparent;
  border-left: 22px solid var(--orange);
  filter: drop-shadow(0 2px 6px rgba(232, 119, 34, 0.35));
}
.stage .target-arrow { opacity: 1; }
/* Small pulse/glow at the tip on the click moment, reuses the ring-pulse keyframe. */
.stage .target-arrow-pulse {
  position: absolute;
  width: 56px; height: 56px;
  border: 3px solid var(--orange);
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(1);
  z-index: 4;
  pointer-events: none;
  opacity: 0;
}
.stage.clicked .target-arrow-pulse {
  animation: ring-pulse 900ms ease-out 1;
}
/* Hide arrow on after-state, same fade-out timing as the ring */
.stage.clicked .target-arrow { opacity: 0; transition: opacity 250ms ease; }

/* data-arrow-frame="after": read in js/trainer.js createArrowIndicator, which tags the
   arrow itself with .arrow-frame-after (not a raw attribute selector on .stage, so the
   JS that builds the arrow is the one source of truth for this behavior). Before/after
   frames show different screens, so the arrow coordinate (measured against the AFTER
   frame) is meaningless on the BEFORE frame and may land on unrelated or sensitive
   content there. Invert the default timing: stay hidden on slide entry (before-state),
   only fade in once .clicked (after-state) is active. Higher-specificity class rules
   override the two base rules above; the base rules stay untouched for every other slide. */
.target-arrow.arrow-frame-after { opacity: 0; }
.stage.clicked .target-arrow.arrow-frame-after {
  opacity: 1;
  transition: opacity 350ms ease 200ms;
}

/* Before/After badge */
.stage .badge {
  position: absolute; top: 14px; left: 14px; z-index: 6;
  background: rgba(27,27,27,0.78); color: white;
  padding: 0.3rem 0.7rem; border-radius: 999px;
  font-size: 0.7em; letter-spacing: 0.15em; text-transform: uppercase;
  font-family: -apple-system, "SF Pro Text", sans-serif;
}
.stage.clicked .badge::after { content: " AFTER"; }
.stage:not(.clicked) .badge::after { content: " BEFORE"; }
.stage .badge::before { content: "•"; color: var(--orange); margin-right: 4px; }

/* In-slide brand strip (replaces fixed bar that was clipping content) */
.brand-strip {
  position: absolute; top: 0; left: 0; right: 0; height: 32px;
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 1rem; font-size: 0.55em; color: var(--ink-soft);
  border-bottom: 1px solid var(--line); background: var(--cream);
  z-index: 2;
}
.brand-strip .logo { font-weight: 600; color: var(--ink); letter-spacing: -0.01em; }
.brand-strip .logo span { color: var(--orange); }
.brand-strip .crumb { font-variant: small-caps; letter-spacing: 0.08em; }

.reveal .slides section { box-sizing: border-box; overflow: hidden; }
/* Force step slides to fill the full Reveal logical height (800px) */
.reveal .slides section:has(.step) { height: var(--kt-canvas-h, 800px); }
/* 2026-09-28: vertical stacks hold step slides, so they grow with the canvas too. */
.reveal .slides section.stack { height: var(--kt-canvas-h, 800px) !important; }
.reveal .slides section:has(.chapter-title) { height: 800px; }
.reveal .slides section:has(.checklist) { height: 800px; }
.reveal .slides section:has(.mistakes) { height: 800px; }
.reveal .slides section:has(.tag-rules) { height: 800px; }
.reveal .slides section:has(.concept) { height: 800px; }

/* Step slide layout — overrides earlier .step block to keep within 800px */
.step { height: 100%; padding: 1.5rem; padding-top: var(--kt-top-clear, 1.5rem); }
.step .caption { padding: 0.8rem 1.2rem; }
/* Explicit px, same reasoning as the concept/checklist blocks: these were the
   last text still on nested ems, which compounded down to roughly 12-14px and
   made the screenshot captions unreadable in a room. */
.step .caption h2 { font-size: 28px; margin: 0 0 0.4rem; line-height: 1.2; }
.step .caption p { font-size: 21px; line-height: 1.45; margin: 0; }
/* Tip line: border-top rule + generous top spacing instead of the old
   boxed/padded hint card, since it now reads as one inline line under the
   transcript rather than a side panel next to it. */
.step .caption .hint { font-size: 18px; padding: 0.5rem 0 0; margin: 0.5rem 0 0; line-height: 1.4; }
.step .caption .step-num { font-size: 14px; letter-spacing: 0.2em; }
/* 2026-09-28: tall canvas (phone, narrow lesson box) scales everything down
   hard, so the transcript gets real room and bigger type there. */
body.kt-tall .step .caption h2 { font-size: 64px; }
body.kt-tall .step .caption p { font-size: 50px; }
body.kt-tall .step .caption .hint { font-size: 44px; }
body.kt-tall .step .caption .step-num { font-size: 30px; }
body.kt-tall .step .caption { padding: 1.6rem 2rem; }

/* Concept slide — text sized for a room, not a laptop 12in away */
.concept {
  padding: 2.2rem 3rem; height: 100%; box-sizing: border-box;
  display: flex; flex-direction: column; justify-content: center;
}
/* Explicit px so nested-em compounding can't shrink these. The deck scales
   as a whole (Reveal 1280x800), so px stays proportional on any screen. */
.concept h2 { font-size: 44px; margin: 0.4rem 0 0.7rem; line-height: 1.12; }
.concept > p { font-size: 21px; line-height: 1.5; max-width: 60%; margin: 0 0 1rem; }
.concept .grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-top: 0.9rem;
  max-width: 70%;
}
.concept .card {
  background: rgba(255,255,255,0.93); border: 1px solid var(--line); border-radius: 12px;
  padding: 1.05rem 1.15rem; box-shadow: var(--shadow);
  backdrop-filter: blur(2px);
}
.concept .card h3 { font-size: 21px; color: var(--orange); margin: 0 0 0.4rem; }
.concept .card p { font-size: 18px; margin: 0; line-height: 1.45; }

/* Checklist slide */
.checklist { padding: 2.2rem 3rem; height: 100%; box-sizing: border-box; }
.checklist h2 { font-size: 42px; margin: 0.3rem 0 1rem; }
.checklist ul { list-style: none; padding: 0; margin: 0; max-width: 66%; }
.checklist li {
  padding: 0.72rem 0 0.72rem 2.2rem; position: relative;
  border-bottom: 1px solid var(--line); font-size: 21px; color: var(--ink);
  line-height: 1.4;
}
.checklist li::before {
  content: "✓"; color: var(--orange); position: absolute; left: 0.3rem; top: 0.62rem;
  font-weight: 700; font-size: 1.15em;
}

/* Tag rules slide — two-column reference */
.tag-rules { padding: 1.4rem 2rem; height: 100%; box-sizing: border-box; }
.tag-rules h2 { font-size: 40px; margin: 0 0 0.6rem; }
.tag-rules .grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-top: 0.5rem;
}
.tag-rules .panel {
  background: white; border: 1px solid var(--line); border-radius: 12px;
  padding: 0.9rem 1rem; box-shadow: var(--shadow);
}
.tag-rules .panel h3 { font-size: 21px; color: var(--orange); margin: 0 0 0.5rem; }
.tag-rules .panel ul { list-style: none; padding: 0; margin: 0; }
.tag-rules .panel li {
  font-size: 19px; padding: 0.3rem 0; color: var(--ink);
  font-family: -apple-system, "SF Mono", Menlo, monospace;
}
.tag-rules .panel li b { color: var(--ink); font-weight: 600; }
.tag-rules .panel.warn { border-color: rgba(178,58,42,0.3); }
.tag-rules .panel.warn h3 { color: #B23A2A; }
.tag-rules .panel.warn li::before { content: "✕ "; color: #B23A2A; }

/* ---------------------------------------------------------------
   Chapter sculpture art — AI360 CPA paper-sculpture imagery blended
   into the text-only slides so narration never plays over a bare
   cream screen. Each sculpture is topic-matched to its chapter.
   Sits behind content, right side, faded into the cream so it reads
   as texture rather than a pasted photo.
   --------------------------------------------------------------- */
.sculpt {
  position: absolute;
  right: 0; bottom: 0;
  height: 86%;
  width: auto;
  object-fit: contain;
  object-position: bottom right;
  opacity: 1;
  z-index: 0;
  pointer-events: none;
  /* The PNGs carry a baked alpha channel (backdrop knocked out, edges
     feathered), so the art floats on the cream with no box edge.
     NO blend mode and NO opacity wash: multiply clamped every highlight to
     the cream value, which is why the art read dull. The orange glow must be
     allowed to render brighter than the background. */
  filter: saturate(1.12) contrast(1.04);
}
/* Wide, low sculptures (assembly line) hug the bottom edge instead */
.sculpt.wide {
  height: auto; width: 62%;
  right: 2%; bottom: 4%;
  opacity: 1;
}
/* Tall narrow sculptures (scanner feed, portal phone) would clip on the right
   edge and read too faint at the shared settings, so pull them inboard and
   let them sit a little stronger. */
/* (ch7 moved to the default rule when its art was replaced with a square
   render; the inboard 84% sizing was tuned for the old tall narrow crop and
   pushed the new art into the lead column.) */
/* Chapter 0 doorway (2026-09-18) is a tall narrow portrait (ratio 0.55). Pull
   it inboard and size by height so the frame never touches the slide edge. */
.sculpt[src$="ch0.png"] { height: 80%; right: 6%; bottom: 7%; }
/* Cover and outro art is wider than the chapter sculptures and was crowding
   the lead paragraph, so pull it in slightly and give the text room. */
.sculpt[src$="cover.png"], .sculpt[src$="outro.png"] {
  height: 74%;
  right: 1%;
}
/* LANDSCAPE sculptures must be sized by WIDTH, never height. Sizing a wide
   render by height makes it balloon across the whole frame and run under the
   body copy, which is exactly what happened when the new art landed. Anything
   wider than it is tall belongs in this rule. */
.sculpt[src$="ch1.png"],
.sculpt[src$="ch3.png"],
.sculpt[src$="ch4.png"],
.sculpt[src$="ch6.png"],
.sculpt[src$="ch8.png"],
.sculpt[src$="ch9.png"],
.sculpt[src$="ops-manual-actions.png"],
.sculpt[src$="ops-snippets.png"],
.sculpt[src$="ops-smart-lists.png"],
.sculpt[src$="ops-tasks.png"],
.sculpt[src$="ops-calendars.png"],
.sculpt[src$="ops-portal-upload.png"] {
  top: auto; height: auto;
  width: 54%;
  right: 1%; bottom: 3%;
  opacity: 1;
}
/* Content must sit above the art */
.concept, .checklist, .mistakes, .tag-rules, .chapter-title { position: relative; z-index: 2; }

/* ------------------------------------------------------------------
   TEXT NEVER OVERLAPS ART.
   Title slides carry short copy, so the art can run large. Content
   slides (concept / checklist / mistakes / tag-rules) carry long copy
   and were colliding with it: containers were capped at 66-70% while
   the art occupied the right 46-50% of the frame.
   Fix: on content slides the art shrinks into the bottom-right corner
   and sits well back, and every text container is capped so it stops
   before the art begins.
   ------------------------------------------------------------------ */
section:has(.concept) .sculpt,
section:has(.checklist) .sculpt,
section:has(.mistakes) .sculpt,
section:has(.tag-rules) .sculpt {
  height: auto;
  width: 38%;
  right: 1.5%;
  bottom: 3%;
  top: auto;
  opacity: 1;
  z-index: 0;
}

/* Text stops before the art starts. Art now occupies the right 38% plus a
   1.5% gutter, so it begins at ~60.5% of the frame. Text is capped below that. */
.concept h2,
.concept > p,
.checklist h2,
.checklist ul,
.mistakes h2,
.mistakes ul,
.concept ul.misses {
  max-width: 63%;
}
.concept .grid { max-width: 63%; }
/* FONT-BUMP FIX (2026-08-16): .concept ul.misses had its own looser 66%
   max-width (set where the rule was defined, further down this file) and was
   left out of the tighter before-art cap above. At the old 21px body copy
   that slack never showed; at the new 26px bump the longest line on
   c10-mistakes item 3 reached past 60.5% and ran under the sculpt. Capped
   here with every other mistakes/concept text block so all eleven mistakes
   slides use the same right edge. */
/* AUDIT FIX (2026-08-14): .concept .hint was left out of the text-stops-
   before-art cap above, so on ch6/ch9/ch10 concept slides the hint line ran
   under the shrunk-but-still-present sculpt at bottom-right (confirmed via
   pixel-alpha sampling, not just bbox overlap: alpha ~220-228, fully opaque
   art under the text). Cap it with the other concept text. */
.concept .hint { max-width: 63%; }

/* Long lists get the full column back, since the art sits low and right */
.checklist ul, .mistakes ul { max-width: 66%; }

/* Same bump as .mistakes li, for the "you pass this chapter when" lists */
.checks li { font-size: 26px; line-height: 1.5; }

/* Larger, more readable type now that the columns are properly bounded */
.concept > p { font-size: 22px; }
.concept .card h3 { font-size: 22px; }
.concept .card p { font-size: 19px; }
.checklist li { font-size: 22px; }

/* c6-s4 desktop: six cards should read as one deliberate two-row summary.
   The sixth card made the second row taller than the first; a shared minimum
   keeps the card faces aligned at the 1280x800 GHL target. */
@media (min-width: 900px) {
  .reveal .slides section[data-step="c6-s4"] .card { min-height: 224px; box-sizing: border-box; }

  /* c6-mistakes and c6-checklist desktop: use the same reference-panel
     treatment so adjacent safety sections read as one consistent pair. */
  .reveal .slides section[data-step="c6-mistakes"] .mistakes ul,
  .reveal .slides section[data-step="c6-checklist"] .checklist ul {
    background: rgba(255, 255, 255, 0.84);
    border: 1px solid var(--line);
    border-radius: 12px;
    box-shadow: var(--shadow);
    box-sizing: border-box;
    padding: 0.35rem 1.15rem;
  }

  /* Controlled preview: a chapter opener gets slightly clearer hierarchy
     without changing its wording or sculpture placement. */
  .reveal .slides section[data-step="c1-title"] .chapter-title .num { margin-bottom: 0.8rem; }
  .reveal .slides section[data-step="c1-title"] .chapter-title h1 { line-height: 1; }
  .reveal .slides section[data-step="c1-title"] .chapter-title p.lead {
    margin-top: 1.25rem;
    line-height: 1.45;
  }

  /* Controlled preview: make the concept-slide takeaway read as a clear
     reference callout, matching the deck's existing hint treatment. */
  .reveal .slides section[data-step="c9-s3"] .concept .hint {
    background: var(--cream-2);
    border-left: 3px solid var(--orange);
    border-radius: 0 8px 8px 0;
    box-sizing: border-box;
    color: var(--ink);
    font-size: 20px;
    line-height: 1.4;
    margin-top: 0.85rem;
    padding: 0.8rem 1rem;
  }

  .reveal .slides section[data-step="c6-s4"] .concept .hint {
    background: var(--cream-2);
    border-left: 3px solid var(--orange);
    border-radius: 0 8px 8px 0;
    box-sizing: border-box;
    color: var(--ink);
    font-size: 18px;
    line-height: 1.3;
    margin-top: 0.65rem;
    padding: 0.5rem 0.8rem;
  }
}
/* .mistakes li font-size lives in the "Mistakes slide" block below (with
   padding/border/color), not here. Two declarations existed at once before
   and the later one in the file won the cascade, so the earlier value here
   was silently ignored. Keep it a single rule. */
.motion-in .sculpt { animation: sculpt-drift 18s ease-out forwards; }
@keyframes sculpt-drift {
  0%   { transform: scale(1.0) translateX(0); }
  100% { transform: scale(1.06) translateX(-1.2%); }
}

/* AI360 CPA corner logo - cover and outro only. Top-right is clear on both
   since headlines are left-aligned there. Home uses .kt-home-logo instead
   (in the header layout, not floating - see .kt-home-brand below). No other
   slide carries a logo: training/step slides stay clean per spec. */
.corner-logo {
  position: absolute;
  top: 28px; right: 36px;
  width: 84px; height: auto;
  z-index: 3;
  pointer-events: none;
}

/* Motion pass — concept/checklist/mistakes/chapter-title slides get a slow
   Ken-Burns drift + staggered card/line entrance on enter, so narration never
   plays over a dead-static screen. Triggered by adding/removing .motion-in
   via js/trainer.js on Reveal's slidechanged. */
.concept, .mistakes, .checklist, .tag-rules, .chapter-title {
  transform: scale(1);
  transform-origin: 50% 45%;
}
.motion-in .concept,
.motion-in .mistakes,
.motion-in .checklist,
.motion-in .tag-rules,
.motion-in .chapter-title {
  animation: slide-drift 14s ease-out forwards;
}
@keyframes slide-drift {
  0%   { transform: scale(1.015); }
  100% { transform: scale(1.045); }
}

.concept .card, .tag-rules .panel {
  opacity: 0; transform: translateY(14px);
}
.motion-in .concept .card, .motion-in .tag-rules .panel {
  animation: card-rise 620ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
}
.motion-in .concept .card:nth-child(1), .motion-in .tag-rules .panel:nth-child(1) { animation-delay: 120ms; }
.motion-in .concept .card:nth-child(2), .motion-in .tag-rules .panel:nth-child(2) { animation-delay: 280ms; }
.motion-in .concept .card:nth-child(3), .motion-in .tag-rules .panel:nth-child(3) { animation-delay: 440ms; }
.motion-in .concept .card:nth-child(4), .motion-in .tag-rules .panel:nth-child(4) { animation-delay: 600ms; }
@keyframes card-rise {
  to { opacity: 1; transform: translateY(0); }
}

.checklist li, .mistakes li {
  opacity: 0; transform: translateX(-10px);
}
.motion-in .checklist li, .motion-in .mistakes li {
  animation: line-slide 480ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
}
.motion-in .checklist li:nth-child(1), .motion-in .mistakes li:nth-child(1) { animation-delay: 100ms; }
.motion-in .checklist li:nth-child(2), .motion-in .mistakes li:nth-child(2) { animation-delay: 220ms; }
.motion-in .checklist li:nth-child(3), .motion-in .mistakes li:nth-child(3) { animation-delay: 340ms; }
.motion-in .checklist li:nth-child(4), .motion-in .mistakes li:nth-child(4) { animation-delay: 460ms; }
.motion-in .checklist li:nth-child(5), .motion-in .mistakes li:nth-child(5) { animation-delay: 580ms; }
.motion-in .checklist li:nth-child(6), .motion-in .mistakes li:nth-child(6) { animation-delay: 700ms; }
@keyframes line-slide {
  to { opacity: 1; transform: translateX(0); }
}

.motion-in .chapter-title h1 {
  animation: title-rise 700ms cubic-bezier(0.22, 1, 0.36, 1) both;
}
.motion-in .chapter-title p.lead {
  opacity: 0;
  animation: card-rise 620ms cubic-bezier(0.22, 1, 0.36, 1) forwards 260ms;
}
@keyframes title-rise {
  0% { opacity: 0; transform: translateY(10px); }
  100% { opacity: 1; transform: translateY(0); }
}

/* Respect reduced-motion preference */
@media (prefers-reduced-motion: reduce) {
  .motion-in .concept, .motion-in .mistakes, .motion-in .checklist,
  .motion-in .tag-rules, .motion-in .chapter-title,
  .motion-in .concept .card, .motion-in .tag-rules .panel,
  .motion-in .checklist li, .motion-in .mistakes li,
  .motion-in .chapter-title h1, .motion-in .chapter-title p.lead {
    animation: none !important; opacity: 1 !important; transform: none !important;
  }
}

/* Mistakes slide */
.mistakes { padding: 2.2rem 3rem; height: 100%; box-sizing: border-box; }
.mistakes h2 { font-size: 42px; color: #B23A2A; margin: 0.3rem 0 1rem; }
.mistakes ul { list-style: none; padding: 0; margin: 0; max-width: 66%; }
.mistakes li {
  padding: 0.72rem 0 0.72rem 2.2rem; position: relative;
  border-bottom: 1px solid var(--line); font-size: 26px; color: var(--ink);
  line-height: 1.5;
}
.mistakes li::before {
  content: "✕"; color: #B23A2A; position: absolute; left: 0.3rem; top: 0.62rem;
  font-weight: 700; font-size: 1.1em;
}

/* ul.misses: the same "what people get wrong" list, used inside .concept slides
   (c9-mistakes, c10-mistakes, c10-mistakes-b, c11-mistakes) instead of the .mistakes
   div wrapper. It had no dedicated rule at all until now, so it fell back to the
   ambient .reveal li font-size (0.85em) with default browser bullets, missing both
   the sizing and the x-mark treatment every other mistakes slide in the deck gets.
   Mirrors .mistakes/.mistakes li/.mistakes li::before exactly. */
/* max-width lives in the "text stops before art" cap above (63%), not here.
   Do not add max-width back on this line, same equal-specificity trap that
   silently overrode it once already. */
.concept ul.misses { list-style: none; padding: 0; margin: 0; }
.concept ul.misses li {
  padding: 0.72rem 0 0.72rem 2.2rem; position: relative;
  border-bottom: 1px solid var(--line); font-size: 26px; color: var(--ink);
  line-height: 1.5;
}
.concept ul.misses li::before {
  content: "✕"; color: #B23A2A; position: absolute; left: 0.3rem; top: 0.62rem;
  font-weight: 700; font-size: 1.1em;
}

/* ul.quiet: the five-case list inside a .step .caption (c9-s2), same slot as
   .caption p (grid-column 1, after the p, before the hint). Matches .caption p's
   font family and size (21px, set two blocks up), tighter line-height since it is
   a list, small square marker in the deck's orange/amber, the same color .target-arrow
   uses. Scoped to this one slide's pattern only, nothing else touched. */
.step .caption ul.quiet {
  grid-column: 1;
  font-family: -apple-system, "SF Pro Text", "Inter", system-ui, sans-serif;
  font-size: 21px; line-height: 1.35;
  margin: 0.4rem 0 0.6rem; padding-left: 1.1em;
  list-style: none; color: var(--ink-soft);
}
.step .caption ul.quiet li { position: relative; margin: 0.15rem 0; }
.step .caption ul.quiet li::before {
  content: ""; position: absolute; left: -1.1em; top: 0.45em;
  width: 0.4em; height: 0.4em; background: var(--orange);
}

/* ---- Trainer controls: chapter menu, play/pause, keyboard hint ---- */
.trainer-controls {
  position: fixed; top: 16px; right: 16px; z-index: 40;
  display: flex; align-items: center; gap: 8px;
  font-family: -apple-system, "SF Pro Text", "Inter", system-ui, sans-serif;
}
.trainer-btn {
  background: var(--cream); color: var(--ink);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 8px 14px; font-size: 13px; font-weight: 600;
  box-shadow: var(--shadow); cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px;
  transition: background 0.15s ease, transform 0.1s ease;
}
.trainer-btn:hover { background: white; transform: translateY(-1px); }
.trainer-btn:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }
.trainer-menu-btn { color: var(--orange); }

.trainer-hint {
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--cream); border: 1px solid var(--line); box-shadow: var(--shadow);
  color: var(--ink-soft); font-size: 13px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  cursor: help;
}

.trainer-menu-panel {
  position: fixed; top: 60px; right: 16px; z-index: 41;
  width: 300px; max-height: 70vh; overflow-y: auto;
  background: var(--cream); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--shadow); padding: 10px;
}
.trainer-menu-title {
  font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--orange); font-weight: 700; padding: 6px 10px 8px;
}
.trainer-menu-item {
  display: block; width: 100%; text-align: left;
  background: white; color: var(--ink); border: 1px solid var(--line);
  border-radius: 10px; padding: 9px 12px; margin-bottom: 6px;
  font-size: 14px; font-weight: 500; cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.trainer-menu-item:hover, .trainer-menu-item:focus-visible {
  background: var(--orange-soft); border-color: var(--orange); color: var(--ink);
  outline: none;
}
.trainer-menu-item:last-child { margin-bottom: 0; }

/* ==================================================================
   COURSE HOME (data-step="home", h-index 0) + LMS SIDEBAR
   Palette and card language lifted from nav-samples.html mocks #1/#2,
   sized for the deck's real 1280x800 Reveal canvas. Home cards and the
   rail rows are both built at runtime by js/trainer.js from the
   chapter markup already in this document, so nothing here duplicates
   slide copy.
   ================================================================== */

/* ---- Course home ---- */
.reveal .slides section:has(.kt-home) { height: 800px; }

.kt-home {
  height: 100%; box-sizing: border-box; padding: 2.1rem 2.6rem 1.6rem;
  display: flex; flex-direction: column; gap: 1.1rem; overflow-y: auto;
  position: relative; z-index: 2;
}
.kt-home-head {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: space-between; gap: 1.2rem;
}
.kt-home-brand {
  display: flex; align-items: center; gap: 1rem;
}
.kt-home-logo {
  width: 52px; height: 52px; object-fit: contain; flex-shrink: 0;
}
.kt-home-eyebrow {
  font-size: 13px; letter-spacing: 0.28em; text-transform: uppercase;
  color: var(--orange); font-weight: 700; margin-bottom: 0.35rem;
}
.kt-home-head h1 { font-size: 38px; margin: 0; line-height: 1.05; }
.kt-home-start {
  flex-shrink: 0; font-family: inherit;
  background: var(--orange); color: #fff; border: none; border-radius: 999px;
  padding: 0.8rem 1.4rem; font-size: 16px; font-weight: 600; cursor: pointer;
  box-shadow: var(--shadow); transition: background 0.15s ease, transform 0.1s ease;
}
.kt-home-start:hover { background: #d3691c; transform: translateY(-1px); }
.kt-home-start:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

.kt-home-grid {
  flex: 1; align-content: start;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.85rem;
}
.kt-chapter-card {
  background: white; border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--shadow); padding: 0.85rem; cursor: pointer; font-family: inherit;
  display: flex; flex-direction: column; gap: 0.45rem; text-align: left;
  position: relative; color: var(--ink);
  transition: transform 0.12s ease, border-color 0.12s ease;
}
.kt-chapter-card:hover { transform: translateY(-2px); border-color: var(--orange); }
.kt-chapter-card:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }
.kt-chapter-card .kt-thumb {
  height: 88px; border-radius: 10px; background: var(--cream-2); overflow: hidden; position: relative;
}
.kt-chapter-card .kt-thumb img { width: 100%; height: 100%; object-fit: contain; object-position: bottom right; }
.kt-chapter-card .kt-cnum {
  font-size: 12px; letter-spacing: 0.15em; text-transform: uppercase; color: var(--orange); font-weight: 700;
}
.kt-chapter-card .kt-ctitle { font-size: 17px; font-weight: 600; line-height: 1.2; }
.kt-chapter-card .kt-cmeta {
  margin-top: auto; font-size: 13px; color: var(--ink-soft);
  display: flex; align-items: center; justify-content: space-between;
}
.kt-chapter-card .kt-ring { flex-shrink: 0; }
.kt-chapter-card .kt-done-badge {
  position: absolute; top: 0.55rem; right: 0.55rem; width: 22px; height: 22px; border-radius: 50%;
  background: var(--orange); color: #fff; font-size: 12px; font-weight: 700;
  display: none; align-items: center; justify-content: center;
}
/* Toggled by js/trainer.js via updateProgressUI(), not the [hidden] attribute -
   an attribute-driven default would fight this file's own display rule above. */
.kt-chapter-card.is-done .kt-done-badge { display: flex; }

/* ---- LMS sidebar (fixed, lives outside the Reveal canvas like .trainer-controls) ---- */
.kt-rail-opener {
  position: fixed; top: 16px; left: 16px; z-index: 61;
  width: 40px; height: 40px; border-radius: 50%;
  background: var(--cream); border: 1px solid var(--line); box-shadow: var(--shadow);
  color: var(--ink); font-size: 17px; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.kt-rail-opener:hover { background: white; }
.kt-rail-opener:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }
body.kt-rail-open .kt-rail-opener { display: none; }

.kt-rail-scrim {
  position: fixed; inset: 0; z-index: 58; background: rgba(27,27,27,0.4);
  opacity: 0; pointer-events: none; transition: opacity 0.2s ease;
}

.kt-rail {
  position: fixed; top: 0; left: 0; bottom: 0; width: 300px; z-index: 60;
  background: var(--cream-2); border-right: 1px solid var(--line);
  display: flex; flex-direction: column;
  /* -100% (not a fixed px value) so the collapsed position always matches
     this element's own width, desktop 300px or the mobile 84vw below. */
  transform: translateX(-100%);
  transition: transform 0.22s ease;
  font-family: -apple-system, "SF Pro Text", "Inter", system-ui, sans-serif;
}
body.kt-rail-open .kt-rail { transform: translateX(0); }
/* Push the deck over on desktop only; below 900px the rail overlays instead
   (see the max-width block) so the canvas never gets crushed on a phone. */
body.kt-rail-open { margin-left: 300px; }

.kt-rail-header {
  flex: 0 0 auto; display: flex; align-items: center; gap: 0.6rem;
  padding: 14px 14px 8px;
}
.kt-rail-close {
  width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0;
  border: 1px solid var(--line); background: white; color: var(--ink);
  cursor: pointer; font-size: 14px; display: flex; align-items: center; justify-content: center;
}
.kt-rail-close:hover { background: var(--orange-soft); border-color: var(--orange); }
.kt-rail-title { font-size: 12px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-soft); }

/* Home: first row of the rail, above the chapter accordions - always
   reachable once the rail is open (see .kt-rail-home-opener below for the
   collapsed-rail equivalent). */
.kt-rail-home-row { flex: 0 0 auto; padding: 0 14px 10px; }
.kt-rail-home-btn {
  display: flex; align-items: center; gap: 0.5rem; width: 100%; box-sizing: border-box;
  text-align: left; font-family: inherit; background: white; color: var(--ink);
  border: 1px solid var(--line); border-radius: 10px; cursor: pointer;
  padding: 10px 12px; font-size: 14px; font-weight: 700;
}
.kt-rail-home-btn span:first-child { color: var(--orange); font-size: 16px; line-height: 1; }
.kt-rail-home-btn:hover { background: var(--orange-soft); border-color: var(--orange); }
.kt-rail-home-btn:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }

.kt-rail-scroll { flex: 1; overflow-y: auto; padding: 4px 10px 10px; }
.kt-rail-chapter { margin-bottom: 2px; }
.kt-rail-chap-btn {
  width: 100%; text-align: left; background: transparent; border: none; cursor: pointer; font-family: inherit;
  padding: 9px 8px; display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
  font-size: 14px; font-weight: 700; color: var(--ink); border-radius: 8px;
}
.kt-rail-chap-btn:hover { background: white; }
.kt-rail-chap-btn:focus-visible { outline: 2px solid var(--orange); outline-offset: -2px; }
.kt-rail-chap-btn .kt-rail-icon {
  width: 28px; height: 28px; border-radius: 8px; flex-shrink: 0; overflow: hidden;
  background: var(--cream-2); display: flex; align-items: center; justify-content: center;
}
.kt-rail-chap-btn .kt-rail-icon img { width: 100%; height: 100%; object-fit: contain; }
.kt-rail-chap-btn .kt-rail-label { flex: 1; min-width: 0; }
.kt-rail-chap-btn .kt-rail-arrow { color: var(--orange); font-size: 11px; flex-shrink: 0; transition: transform 0.15s ease; }
.kt-rail-chapter.open .kt-rail-chap-btn .kt-rail-arrow { transform: rotate(90deg); }
/* Current chapter - separate mark from .open (open is just the accordion's
   own expand state and can stay true for a row the reader left expanded). */
.kt-rail-chapter.current .kt-rail-chap-btn {
  background: var(--orange-soft); box-shadow: inset 3px 0 0 var(--orange); font-weight: 800;
}
.kt-rail-steps { display: none; padding-left: 8px; }
.kt-rail-chapter.open .kt-rail-steps { display: block; }
.kt-rail-step-btn {
  width: 100%; text-align: left; background: transparent; border: none; cursor: pointer; font-family: inherit;
  padding: 7px 9px; margin: 1px 0; font-size: 13px; color: var(--ink-soft); line-height: 1.3;
  border-radius: 6px; display: flex; gap: 0.5rem; align-items: flex-start;
}
.kt-rail-step-btn:hover { background: white; }
.kt-rail-step-btn:focus-visible { outline: 2px solid var(--orange); outline-offset: -2px; }
.kt-rail-step-btn.active { background: var(--orange-soft); color: var(--ink); font-weight: 600; }
.kt-rail-step-btn .kt-rail-chk { color: var(--orange); flex-shrink: 0; width: 1em; }

/* Icons-only toggle, header row (next to the ‹ close button) - shrinks the
   pane instead of hiding it, see body.kt-rail-mini below. */
.kt-rail-mini-toggle {
  width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0; margin-left: auto;
  border: 1px solid var(--line); background: white; color: var(--ink);
  cursor: pointer; font-size: 13px; display: flex; align-items: center; justify-content: center;
  transition: transform 0.15s ease, background 0.12s ease;
}
.kt-rail-mini-toggle:hover { background: var(--orange-soft); border-color: var(--orange); }
.kt-rail-mini-toggle:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }
body.kt-rail-mini .kt-rail-mini-toggle { transform: rotate(180deg); margin-left: 0; }

/* ---- Rail icons-only ("mini") state ----
   Keeps the pane on screen at icon width instead of collapsing it fully -
   built now for the future GHL per-chapter embed (its own course sidebar
   would otherwise fight this rail for the same strip); see
   window.ktTrainerRail in trainer.js. Declared after the 300px open-state
   rule above so it wins the cascade whenever both classes are present. */
body.kt-rail-mini .kt-rail { width: 64px; }
body.kt-rail-mini { margin-left: 64px; }
body.kt-rail-mini .kt-rail-header { justify-content: center; padding: 14px 6px 8px; gap: 0.3rem; }
body.kt-rail-mini .kt-rail-title,
body.kt-rail-mini .kt-rail-label,
body.kt-rail-mini .kt-rail-arrow,
body.kt-rail-mini .kt-rail-home-btn span:last-child {
  display: none;
}
/* Three classes (.kt-rail-chapter.open .kt-rail-steps) outweigh two classes
   plus a type selector on specificity alone, so the open-accordion's own
   "show my steps" rule would otherwise win over this one and leak the step
   list past the narrowed 64px pane - match its selector shape exactly. */
body.kt-rail-mini .kt-rail-chapter .kt-rail-steps,
body.kt-rail-mini .kt-rail-chapter.open .kt-rail-steps {
  display: none;
}
body.kt-rail-mini .kt-rail-chap-btn,
body.kt-rail-mini .kt-rail-home-btn {
  justify-content: center; padding-left: 4px; padding-right: 4px;
}

/* Collapsed-rail Home affordance: sits next to the ☰ opener strip so Home
   stays reachable without expanding the rail. Hides with the opener once
   the rail is open, where the in-rail Home row (above) takes over. */
.kt-rail-home-opener {
  position: fixed; top: 16px; left: 64px; z-index: 61;
  width: 40px; height: 40px; border-radius: 50%;
  background: var(--cream); border: 1px solid var(--line); box-shadow: var(--shadow);
  color: var(--orange); font-size: 18px; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.kt-rail-home-opener:hover { background: white; }
.kt-rail-home-opener:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }
body.kt-rail-open .kt-rail-home-opener { display: none; }

/* ---- Transport bar: fused to the bottom of the stage ----
   Replaces the two floating corner buttons this phase retires (the old
   bottom-left Auto-advance toggle that lived in the rail footer, and the
   old bottom-right position:fixed Pause button). Default rule below is the
   NO-STAGE fallback (home, cover, outro, chapter-title, checklist,
   mistakes, concept, tag-rules) - full viewport width, tracking the rail's
   left edge exactly like body's own margin-left above, since a
   position:fixed element ignores body margin. On any slide with a stage,
   js/trainer.js's positionTransportBar() sets top/left/width inline to
   the stage's own getBoundingClientRect() and adds .kt-transport-fused -
   that inline style wins the cascade over the left/right rules below, so
   the same element becomes a narrow bar glued to the stage instead. */
.kt-transport {
  /* box-sizing FIX 2026-09-21 (JOB 2): js/trainer.js's positionTransportBar()
     sets this element's width to the stage's own getBoundingClientRect()
     width. Content-box (the default) then adds this rule's left+right
     padding (32px) and, once .kt-transport-fused adds its 1px+1px border,
     2px more on top of that JS-set width, so the bar rendered ~34px wider
     than the stage it is meant to match exactly. border-box makes the
     JS-set width the bar's true outer width, flush with the stage edges. */
  box-sizing: border-box;
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
  display: flex; align-items: center; gap: 10px;
  padding: 10px 16px; background: var(--cream); border-top: 1px solid var(--line);
  box-shadow: 0 -2px 8px rgba(27,27,27,0.06);
  font-family: -apple-system, "SF Pro Text", "Inter", system-ui, sans-serif;
}
.kt-transport-fused {
  border-top: none; border-radius: 12px; border: 1px solid var(--line);
  box-shadow: var(--shadow);
}
body.kt-rail-open .kt-transport { left: 300px; }
body.kt-rail-mini .kt-transport { left: 64px; }
.kt-transport-btn { flex-shrink: 0; }
.kt-transport-prev, .kt-transport-next { padding: 8px 12px; }
.kt-transport-play.is-on { background: var(--ink); color: white; border-color: var(--ink); }
.kt-transport-counter {
  min-width: 56px; text-align: center; font-size: 13px; font-weight: 700;
  color: var(--ink-soft); font-variant-numeric: tabular-nums;
}
.kt-transport-auto { margin-left: auto; }
.kt-transport-auto.is-on { background: var(--orange); color: white; border-color: var(--orange); }

/* Desktop GHL frame: keep the floating controls large enough to target without
   changing the mobile drawer sizing. This follows the base rail rules so the
   desktop dimensions win the cascade. */
@media (min-width: 900px) {
  .trainer-btn { min-height: 44px; box-sizing: border-box; }
  .trainer-hint { width: 44px; height: 44px; }
  .kt-rail-opener, .kt-rail-home-opener, .kt-rail-close, .kt-rail-mini-toggle { width: 44px; height: 44px; }
}

/* Mobile: rail becomes an overlay drawer instead of pushing the deck over */
@media (max-width: 899px) {
  body.kt-rail-open { margin-left: 0; }
  .kt-rail { width: 84vw; max-width: 320px; }
  body.kt-rail-open .kt-rail-scrim { opacity: 1; pointer-events: auto; }
  body.kt-rail-open .kt-transport, body.kt-rail-mini .kt-transport { left: 0; }
  body.kt-rail-mini { margin-left: 0; }
  body.kt-rail-mini .kt-rail { width: 84vw; max-width: 320px; }
  /* Mobile has no room for a permanent icon strip - mini behaves like a
     normal open drawer there rather than a persistent narrow column. */
  body.kt-rail-mini .kt-rail-label,
  body.kt-rail-mini .kt-rail-steps,
  body.kt-rail-mini .kt-rail-home-btn span:last-child { display: inline; }
  body.kt-rail-mini .kt-rail-chapter.open .kt-rail-steps { display: block; }
}

/* Phone-width transport bar fix (2026-09-28): at ~390px the bar's inline
   width is set by positionTransportBar() to the STAGE's own rendered width
   (see js/trainer.js), which on a phone is far narrower than the five
   flex items (prev, pause, next, counter, auto-advance) need at their
   unscaled font-size - .kt-transport lives outside Reveal's scaled canvas,
   so its text never shrinks with the deck. The auto-advance button, pushed
   rightmost by margin-left:auto, was the one item still off after the
   others fit and rendered clipped past the visible right edge (confirmed
   live at kt-trainer-ghl.netlify.app, evidence/2026-09-28/live-phone-390x844.png).
   Fix: let the bar wrap instead of clip - prev/pause/next/counter keep one
   row, auto-advance drops to its own full-width row, centered, so nothing
   ever renders past the viewport edge. Also trims padding/gap so the first
   row has slack instead of running edge-to-edge. */
@media (max-width: 480px) {
  .kt-transport { flex-wrap: wrap; justify-content: center; gap: 6px 8px; padding: 8px 10px; }
  .kt-transport .trainer-btn { padding: 6px 10px; font-size: 12px; }
  .kt-transport-counter { min-width: 40px; font-size: 12px; }
  .kt-transport-auto { margin-left: 0; flex: 1 1 100%; justify-content: center; order: 1; }
}

/* Rendered click-motion chain clip (Remotion/BeatChain output) standing in for a
   before/after still pair. Sizes exactly like .stage img.shot.before did (fills
   whatever box .step .stage resolves to - the ~420px-tall Phase 2 stage box,
   see --kt-stage-h above), and turns off the JS-drawn floating arrow/badge
   since the video already bakes its own arrows, ripples, and crossfades into
   the pixels. See motion/README.md. */
.stage video.chain-clip {
  position: absolute; inset: 0;
  display: block;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center top;
}
.stage.video-chain .badge,
.stage.video-chain .target-arrow,
.stage.video-chain .target-arrow-pulse,
.stage.video-chain .target-ring,
.stage.video-chain .target-pulse {
  display: none !important;
}

/* Poster fallback for a chain clip that errors or stalls past 4 s (2C F2).
   The stage paints the poster as a background AND carries the fallback <img>
   above every other frame, so a stage that happens to be .clicked, or an image
   that fails to decode, still shows the frame instead of white. */
.stage.poster-fallback img.chain-poster-fallback {
  opacity: 1 !important;
  display: block !important;
  z-index: 3;
}
.stage.poster-fallback video.chain-clip { display: none !important; }

/* Enlarge button + lightbox (2026-09-25). The lightbox is appended to <body>,
   outside the Reveal-scaled canvas, so it renders at true screen pixels. */
.stage .kt-zoom-btn {
  position: absolute; right: 12px; bottom: 12px; z-index: 30;
  line-height: 1; font: 600 18px/1 -apple-system, "Inter", system-ui, sans-serif;
  padding: 10px 16px; border-radius: 10px; border: none; cursor: zoom-in;
  background: var(--orange); color: #fff; box-shadow: 0 6px 18px rgba(0,0,0,0.25);
}
.stage .kt-zoom-btn:hover { background: #cf6516; }
.stage .kt-zoom-btn:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; }
.stage img.shot { cursor: zoom-in; }
.kt-lightbox {
  position: fixed; inset: 0; z-index: 2147483000;
  background: rgba(20,20,20,0.92);
  display: flex; align-items: center; justify-content: center;
  padding: 48px 16px 40px; box-sizing: border-box; cursor: zoom-out;
}
.kt-lightbox img, .kt-lightbox video {
  max-width: 100%; max-height: 100%; width: auto; height: auto;
  object-fit: contain; border-radius: 8px; background: #fff;
  box-shadow: 0 20px 60px rgba(0,0,0,0.5);
}
.kt-lightbox-close {
  position: absolute; top: 10px; right: 12px;
  font: 600 16px/1 -apple-system, "Inter", system-ui, sans-serif;
  padding: 9px 14px; border-radius: 10px; border: none; cursor: pointer;
  background: #fff; color: var(--ink);
}
.kt-lightbox-hint {
  position: absolute; bottom: 12px; left: 0; right: 0; text-align: center;
  color: rgba(255,255,255,0.75); font: 14px -apple-system, "Inter", system-ui, sans-serif;
}
