/* ==========================================================
   ACT 2: CALLIE'S RESPONSE — RECOGNITION, TRIAGE, COOLING, TRANSPORT
   Callie and Tay: A Story About Heat Stroke in Dogs

   Deliberately built on Act 1's shell (same 16:9 viewport card, same HUD pill/button
   geometry, same speech-bubble components from act0-screen.css) so the two acts read as
   one product. What CHANGES is the temperature of the interface: Act 1's HUD is warm and
   playful, Act 2's is cooled and clinical, because the learner is now outside the dog.
   ========================================================== */

.act2-container {
  position: relative;
  width: 100%;
  height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: radial-gradient(circle at 50% 30%, #FFFDFB 0%, var(--palette-peach-light) 65%, var(--palette-peach) 100%);
  padding: 1rem;
  box-sizing: border-box;
  overflow: hidden;
}

/* Main 16:9 Cinematic Viewport Card — geometry matched to .act1-viewport-card.
   No low-cam tilt: Act 2's camera is at Callie's standing eyeline. */
.act2-viewport-card {
  position: relative;
  width: min(94vw, 1300px);
  aspect-ratio: 16 / 9;
  max-height: 84vh;
  border-radius: var(--radius-xl);
  overflow: hidden;
  box-shadow: var(--elev-card);
  border: 4px solid var(--palette-warm-white);
  background: var(--surface-card-dark);
  user-select: none;
  transition: filter 0.8s var(--ease-out-expo);
}

.act2-scene-img,
.act2-car-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
  /* Palette drain carried on from Act 1's escalation system. */
  filter: saturate(calc(100% - var(--act2-saturation-drop, 40%)));
  transition: filter 1.8s ease;
}

/* Heat wash — the Act 2 counterpart of Act 1's .shade-drift-overlay. */
.act2-heat-wash {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(circle at 30% 78%, rgba(255, 214, 150, 0.42) 0%, rgba(255, 170, 96, 0.2) 42%, transparent 76%),
    linear-gradient(to bottom, rgba(24, 20, 18, 0.28) 0%, transparent 38%);
  opacity: var(--act2-heat-opacity, 0.6);
  mix-blend-mode: multiply;
  transition: opacity 2s ease-in-out;
  z-index: 12;
}

/* ==========================================================
   HUD — TOP BAR
   ========================================================== */

.act2-hud-bar {
  position: absolute;
  top: 1.25rem;
  left: 1.5rem;
  right: 1.5rem;
  min-height: 48px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  pointer-events: none;
  z-index: 40;
}

.act2-hud-group {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  flex-wrap: wrap;
  pointer-events: auto;
}

.act2-hud-pill {
  background: var(--surface-hud);
  backdrop-filter: blur(10px);
  color: var(--text-inverse);
  border: 1.5px solid var(--hairline-light);
  font-family: var(--font-family-display);
  font-size: 0.88rem;
  font-weight: 700;
  height: 38px;
  padding: 0 1rem;
  border-radius: var(--radius-pill);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  box-shadow: var(--elev-3);
  box-sizing: border-box;
}

.act2-hud-pill.clock-pill {
  background: var(--surface-clock);
  border-color: var(--color-amber-tint);
  color: var(--text-inverse);
  letter-spacing: 0.02em;
}

/* The emergency clock. Appears at the decision and never leaves. */
.act2-hud-pill.elapsed-pill {
  background: var(--color-danger);
  border-color: var(--color-danger-pale);
  color: var(--text-inverse);
  letter-spacing: 0.05em;
  font-size: 0.78rem;
}

.act2-hud-pill.elapsed-pill .elapsed-value {
  font-size: 1rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  color: var(--text-inverse);
}

.act2-hud-pill.hints-pill {
  background: var(--color-danger);
  border-color: var(--color-danger-pale);
  color: var(--text-inverse);
  font-weight: 800;
  letter-spacing: 0.04em;
  animation: act2PulsePill 2s infinite;
}

.act2-hud-pill.hints-cashed-pill {
  background: var(--color-success);
  border-color: var(--color-success-pale);
  color: var(--text-inverse);
  font-weight: 800;
  letter-spacing: 0.03em;
}

.act2-hud-pill.checks-pill {
  background: var(--palette-teal-dark);
  border-color: var(--color-info);
  color: var(--text-inverse);
  transition: background-color var(--dur-base) ease, border-color var(--dur-base) ease;
}

.act2-hud-pill.checks-pill.all-done {
  background: var(--color-success);
  border-color: var(--color-success-pale);
  color: var(--text-inverse);
}

.act2-nudge-pill {
  font-family: var(--font-family-display);
  font-size: 0.82rem;
  font-weight: 500;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  padding: 0.3rem 0.8rem;
  background: rgba(15, 23, 42, 0.7);
  backdrop-filter: blur(4px);
  color: var(--text-inverse);
  border: none;
  box-shadow: none;
  border-radius: var(--radius-sm);
  pointer-events: none;
  cursor: default;
}

@keyframes act2PulsePill {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.04); }
}

/* ==========================================================
   BUTTONS — geometry matched to .act1-hud-btn
   ========================================================== */

.act2-hud-btn {
  background: var(--surface-hud-btn);
  backdrop-filter: blur(8px);
  color: var(--text-inverse);
  border: 1.5px solid var(--hairline-light);
  font-family: var(--font-family-display);
  font-size: 0.92rem;
  font-weight: 700;
  height: 40px;
  padding: 0 1.2rem;
  border-radius: var(--radius-pill);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  box-sizing: border-box;
  transition: background-color var(--dur-fast) var(--ease-out-expo),
              border-color var(--dur-fast) var(--ease-out-expo),
              opacity var(--dur-fast) var(--ease-out-expo),
              transform var(--dur-fast) var(--ease-out-expo);
  box-shadow: var(--elev-2);
  pointer-events: auto;
}

.act2-hud-btn:hover:not(:disabled),
.act2-hud-btn:focus-visible:not(:disabled) {
  background: var(--surface-hud-btn-hover);
  transform: translateY(-2px);
  border-color: var(--hairline-light-strong);
}

.act2-hud-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.act2-hud-btn.btn-action-primary {
  background: var(--color-heat);
  color: var(--text-inverse);
  border: 2px solid var(--color-amber-tint);
  font-weight: 800;
  box-shadow: 0 6px 20px rgba(194, 65, 12, 0.4);
}

.act2-hud-btn.btn-action-primary:hover:not(:disabled),
.act2-hud-btn.btn-action-primary:focus-visible:not(:disabled) {
  background: var(--color-heat-hover);
  border-color: var(--palette-warm-white);
  transform: translateY(-2px);
}

.act2-hud-btn.btn-action-primary.pulse-btn {
  animation: act2PulseBtn 1.8s infinite;
}

@keyframes act2PulseBtn {
  0%, 100% { box-shadow: 0 6px 20px rgba(194, 65, 12, 0.4); }
  50% { box-shadow: 0 6px 28px rgba(194, 65, 12, 0.75); }
}

/* Visible focus for every interactive element (WCAG 2.1 AA 2.4.7; design-language.md §7.2).
   Two rings by ground: amber over the scene / HUD chrome, teal on the light modal cards.
   Offset is kept at 3px so the ring is never clipped by the viewport card's overflow. */
#screen-act2 button:focus-visible,
#screen-act2 [role="button"]:focus-visible,
#screen-act2 [role="switch"]:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-on-dark);
  outline-offset: var(--focus-ring-offset);
  border-radius: var(--radius-sm);
}

#screen-act2 .act2-check-card button:focus-visible,
#screen-act2 .act2-payoff-card button:focus-visible,
#screen-act2 .act2-decision-card button:focus-visible,
#screen-act2 .act2-waiting-card button:focus-visible,
#screen-act2 .act2-cool-card button:focus-visible,
#screen-act2 .act2-cool-feedback button:focus-visible,
#screen-act2 .act2-handoff-card button:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-on-light);
  outline-offset: var(--focus-ring-offset);
}

.act2-nav-bar {
  position: absolute;
  bottom: 1.25rem;
  left: 1.5rem;
  right: 1.5rem;
  min-height: 48px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  pointer-events: none;
  z-index: 40;
}

/* ==========================================================
   SCENE LAYER — Tay down, Callie crouched, the cooler at the edge of frame
   ========================================================== */

.act2-scene-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 20;
}

.act2-speech-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 30;
}

/* When holding a modal dialog, out-rank the HUD bars (z-index 40) so the scrim covers chrome */
.act2-speech-layer.has-modal {
  z-index: 45;
}

/* ==========================================================
   CAMERA MODE 1: CLOSE CANOPY VIEW (arrival & call beats)
   Callie crouched with Tay proportioned naturally beside her.
   ========================================================== */

.act2-viewport-card.view-close-canopy .act2-callie-group {
  position: absolute;
  left: 4%;
  bottom: 0;
  top: auto;
  width: 44%;
  min-width: 260px;
  max-width: 520px;
  pointer-events: none;
  z-index: 15;
}

.act2-callie-img {
  width: 100%;
  height: auto;
  display: block;
  user-select: none;
  -webkit-user-drag: none;
  filter: drop-shadow(0 14px 28px rgba(24, 20, 18, 0.35));
}

/* Tay correctly proportioned as a French bulldog (~27% width) relative to Callie */
.act2-viewport-card.view-close-canopy .act2-tay-group {
  position: absolute;
  left: 36%;
  bottom: 3.5%;
  top: auto;
  width: 27%;
  min-width: 220px;
  aspect-ratio: 1376 / 768;
  pointer-events: none;
  z-index: 14;
}

/* Callie speech bubble in arrival & call — stem points down-left towards Callie's mouth */
.act2-viewport-card.view-close-canopy .act2-callie-bubble {
  position: absolute;
  top: 14%;
  left: 18%;
  max-width: min(380px, 32vw);
}

/* Stem sits near the left edge, but is placed from the right via --stem-right so Edit
   Mode's stem handle (which writes --stem-right on .callie-bubble) still moves it (§6.3).
   calc(100% - 58px) = the old left: 34px for a 24px-wide stem. */
.act2-viewport-card.view-close-canopy .act2-callie-bubble::before {
  left: auto;
  right: var(--stem-right, calc(100% - 58px));
  border-left: 6px solid transparent;
  border-right: 18px solid transparent;
  border-top: 22px solid var(--palette-brown-dark);
}

.act2-viewport-card.view-close-canopy .act2-callie-bubble::after {
  left: auto;
  right: calc(var(--stem-right, calc(100% - 58px)) + 2px);
  border-left: 5px solid transparent;
  border-right: 15px solid transparent;
  border-top: 19px solid var(--palette-warm-white);
}

.act2-viewport-card.view-close-canopy .act2-tay-final-bubble {
  position: absolute;
  bottom: 22%;
  top: auto;
  left: 42%;
  max-width: min(320px, 26vw);
}

.act2-viewport-card.view-close-canopy .act2-call-panel {
  top: 5rem;
  left: auto;
  right: 2rem;
  width: min(380px, 34%);
}

/* ==========================================================
   COMIC-BOOK ELECTRIC RADIO / PHONE SPEECH BUBBLE (Note 4)
   Sharp, angular, electric tech look for clinic audio over phone.
   ========================================================== */

.speech-bubble.phone-radio-bubble {
  position: absolute;
  background: var(--surface-radio);
  border: 3px solid var(--color-radio);
  color: var(--text-radio);
  border-radius: var(--radius-xs);
  box-shadow: 0 0 18px var(--color-radio-glow), var(--elev-modal);
  padding: 1.1rem 1.4rem;
  pointer-events: auto;
  z-index: 35;
  animation: bubblePop 0.3s var(--ease-back) both;
}

.speech-bubble.phone-radio-bubble .comic-radio-speaker {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  color: var(--color-info);
  font-family: var(--font-family-display);
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-bottom: 0.4rem;
}

/* Third voice, own colour treatment (design-language.md note, v1.1 pass) — but the same
   §6.3.1 dialogue metrics as every other bubble: display family, clamp(1rem,1.25vw,1.2rem),
   600, line-height 1.4. No documented reason to diverge, so it doesn't. */
.speech-bubble.phone-radio-bubble .comic-radio-text {
  font-family: var(--font-family-display);
  font-size: clamp(1rem, 1.25vw, 1.2rem);
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0.02em;
  color: var(--text-inverse);
  margin: 0;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85);
}

.speech-bubble.phone-radio-bubble .electric-lightning-tail {
  /* No clip-path on the bubble: it used to chamfer the corners and silently cut this off. */
  position: absolute;
  top: calc(100% - 3px); /* overlaps the 3px border so the join is seamless */
  left: -14px;
  width: 80px;
  height: 60px;
  pointer-events: none;
  filter: drop-shadow(0 2px 4px var(--color-radio-glow));
}

.act2-call-calling-pill {
  position: absolute;
  top: 5rem;
  left: 50%;
  transform: translateX(-50%);
  background: var(--surface-radio-pill);
  border: 2px solid var(--color-radio);
  color: var(--text-radio);
  font-family: var(--font-family-display);
  font-size: 0.95rem;
  font-weight: 700;
  padding: 0.6rem 1.4rem;
  border-radius: var(--radius-pill);
  box-shadow: 0 0 15px var(--color-radio-glow);
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  pointer-events: auto;
  z-index: 35;
}

/* ==========================================================
   CAMERA MODE 2: FIRST-PERSON VIEW (FPV) LOOKING DOWN (checks, gate, payoff, cooling)
   Callie's downward perspective looking at Tay on the grass.
   ========================================================== */

.act2-viewport-card.view-fpv-inspect .act2-tay-group {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 86%;
  max-width: 1120px;
  aspect-ratio: 1376 / 768;
  pointer-events: auto;
  z-index: 22;
}

/* Repositioned to upper-right to leave all 4 observation hotspots 100% unobstructed (Note 5) */
.act2-viewport-card.view-fpv-inspect .act2-call-panel {
  top: 4.8rem;
  left: auto;
  right: 2rem;
  width: min(340px, 28%);
}

.act2-tay-svg {
  width: 100%;
  height: auto;
  display: block;
  filter: drop-shadow(0 8px 18px rgba(0, 0, 0, 0.32));
}

/* Heavy labored breathing: abdominal and thoracic heaving anchored along the dorsal spine */
.act2-tay-labored-abdomen,
.act2-tay-svg .tay-labored-abdomen {
  transform-origin: 766px 240px;
  transform-box: view-box;
  animation: tayLaboredHeave 0.52s infinite ease-in-out;
}

/* FPV labored breathing strictly anchored to abdominal flank (Note 6, Note 5) */
.act2-tay-labored-abdomen.fpv-labored-abdomen,
.act2-tay-svg .fpv-labored-abdomen {
  transform-origin: 745px 225px;
  transform-box: view-box;
  animation: tayLaboredHeave 0.52s infinite ease-in-out;
}

@keyframes tayLaboredHeave {
  0%, 100% {
    transform: scale(1, 1);
  }
  35% {
    transform: scale(1.025, 1.075) translateY(2px);
  }
  65% {
    transform: scale(1.015, 1.04) translateY(1px);
  }
}

.act2-tay-svg.is-still .act2-tay-labored-abdomen,
.act2-tay-svg.is-still .tay-labored-abdomen,
.act2-tay-svg.is-still .act2-tay-chest,
.act2-tay-svg.is-still .act2-tay-tongue {
  animation: none;
}

/* Legacy 3rd-person positioning fallback */
.act2-tay-group {
  position: absolute;
  top: 66.5%;
  left: 68%;
  width: 16%;
  aspect-ratio: 1376 / 768;
  pointer-events: auto;
  z-index: 13;
}

.act2-callie-group {
  position: absolute;
  top: 56%;
  left: 57%;
  width: 11%;
  min-width: 95px;
  pointer-events: none;
  z-index: 14;
}

/* Pop-Up Shade Canopy — matches Act 1 position (top: 27%, left: 60%) */
.act2-canopy-group {
  position: absolute;
  top: 27%;
  left: 60%;
  width: 35%;
  height: 52%;
  pointer-events: none;
  z-index: 11;
  filter: drop-shadow(0 8px 16px rgba(0, 0, 0, 0.25));
}

.act2-canopy-group .canopy-shade-svg,
.act2-canopy-group .canopy-frame-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

.act2-canopy-group .canopy-shade-svg {
  transform: translateX(32%) scaleY(0.72);
  transform-origin: 50% 92%;
}

/* The Wooden Dock ("High Ground") — matches Act 1 position */
.act2-dock-group {
  position: absolute;
  top: 46%;
  left: 14%;
  width: 20%;
  height: 22%;
  transform: rotate(-9deg);
  pointer-events: none;
  z-index: 10;
}

.act2-dock-group svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* Water Bowl ("The Water One") — matches Act 1 position */
.act2-bowl-group {
  position: absolute;
  top: 79%;
  left: 45%;
  width: 9.5%;
  height: 10%;
  pointer-events: none;
  z-index: 10;
}

.act2-bowl-group svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* Callie's cooler ("The Vault") — matches Act 1 position (top: 63%, left: 38%) */
.act2-cooler-group {
  position: absolute;
  top: 63%;
  left: 38%;
  width: 11%;
  height: 13%;
  min-width: 80px;
  pointer-events: none;
  z-index: 12;
  opacity: 0.92;
  transition: opacity var(--transition-smooth, 0.35s ease), transform var(--transition-smooth, 0.35s ease);
}

.act2-cooler-group.is-tempting {
  opacity: 1;
  transform: translateY(-4px) scale(1.06);
}

.act2-cooler-svg {
  width: 100%;
  height: auto;
  display: block;
}

/* ---- The four observation hotspots (any order) ---- */

.act2-hotspot-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.act2-hotspot {
  position: absolute;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 2.5px solid var(--focus-ring-on-dark);
  background: var(--surface-hud);
  color: var(--text-inverse);
  font-size: 0.95rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  pointer-events: auto;
  box-shadow: var(--elev-4);
  transition: transform 0.2s var(--ease-out-expo), background 0.2s ease, border-color 0.2s ease;
  animation: act2HotspotInvite 2.2s ease-in-out infinite;
}

.act2-hotspot::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  min-width: 44px;
  min-height: 44px;
  width: 125%;
  height: 125%;
  pointer-events: auto;
}

.act2-hotspot:hover,
.act2-hotspot:focus-visible {
  transform: scale(1.14);
  background: var(--color-heat);
  border-color: var(--palette-warm-white);
}

.act2-hotspot.reported {
  background: var(--color-success);
  border-color: var(--color-success-pale);
  animation: none;
  cursor: default;
}

@keyframes act2HotspotInvite {
  0%, 100% { box-shadow: var(--elev-4), 0 0 0 0 var(--color-food-glow); }
  50% { box-shadow: var(--elev-4), 0 0 0 12px transparent; }
}

.act2-hotspot-tooltip {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  white-space: nowrap;
  background: var(--surface-tooltip);
  color: var(--text-inverse);
  font-family: var(--font-family-display);
  font-size: 0.76rem;
  font-weight: 700;
  padding: 0.3rem 0.65rem;
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--hairline-light);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
}

.act2-hotspot:hover .act2-hotspot-tooltip,
.act2-hotspot:focus-visible .act2-hotspot-tooltip {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* Observation Hotspots aligned with Tay FPV downward body */
.act2-hotspot.hotspot-ears    { left: 31%; top: 34%; }
.act2-hotspot.hotspot-gums    { left: 15%; top: 62%; }
.act2-hotspot.hotspot-name    { left: 19%; top: 40%; }
.act2-hotspot.hotspot-panting { left: 55%; top: 47%; }

/* ==========================================================
   BEAT: ARRIVAL — Tay's one subtitle, then the silence card
   ========================================================== */

.act2-tay-final-bubble {
  pointer-events: auto;
}

.act2-final-line-tag {
  display: block;
  margin-top: 0.5rem;
  padding-top: 0.45rem;
  border-top: 1px dashed rgba(56, 36, 24, 0.3);
  font-family: var(--font-family-display);
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-heat-hover);
}

.act2-silence-card {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(560px, 68%);
  background: rgba(24, 20, 18, 0.94);
  border: 2px solid var(--hairline-light-soft);
  border-radius: var(--radius-lg);
  padding: 2rem 2.25rem;
  text-align: center;
  color: var(--text-on-dark);
  box-shadow: var(--elev-modal);
  pointer-events: auto;
}

.act2-silence-mark {
  display: block;
  font-size: 2.4rem;
  line-height: 1;
  color: var(--palette-text-muted);
  margin-bottom: 0.6rem;
}

.act2-silence-line {
  font-family: var(--font-family-display);
  font-size: 1.5rem;
  font-weight: 800;
  margin-bottom: 0.6rem;
}

.act2-silence-sub {
  font-size: 0.98rem;
  line-height: 1.6;
  color: var(--text-on-dark-muted);
}

@keyframes act2FadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* ==========================================================
   BEAT 2A: THE PHONE CALL
   ========================================================== */

.act2-call-panel {
  position: absolute;
  top: 5.5rem;
  left: 2rem;
  right: auto;
  width: min(380px, 34%);
  pointer-events: auto;
  z-index: 34;
}

.act2-call-panel.is-docked {
  top: 5.5rem;
  left: 2rem;
  right: auto;
}

@keyframes act2SlideIn {
  from { opacity: 0.99; transform: translateX(-18px); }
  to { opacity: 1; transform: translateX(0); }
}

.act2-phone-bezel {
  background: var(--surface-card-dark);
  border: 3px solid var(--surface-chip-dark);
  border-radius: var(--radius-2xl);
  padding: 0.85rem;
  box-shadow: var(--elev-modal);
}

.act2-phone-header {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.55rem 0.7rem 0.75rem;
  border-bottom: 1px solid var(--hairline-light-faint);
}

.act2-phone-avatar {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--palette-teal-dark);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  flex-shrink: 0;
}

.act2-phone-meta {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.act2-phone-name {
  font-family: var(--font-family-display);
  font-size: 0.92rem;
  font-weight: 800;
  color: var(--text-on-dark);
}

.act2-phone-status {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--color-success-pale);
}

.act2-phone-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--color-success-pale);
  animation: act2PulseDot 1.6s ease-in-out infinite;
}

@keyframes act2PulseDot {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

.act2-phone-body {
  padding: 0.9rem 0.7rem 0.4rem;
}

.act2-phone-dialing {
  font-family: var(--font-family-display);
  font-size: 1rem;
  font-weight: 700;
  color: var(--text-on-dark-muted);
  text-align: center;
  padding: 1.2rem 0;
  letter-spacing: 0.03em;
}

.act2-phone-line {
  border-left: 4px solid var(--color-info);
  padding-left: 0.8rem;
  margin-bottom: 0.4rem;
}

.act2-phone-line.line-callie {
  border-left-color: var(--color-heat);
}

.act2-phone-line-who {
  display: block;
  font-family: var(--font-family-display);
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-info-pale);
  margin-bottom: 0.25rem;
}

.act2-phone-line-text {
  font-family: var(--font-family-display);
  font-size: clamp(1rem, 1.25vw, 1.2rem);
  font-weight: 600;
  line-height: 1.4;
  color: var(--text-on-dark);
}

.act2-phone-hint {
  margin-top: 0.75rem;
  font-family: var(--font-family-display);
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--color-amber-tint);
  text-align: center;
}

.act2-triage-list {
  list-style: none;
  margin: 0.9rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.act2-triage-item {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.4rem 0.6rem;
  border-radius: var(--radius-sm);
  background: var(--hairline-light-faint);
  font-size: 0.86rem;
  color: var(--text-on-dark-muted);
}

.act2-triage-item.is-done {
  background: color-mix(in srgb, var(--color-success) 32%, transparent);
  color: var(--text-inverse);
}

.act2-triage-item.is-missing {
  background: color-mix(in srgb, var(--color-danger) 32%, transparent);
  color: var(--text-inverse);
}

.act2-triage-mark {
  font-weight: 800;
  width: 1rem;
  text-align: center;
  flex-shrink: 0;
}

.act2-triage-label {
  font-weight: 700;
  font-family: var(--font-family-display);
}

.act2-triage-state {
  margin-left: auto;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  opacity: 0.85;
}

/* ==========================================================
   BEAT 2A: AN OPENED OBSERVATION CHECK
   ========================================================== */

.act2-check-modal {
  position: absolute;
  inset: 0;
  background: rgba(18, 15, 13, 0.72);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
  pointer-events: auto;
  z-index: 50;
}

.act2-check-card {
  width: min(860px, 100%);
  max-height: 100%;
  overflow-y: auto;
  background: var(--palette-cream);
  border: 3px solid var(--palette-warm-white);
  border-radius: var(--radius-lg);
  box-shadow: var(--elev-modal);
  padding: 1.2rem 1.4rem 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}

.act2-check-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.act2-check-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  background: var(--palette-teal-dark);
  color: var(--text-inverse);
  font-family: var(--font-family-display);
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.07em;
  padding: 0.35rem 0.8rem;
  border-radius: var(--radius-pill);
}

.act2-check-close {
  background: transparent;
  border: 2px solid rgba(56, 36, 24, 0.25);
  color: var(--palette-brown-med);
  font-family: var(--font-family-display);
  font-size: 0.82rem;
  font-weight: 700;
  padding: 0.35rem 0.85rem;
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: background-color var(--dur-fast) ease, border-color var(--dur-fast) ease;
}

.act2-check-close:hover,
.act2-check-close:focus-visible {
  background: rgba(56, 36, 24, 0.08);
  border-color: rgba(56, 36, 24, 0.5);
}

.act2-check-body {
  /* The card is a flex column with max-height:100%. Without min-height:0 the body keeps
     its flex-computed height while its content runs past the bottom edge, and the nav row
     lands on top of the readouts. 0 lets it shrink to the space available; overflow-y
     makes it scroll rather than spill, so the nav always sits clear.
     The floor that used to live here (190px) now comes from .act2-check-conversation,
     which sets its own min-height — a second declaration here would just fight it. */
  min-height: 0;
  overflow-y: auto;
}

.act2-check-tech-line {
  background: color-mix(in srgb, var(--palette-teal) 10%, var(--palette-warm-white));
  color: var(--palette-text-dark);
  border-radius: var(--radius-xl);
  border-bottom-left-radius: var(--radius-xs);
  padding: 0.8rem 1.1rem;
  max-width: 85%;
  align-self: flex-start;
}
.act2-check-tech-line .speech-bubble-speaker {
  color: var(--palette-teal-dark);
  margin-bottom: 0.2rem;
}

.act2-check-callie-line {
  background: var(--palette-peach-light);
  color: var(--palette-text-dark);
  border-radius: var(--radius-xl);
  border-bottom-right-radius: var(--radius-xs);
  padding: 0.8rem 1.1rem;
  max-width: 85%;
  align-self: flex-end;
}
.act2-check-callie-line .speech-bubble-speaker {
  color: var(--palette-brown-dark);
  margin-bottom: 0.2rem;
}

.act2-check-art {
  display: grid;
  /* Conversation gets the wider column: at the §6.3.1 dialogue size the old 1.3fr/1fr split
     made the three-line exchange scroll while empty space sat under the art. */
  grid-template-columns: minmax(220px, 1fr) minmax(240px, 1.15fr);
  gap: 1rem;
  /* start, not stretch: the right column sizes to its OWN content and the row grows to
     whichever column is taller. Stretching it to the image height is what squeezed the
     conversation to nothing. */
  align-items: start;
}

.act2-check-svg {
  width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
  display: block;
}

/* Character-accurate check art media frames (Notes 8, 9, 10) */
.act2-check-art-media {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 2;
  border-radius: var(--radius-sm);
  overflow: hidden;
  box-shadow: var(--elev-2);
  background: var(--surface-art-mat);
  border: 2px solid rgba(56, 36, 24, 0.15);
}

.act2-check-right-col {
  display: flex;
  flex-direction: column;
}

/* The conversation owns a real, bounded band of its own.
   It previously lived in a `height: 0; min-height: 100%` column pinned to the image's
   height, where the readouts consumed nearly all of it — leaving the conversation 19px
   tall holding 444px of content. All three dialogue lines were in the DOM and scrolled
   into a sliver nobody could see. Bound it explicitly and let the card grow instead. */
.act2-check-conversation {
  min-height: 190px;
  /* Raised once the readout panels came out of this column: all three lines of the
     exchange now fit without scrolling, so Dana's opening question stays on screen while
     the learner reads Callie's reply. Still capped, so a long line cannot grow the card
     past the viewport — it scrolls at that point instead. */
  max-height: 440px;
  overflow-y: auto;
  padding-right: 0.5rem;
  margin-bottom: 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

/* Internal scrollbar for the conversation */
.act2-check-conversation::-webkit-scrollbar {
  width: 4px;
}
.act2-check-conversation::-webkit-scrollbar-thumb {
  background: var(--hairline-light-strong);
  border-radius: var(--radius-pill);
}

.act2-check-readout-wrap {
  flex-shrink: 0;
}

.act2-check-char-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Gums: animated thumb press and capillary refill (Note 8) */
.act2-check-art[data-editor-id="act2-art-gums"] .act2-check-art-media {
  aspect-ratio: 1376 / 768;
}

.act2-gum-blanch {
  position: absolute;
  left: var(--blanch-x, 59.1%);
  top: var(--blanch-y, 59.9%);
  /* Sized to stay READABLE in the modal, where the plate renders about 445px wide. At 3%
     the blanched spot was ~13px and the refill was easy to miss — and a refill nobody can
     see teaches nothing. Still small enough to sit inside the exposed gum. */
  width: var(--blanch-w, 4.6%);
  height: var(--blanch-h, 6.2%);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background-color: var(--gum-color);
  pointer-events: none;
  animation: act2GumBlanchAnim var(--cycle-total, 4s) infinite;
}

.act2-gum-hand {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  animation: act2GumHandAnim var(--cycle-total, 4s) infinite;
}

/* Ears: animated thermal waves (Note 9) */
.act2-ear-heat-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.act2-ear-heat-waves {
  animation: act2HeatWaves 1.8s infinite ease-in-out;
}

@keyframes act2HeatWaves {
  0%, 100% {
    opacity: 0.45;
    transform: translateY(0);
  }
  50% {
    opacity: 0.88;
    transform: translateY(-5px);
  }
}

/* Panting: distressed breathing heave (Note 10) */
.act2-panting-img-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 2;
  border-radius: var(--radius-sm);
  overflow: hidden;
  box-shadow: var(--elev-2);
  grid-row: span 2;
  background: var(--surface-art-mat);
  border: 2px solid rgba(56, 36, 24, 0.15);
}

.act2-panting-img-wrap .act2-check-char-img {
  transform-origin: 50% 75%;
  animation: act2PantPulse 0.38s infinite ease-in-out;
}

@keyframes act2PantPulse {
  0%, 100% {
    transform: scale(1, 1);
  }
  40% {
    transform: scale(1.025, 1.045) translateY(-2px);
  }
}

.act2-check-readout {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.act2-check-readout > div {
  background: var(--palette-warm-white);
  border: 1.5px solid rgba(56, 36, 24, 0.14);
  border-radius: var(--radius-sm);
  padding: 0.55rem 0.75rem;
}

.act2-check-readout dt {
  font-family: var(--font-family-display);
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--palette-text-muted);
  margin-bottom: 0.15rem;
}

.act2-check-readout dd {
  margin: 0;
  font-size: 0.94rem;
  font-weight: 600;
  line-height: 1.45;
  color: var(--palette-text-dark);
}





.act2-heat-lines path {
  animation: act2HeatRise 2.2s ease-in-out infinite;
}

@keyframes act2HeatRise {
  0%, 100% { opacity: 0.35; transform: translateY(2px); }
  50% { opacity: 0.9; transform: translateY(-2px); }
}

.act2-pant-trace {
  animation: act2PantSlide 1.1s linear infinite;
}

.act2-pant-trace.is-still {
  animation: none;
}

@keyframes act2PantSlide {
  from { transform: translateX(0); }
  to { transform: translateX(-44px); }
}

/* Name-response counting strip: a count, not a colour. */
.act2-count-strip {
  display: flex;
  gap: 0.3rem;
  margin-top: 0.6rem;
}

.act2-count-tick {
  flex: 1;
  text-align: center;
  font-family: var(--font-family-display);
  font-size: 0.8rem;
  font-weight: 800;
  padding: 0.3rem 0;
  border-radius: var(--radius-xs);
  background: var(--palette-peach);
  color: var(--palette-text-muted);
  border: 2px solid transparent;
}

.act2-count-tick.counted {
  background: color-mix(in srgb, var(--color-heat) 18%, var(--palette-warm-white));
  color: var(--color-heat-deep);
}

.act2-count-tick.is-final {
  background: var(--color-heat-hover);
  color: var(--text-inverse);
  border-color: var(--palette-text-dark);
}



.act2-check-nav {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 1rem;
  padding-top: 0.5rem;
  border-top: 1px solid rgba(56, 36, 24, 0.12);
}





/* ==========================================================
   BEAT 2A: THE HINTS-DROPPED PAYOFF
   ========================================================== */

.act2-payoff-card,
.act2-decision-card,
.act2-waiting-card,
.act2-cool-card ,
.act2-handoff-card {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(880px, 88%);
  max-height: 78%;
  overflow-y: auto;
  background: var(--palette-cream);
  border: 3px solid var(--palette-warm-white);
  border-radius: var(--radius-lg);
  box-shadow: var(--elev-modal);
  padding: 1.4rem 1.6rem;
  pointer-events: auto;
  z-index: 45;
}

/* Entrances run once per beat (guideline-persistent-cards.md, Rule 1). The cooling card is
   keyed on its step instead, so each new cooling step still slides in. Transport/handoff are
   untouched pending the car-scene revamp. */
.is-entering .act2-payoff-card,
.is-entering .act2-decision-card,
.is-entering .act2-waiting-card,
.act2-cool-card.is-new-line,
.act2-handoff-card {
  animation: act2CardIn 0.35s var(--ease-out-expo) forwards;
}

@keyframes act2CardIn {
  from { opacity: 0.99; transform: translate(-50%, -48%) scale(0.97); }
  to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

.act2-payoff-header { margin-bottom: 0.75rem; }

.act2-payoff-badge {
  display: inline-block;
  background: var(--color-danger);
  color: var(--text-inverse);
  font-family: var(--font-family-display);
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  padding: 0.28rem 0.7rem;
  border-radius: var(--radius-xs);
  margin-bottom: 0.55rem;
}

.act2-payoff-title,
.act2-decision-title,
.act2-waiting-title,
.act2-transport-title,
.act2-handoff-title {
  font-family: var(--font-family-display);
  font-size: 1.5rem;
  font-weight: 800;
  line-height: 1.25;
  color: var(--palette-brown-dark);
}

.act2-payoff-timeline {
  list-style: none;
  margin: 0 0 0.8rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.act2-payoff-item {
  display: grid;
  grid-template-columns: 84px 1fr;
  gap: 0.7rem;
  align-items: center;
  background: var(--palette-warm-white);
  border: 1.5px solid rgba(56, 36, 24, 0.14);
  border-left: 5px solid var(--color-heat);
  border-radius: var(--radius-sm);
  padding: 0.45rem 0.8rem;
}

.act2-payoff-time {
  font-family: var(--font-family-display);
  font-size: 0.86rem;
  font-weight: 800;
  color: var(--color-heat-hover);
  font-variant-numeric: tabular-nums;
}


.act2-payoff-copy {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  font-size: 0.92rem;
  line-height: 1.45;
  color: var(--palette-text-dark);
}

.act2-payoff-copy strong {
  font-family: var(--font-family-display);
  font-size: 0.98rem;
}

.act2-payoff-tech {
  background: color-mix(in srgb, var(--palette-teal) 10%, var(--palette-warm-white));
  border-left: 5px solid var(--palette-teal);
  border-radius: var(--radius-sm);
  padding: 0.8rem 1rem;
  font-family: var(--font-family-display);
  font-size: clamp(1rem, 1.25vw, 1.2rem);
  font-weight: 600;
  line-height: 1.4;
  color: var(--palette-text-dark);
}

/* The payoff button flows at the END of the card's content. It must NOT be absolutely
   positioned: the payoff card is max-height capped with overflow-y:auto, so a pinned
   button hovers in place while the case-history timeline and Dana's closing line scroll
   underneath it — which is exactly what it was doing.
   It shared a comma group with .act2-transport-footer, whose absolute positioning is
   correct for the car scene; the two are separated now so one cannot drag the other. */
.act2-payoff-footer {
  display: flex;
  justify-content: center;
  margin-top: 1rem;
  pointer-events: auto;
}

/* The arrive button lives in the car scene, not in a panel footer. Pinned to the bottom
   centre over the steering wheel — the only band of the plate clear of both the AC panel
   (right) and the door switch cluster (left). Left in normal flow it landed on top of the
   AC hotspot and swallowed its clicks. */
.act2-transport-footer {
  position: absolute;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 40;
  pointer-events: auto;
}

/* ==========================================================
   BEAT 2B: THE DECISION, AND WHAT WAITING COSTS
   ========================================================== */

.act2-decision-badge,
.act2-waiting-badge,
.act2-cool-badge,
.act2-transport-badge {
  display: inline-block;
  background: var(--palette-brown-dark);
  color: var(--palette-peach);
  font-family: var(--font-family-display);
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  padding: 0.26rem 0.7rem;
  border-radius: var(--radius-xs);
  margin-bottom: 0.6rem;
}

.act2-decision-sub {
  font-size: 1rem;
  line-height: 1.55;
  color: var(--palette-text-muted);
  margin: 0.5rem 0 1.1rem;
}

.act2-decision-options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 0.9rem;
}

.act2-decision-option,
.act2-cool-option {
  text-align: left;
  background: var(--palette-warm-white);
  border: 2.5px solid rgba(56, 36, 24, 0.16);
  border-radius: var(--radius-md);
  padding: 1rem 1.1rem;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  font-family: var(--font-family-body);
  transition: border-color var(--dur-fast) var(--ease-out-expo),
              box-shadow var(--dur-fast) var(--ease-out-expo),
              transform var(--dur-fast) var(--ease-out-expo);
}

.act2-decision-option:hover,
.act2-decision-option:focus-visible,
.act2-cool-option:hover,
.act2-cool-option:focus-visible {
  border-color: var(--color-heat);
  transform: translateY(-3px);
  box-shadow: 0 12px 26px rgba(56, 36, 24, 0.18);
}

.act2-decision-option-title,
.act2-cool-option-label {
  font-family: var(--font-family-display);
  font-size: 1.05rem;
  font-weight: 800;
  color: var(--palette-brown-dark);
}

.act2-decision-option-sub {
  font-size: 0.9rem;
  line-height: 1.45;
  color: var(--palette-text-muted);
}

.act2-waiting-line,
.act2-waiting-note {
  font-size: 1rem;
  line-height: 1.6;
  color: var(--palette-text-dark);
  margin-top: 0.7rem;
}

.act2-waiting-note {
  background: color-mix(in srgb, var(--palette-teal) 10%, var(--palette-warm-white));
  border-left: 5px solid var(--palette-teal);
  border-radius: var(--radius-sm);
  padding: 0.75rem 0.95rem;
  font-weight: 600;
}

.act2-waiting-delta {
  margin-top: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
}

.act2-delta-row {
  display: grid;
  grid-template-columns: minmax(140px, 1fr) auto 28px auto;
  gap: 0.6rem;
  align-items: center;
  background: var(--palette-warm-white);
  border: 1.5px solid rgba(56, 36, 24, 0.14);
  border-radius: var(--radius-sm);
  padding: 0.55rem 0.8rem;
}

.act2-delta-label {
  font-family: var(--font-family-display);
  font-size: 0.86rem;
  font-weight: 800;
  color: var(--palette-brown-dark);
}

.act2-delta-before {
  font-size: 0.9rem;
  color: var(--palette-text-muted);
  text-decoration: line-through;
}

.act2-delta-arrow { color: var(--color-heat); font-weight: 800; text-align: center; }

.act2-delta-after {
  font-family: var(--font-family-display);
  font-size: 0.98rem;
  font-weight: 800;
  color: var(--color-heat-hover);
}

/* ==========================================================
   BEAT 2C: COOLING
   ========================================================== */

.act2-cool-head,
.act2-transport-head {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  flex-wrap: wrap;
  margin-bottom: 0.7rem;
}

.act2-cool-step-label {
  font-family: var(--font-family-display);
  font-size: 1.05rem;
  font-weight: 800;
  color: var(--palette-brown-dark);
}

.act2-cool-prompt {
  background: color-mix(in srgb, var(--palette-teal) 10%, var(--palette-warm-white));
  border-left: 5px solid var(--palette-teal);
  border-radius: var(--radius-sm);
  padding: 0.75rem 0.95rem;
  font-family: var(--font-family-display);
  font-size: clamp(1rem, 1.25vw, 1.2rem);
  font-weight: 600;
  line-height: 1.4;
  color: var(--palette-text-dark);
  margin-bottom: 0.7rem;
}

.act2-cool-prompt .act2-phone-line-who,
.act2-payoff-tech .act2-phone-line-who {
  color: var(--palette-teal);
}

/* The received wisdom the learner probably arrived with, stated plainly and left unattributed.
   Nobody in the scene is saying it, so nobody in the scene has to be humiliated for it being
   wrong. Styled as a quiet aside, deliberately NOT as dialogue — no speaker, no quote marks. */
.act2-belief-line {
  background: color-mix(in srgb, var(--palette-sage) 12%, var(--palette-warm-white));
  border-left: 5px solid var(--palette-sage);
  border-radius: var(--radius-sm);
  padding: 0.7rem 0.95rem;
  font-size: 1rem;
  line-height: 1.5;
  font-style: italic;
  color: var(--palette-brown-med);
  margin-bottom: 0.9rem;
}

.act2-belief-who {
  display: block;
  font-family: var(--font-family-display);
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--palette-teal-dark);
  font-style: normal;
  margin-bottom: 0.2rem;
}

.act2-cool-options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 0.9rem;
}

/* ---- Consequence + correction. Never a game over. ---- */

.act2-cool-feedback {
  background: var(--palette-warm-white);
  border: 3px solid var(--palette-warm-white);
  border-radius: var(--radius-lg);
  padding: 1.1rem 1.3rem;
}
.act2-cool-feedback.is-right { border-color: var(--color-success-pale); }
.act2-cool-feedback.is-wrong { border-color: var(--color-danger-pale); }

.act2-cool-feedback-head {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  flex-wrap: wrap;
  margin-bottom: 0.8rem;
}

.act2-cool-feedback-tag {
  font-family: var(--font-family-display);
  font-size: 0.74rem;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  padding: 0.28rem 0.7rem;
  border-radius: var(--radius-xs);
}

.act2-cool-feedback.is-right .act2-cool-feedback-tag {
  background: var(--color-success);
  color: var(--text-inverse);
}

.act2-cool-feedback.is-wrong .act2-cool-feedback-tag {
  background: var(--color-danger);
  color: var(--text-inverse);
}

.act2-cool-feedback-body {
  font-size: 1.02rem;
  line-height: 1.6;
  color: var(--palette-text-dark);
  margin-bottom: 0.9rem;
}

.act2-cool-correction {
  background: color-mix(in srgb, var(--color-amber) 10%, var(--palette-warm-white));
  border: 2px solid var(--color-amber-tint);
  border-radius: var(--radius-sm);
  padding: 0.85rem 1rem;
}

.act2-cool-correction-tag {
  display: block;
  font-family: var(--font-family-display);
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-heat-hover);
  margin-bottom: 0.35rem;
}

.act2-cool-correction p {
  font-size: 0.98rem;
  line-height: 1.55;
  color: var(--palette-text-dark);
}

.act2-cool-nofail {
  margin-top: 0.75rem;
  font-family: var(--font-family-display);
  font-size: 0.92rem;
  font-weight: 700;
  color: var(--palette-teal-dark); /* sage fails AA on light — §2.4 approved teal-dark instead */
}

/* The flat, factual third voice — same component as Act 1's truth stamp. */
.act2-truth-stamp {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  background: var(--palette-text-dark);
  border-radius: var(--radius-sm);
  padding: 0.85rem 1rem;
  color: var(--text-on-dark);
}

.act2-truth-stamp-metric {
  font-family: var(--font-family-display);
  font-size: 0.8rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-amber-tint);
}

.act2-truth-stamp-line {
  font-size: 0.98rem;
  line-height: 1.55;
}

.act2-cool-feedback-footer {
  display: flex;
  justify-content: flex-end;
  margin-top: 1rem;
}

/* ==========================================================
   BEAT 2D: TRANSPORT MICRO-SIM
   ========================================================== */



/* ==========================================================
   TUNABLE COORDINATES — FPV Car Interior
   ========================================================== */
.act2-transport-scene {
  --ac-left: 79.8%;
  --ac-top: 82.9%;
  --ac-size: 7%;

  /* The painted mirror's glass, measured off Car-FPV-Interior.jpg (x 1257-1762,
     y 118-266 of 1920x1080), inset a hair so the image never covers the frame. */
  --mirror-left: 65.6%;
  --mirror-top: 11.2%;
  --mirror-width: 26.1%;
  --mirror-height: 13.4%;

  /* The driver's side window, measured off Car-FPV-Interior.jpg: the box is its bounding
     rectangle, --win-shape its outline inside that box (frame edge, quarter-light post,
     door sill). */
  --win-left: 0%;
  --win-top: 0%;
  --win-width: 21.6%;
  --win-height: 78%;
  --win-shape: polygon(0% 1.8%, 24.1% 5.7%, 45.8% 11.6%, 57.9% 17.6%, 67.5% 26.7%, 79.6% 37.7%,
    91.6% 47.5%, 98.9% 56.4%, 99.6% 86.4%, 0% 99.1%);
  --win-drop: 24%;          /* how far the glass slides down when cracked */

  /* Where the road's two edge lines meet in the painting. */
  --vp-left: 62.6%;
  --vp-top: 34.5%;

  /* Vent centres (the middle of each grille). */
  --vent1-left: 30.6%;
  --vent1-top: 76%;
  --vent2-left: 66.9%;
  --vent2-top: 76%;
  --vent3-left: 92.2%;
  --vent3-top: 76%;

  /* One dash-plus-gap of road passes under the car per cycle. */
  --road-dash-cadence: 1.1s;
  
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.act2-rear-view-mirror {
  position: absolute;
  left: var(--mirror-left);
  top: var(--mirror-top);
  width: var(--mirror-width);
  height: var(--mirror-height);
  overflow: hidden;
  /* the glass's corners: small at the top, the bottom-right sweeps round */
  border-radius: 4% 4% 14% 5% / 14% 14% 30% 16%;
  /* Clips everything drawn inside, Tay's heaving flank included, to the glass. */
  clip-path: inset(0 round 4% 4% 14% 5% / 14% 14% 30% 16%);
  z-index: 10;
}

.act2-car-overlays {
  position: absolute;
  inset: 0;
  z-index: 20;
}

/* --- Task B: Window rolls down --- */
/* The aperture is cut to the painted window's outline, and the glass is the same outline,
   so it fills the frame exactly when shut. Cracking it slides the glass straight down: its
   top edge keeps the frame's shape, and the aperture hides whatever drops below the sill. */
.act2-window-aperture {
  position: absolute;
  left: var(--win-left);
  top: var(--win-top);
  width: var(--win-width);
  height: var(--win-height);
  clip-path: var(--win-shape);
  pointer-events: none;
}
/* Wind streaks in the gap the lowered glass opens (clipped to that band in the SVG).
   They fade in once the glass is on its way down. */
.act2-wind-gap {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 0.3s ease;
}
.act2-transport-scene.windows-open .act2-wind-gap {
  opacity: 1;
  transition-delay: 0.35s;
}
.act2-wind-line {
  fill: none;
  stroke: var(--hairline-light-strong);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-dasharray: 9 23;
  stroke-dashoffset: 32;
}
.act2-transport-scene.windows-open .act2-wind-line {
  animation: act2WindStreak 0.55s linear infinite;
}
@keyframes act2WindStreak {
  from { stroke-dashoffset: 32; }
  to   { stroke-dashoffset: 0; }
}
.act2-window-pane {
  position: absolute;
  inset: 0;
  clip-path: var(--win-shape);
  /* The glass's top rim: the pane is drawn in the rim colour, and the tinted glass
     (::after, the same outline nudged down) covers all but a thin band along the top. */
  background: var(--hairline-light-strong);
  transition: transform 0.6s cubic-bezier(0.4, 0.0, 0.2, 1);
  transform: translateY(0);
}
.act2-window-pane::after {
  content: '';
  position: absolute;
  inset: 0;
  clip-path: var(--win-shape);
  transform: translateY(4px);
  background-color: rgba(214, 236, 250, 0.38);
  background-image: linear-gradient(135deg, rgba(255,255,255,0.35) 0%, rgba(255,255,255,0) 30%, rgba(255,255,255,0) 100%);
}
.act2-transport-scene.windows-open .act2-window-pane {
  transform: translateY(var(--win-drop));
}

/* Air coming in through the gap: drawn over the cabin (outside the window's clip) so it
   visibly enters the car. Brightest at the gap, gone by the time it reaches the wheel. */
.act2-window-inflow {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.3s ease;
  -webkit-mask-image: radial-gradient(ellipse 48% 75% at 8% 22%, #000 40%, transparent 100%);
  mask-image: radial-gradient(ellipse 48% 75% at 8% 22%, #000 40%, transparent 100%);
}
.act2-transport-scene.windows-open .act2-window-inflow {
  opacity: 1;
  transition-delay: 0.45s;
}
.act2-inflow-line {
  fill: none;
  stroke: var(--text-inverse);
  stroke-width: 3.5px;
  /* a faint dark edge so white air still reads over the pale pillar and headliner */
  filter: drop-shadow(0 0 1.5px rgba(56, 36, 24, 0.35));
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 12 28;
  stroke-dashoffset: 40;
}
.act2-transport-scene.windows-open .act2-inflow-line {
  animation: act2InflowStreak 0.9s linear infinite;
}
@keyframes act2InflowStreak {
  from { stroke-dashoffset: 40; }
  to   { stroke-dashoffset: 0; }
}

/* --- Task A: AC knob turns --- */
.act2-ac-knob-well {
  position: absolute;
  left: var(--ac-left);
  top: var(--ac-top);
  width: var(--ac-size);
  aspect-ratio: 1/1;
  transform: translate(-50%, -50%);
  z-index: 20;
}
.act2-ac-knob-svg {
  width: 100%;
  height: 100%;
  transform-origin: center;
  transform-box: fill-box;
  transform: rotate(-135deg);
  transition: transform 0.6s cubic-bezier(0.4, 0.0, 0.2, 1);
}
/* On is full blast: the knob sweeps all the way round to max. */
.act2-transport-scene.ac-on .act2-ac-knob-svg {
  transform: rotate(135deg);
}

/* --- Task C: Airflow --- */
/* Wind streaks, not puffs: each vent fans three curved lines toward the cabin, and short
   dashes run along them. Expanding soft circles read as fog or steam; thin fast dashes
   following a line read as air moving. Two dashes per line, so the flow never empties. */
.act2-airflow-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.act2-stream {
  position: absolute;
  width: 14%;
  aspect-ratio: 1/1;
  overflow: visible;
  z-index: 21;
  opacity: 0;
  transition: opacity 0.4s ease;
  /* Streaks are brightest at the grille and thin out as the air spreads. */
  -webkit-mask-image: radial-gradient(ellipse 75% 95% at 50% 5%, #000 35%, transparent 95%);
  mask-image: radial-gradient(ellipse 75% 95% at 50% 5%, #000 35%, transparent 95%);
}
/* --ventN-* is the grille centre; the streaks start at the box's top centre. */
.act2-stream-1 { left: calc(var(--vent1-left) - 7%); top: calc(var(--vent1-top) - 1.2%); transform: rotate(-28deg); transform-origin: 50% 5%; }
.act2-stream-2 { left: calc(var(--vent2-left) - 7%); top: calc(var(--vent2-top) - 1.2%); transform: rotate(24deg); transform-origin: 50% 5%; }
.act2-stream-3 { left: calc(var(--vent3-left) - 7%); top: calc(var(--vent3-top) - 1.2%); transform: rotate(-8deg); transform-origin: 50% 5%; }
.act2-transport-scene.ac-on .act2-stream { opacity: 1; }

.act2-air-line {
  fill: none;
  stroke: var(--color-info-pale);
  stroke-width: 4.5;
  stroke-linecap: round;
  stroke-dasharray: 14 36;
  stroke-dashoffset: 50;
}
.act2-transport-scene.ac-on .act2-air-line {
  animation: act2AirStreak 1.1s linear infinite;
}
@keyframes act2AirStreak {
  from { stroke-dashoffset: 50; }
  to   { stroke-dashoffset: 0; }
}

.act2-ac-tint {
  position: absolute;
  inset: 0;
  background: rgba(186, 230, 253, 0.05);
  opacity: 0;
  transition: opacity 0.4s ease;
}
.act2-transport-scene.ac-on .act2-ac-tint {
  opacity: 1;
}

/* --- Task D & E: Motion and Arrival --- */
/* The cabin does not move. Motion comes from the road alone — the lane dashes running
   toward the viewer and the roadside drifting past. Rocking the whole interior read as
   the camera swaying rather than the car travelling, and it is the component most likely
   to make a viewer queasy. The wrapper stays as the stacking context; the sway is gone,
   and with it the 104% oversize that only existed to give the rock somewhere to go. */
.act2-car-sway-container {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.act2-exterior-motion {
  --act2-windshield-clip: polygon(21% 4%, 100% 4%, 100% 53%, 28% 53%);
  position: absolute;
  inset: 0;
  overflow: hidden;
  clip-path: var(--act2-windshield-clip);
}
/* The centre line lies flat on the road in CSS 3D. The plane's near end sits where the
   centre line meets the bottom of the windshield; rotated flat, its far end converges on
   the vanishing point (the perspective origin), so the dashes foreshorten exactly as the
   painted road does. Sizes are in cqw so the look holds at every card width: the plane is
   0.9cqw wide against a ~63cqw road there, dashes 30cqw long with 45cqw gaps — long,
   highway-proportioned strokes that the eye can follow. */
.act2-exterior-motion { container-type: inline-size; }
.act2-lane-dashes {
  position: absolute;
  inset: 0;
  pointer-events: none;
  perspective: 60cqw;
  perspective-origin: var(--vp-left) var(--vp-top);
}
.act2-road-plane {
  position: absolute;
  top: 54%;
  left: 55%;
  width: 0.9cqw;
  margin-left: -0.45cqw;
  height: 1500cqw;
  overflow: hidden;
  transform-origin: 50% 0;
  transform: rotateX(-90deg);
  /* fades into the painted haze toward the horizon */
  -webkit-mask-image: linear-gradient(to bottom, #000 0, #000 12%, transparent 60%);
  mask-image: linear-gradient(to bottom, #000 0, #000 12%, transparent 60%);
}
.act2-road-stripe {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: calc(100% + 75cqw);
  background: repeating-linear-gradient(to bottom,
    var(--hairline-light-strong) 0 30cqw, transparent 30cqw 75cqw);
  /* Moving toward the plane's near end (its top) is moving toward the car. */
  animation: act2RoadRoll var(--road-dash-cadence) linear infinite;
}
@keyframes act2RoadRoll {
  from { transform: translateY(0); }
  to   { transform: translateY(-75cqw); }
}

.act2-roadside-drift {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.act2-drift {
  position: absolute;
  left: var(--vp-left);
  top: var(--vp-top);
  width: 10%;
  aspect-ratio: 1/1;
  background: radial-gradient(circle, rgba(34, 139, 34, 0.1) 0%, transparent 70%);
  opacity: 0;
  animation: act2DriftLeftAnim calc(var(--road-dash-cadence) * 4) linear infinite;
}
.act2-drift-left {
  animation-delay: calc(var(--road-dash-cadence) * -1);
}
.act2-drift-right {
  background: radial-gradient(circle, rgba(139, 69, 19, 0.15) 0%, transparent 70%);
  animation-delay: calc(var(--road-dash-cadence) * -3);
  animation-name: act2DriftRightAnim;
}
@keyframes act2DriftLeftAnim {
  0% { transform: scale(0.1) translate(-20%, 0); opacity: 0; }
  20% { opacity: 1; }
  100% { transform: scale(8) translate(-15vw, 20vh); opacity: 0; }
}
@keyframes act2DriftRightAnim {
  0% { transform: scale(0.1) translate(20%, 0); opacity: 0; }
  20% { opacity: 1; }
  100% { transform: scale(8) translate(15vw, 20vh); opacity: 0; }
}

.act2-transport-scene.is-arriving .act2-lane-dashes,
.act2-transport-scene.is-arriving .act2-roadside-drift {
  opacity: 0;
  transition: opacity 4s ease-out;
}

.act2-clinic-approach {
  position: absolute;
  left: var(--vp-left);
  top: var(--vp-top);
  width: 10%;
  transform: translate(-50%, -50%) scale(0);
  opacity: 0;
}
/* The clinic is the road's destination: Clinic-RoadEnd.png (docs/clinic-road-end.py) sets
   the building behind a paved lot that swallows the road, with verges and trees either
   side. It grows out of the vanishing point and eases to a stop with the building's base
   above the dashboard (~44% down) and the lot filling the bottom of the windshield, so the
   road visibly runs out into the car park. Box is 10% wide at 2.4:1; the end translate puts
   its centre at ~(60%, 30%) of the scene. Keep the duration in step with the arrive
   timeout in act2-screen.js (5s + a short hold). */
.act2-transport-scene.is-arriving .act2-clinic-approach {
  animation: clinicApproach 5s cubic-bezier(0.45, 0, 0.35, 1) forwards;
}
@keyframes clinicApproach {
  0% { transform: translate(-50%, -50%) scale(0); opacity: 0; }
  8% { opacity: 1; }
  100% { transform: translate(-77%, -106%) scale(8.85); opacity: 1; }
}

.act2-diegetic-btn {
  position: absolute;
  background: transparent;
  border: 2px solid transparent;
  cursor: pointer;
  z-index: 30;
  outline: none;
  /* The car scene renders inside .act2-speech-layer, which is pointer-events:none so
     bubbles never block the scene. Interactive children must opt back in — same as
     .act2-hotspot and the HUD pills above. Without this the controls are inert. */
  pointer-events: auto;
}
/* Keyboard focus is shown on the traced ring (brightened below), not as a box around the
   hit area, so the indicator follows the control's own shape. */
.act2-diegetic-btn:focus-visible {
  border-color: transparent;
}

/* Each control carries a ring traced on the drawn control itself (the knob's dial, the
   switch plate's outline), as an SVG in the painting's pixel space inside the button:
   --color-food-glow at rest, brighter amber with a glow on hover and focus. The untouched
   ring breathes (the invite) until first use. */
.act2-control-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
.act2-control-ring circle,
.act2-control-ring path {
  fill: none;
  stroke: var(--color-food-glow);
  stroke-width: 3px;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  transition: stroke 0.2s ease, filter 0.2s ease;
}
.act2-diegetic-btn:hover .act2-control-ring :is(circle, path),
.act2-diegetic-btn:focus-visible .act2-control-ring :is(circle, path) {
  stroke: var(--color-amber-tint-2);
  stroke-width: 4px;
  filter: drop-shadow(0 0 6px var(--color-amber));
}
.act2-diegetic-btn:disabled .act2-control-ring { opacity: 0; }
.act2-diegetic-btn.needs-invite .act2-control-ring {
  animation: act2ControlInvite 2.2s ease-in-out infinite;
}
@keyframes act2ControlInvite {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

#act2-toggle-ac {
  --ac-left: 70.8%;
  --ac-top: 63.9%;
  --ac-width: 17.2%;
  --ac-height: 28.7%;
  left: var(--ac-left);
  top: var(--ac-top);
  width: var(--ac-width);
  height: var(--ac-height);
}

#act2-toggle-windows {
  /* the switch plate's traced outline, plus its ring's 7px offset (175-466, 889-1080) */
  --win-left: 9.11%;
  --win-top: 82.31%;
  --win-width: 15.16%;
  --win-height: 17.69%;
  left: var(--win-left);
  top: var(--win-top);
  width: var(--win-width);
  height: var(--win-height);
}

.act2-diegetic-pill {
  position: absolute;
  /* Anchored ABOVE its control, not below. The window switch sits at the very bottom of
     the plate, so a pill hung beneath it renders past the card edge and gets clipped. */
  top: -2.1rem;
  bottom: auto;
  left: 50%;
  transform: translateX(-50%);
  background: var(--palette-text-dark);
  color: var(--text-on-dark);
  padding: 0.3rem 0.6rem;
  border-radius: var(--radius-xs);
  font-family: var(--font-family-display);
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.05em;
  white-space: nowrap;
}

.act2-transport-hud {
  position: absolute;
  top: 10%;
  left: 10%;
  background: var(--palette-cream);
  padding: 1rem 1.2rem;
  border-radius: var(--radius-md);
  box-shadow: var(--elev-modal);
  z-index: 40;
  max-width: 380px;
}
.act2-transport-hud-msg {
  font-family: var(--font-family-display);
  font-size: 1.1rem;
  font-weight: 800;
  color: var(--palette-brown-dark);
  margin-bottom: 0.5rem;
}
.act2-transport-hud-hint {
  font-size: 0.9rem;
  color: var(--palette-text-dark);
  margin-bottom: 0.8rem;
  line-height: 1.4;
}
/* Fills over the cooling delay (COOL_DELAY_MS in act2-screen.js) while the air runs. */
.act2-transport-scene { --cool-delay: 6s; }
.act2-cool-meter {
  display: none;
  height: 6px;
  margin: -0.3rem 0 0.8rem;
  border-radius: var(--radius-pill);
  background: rgba(56, 36, 24, 0.12);
  overflow: hidden;
}
.act2-cool-meter-fill {
  height: 100%;
  width: 0;
  border-radius: inherit;
  background: var(--color-info-mid);
}
.act2-transport-scene.is-cooling .act2-cool-meter { display: block; }
.act2-transport-scene.is-cooling .act2-cool-meter-fill {
  animation: act2CoolFill var(--cool-delay) linear forwards;
}
@keyframes act2CoolFill {
  from { width: 0; }
  to   { width: 100%; }
}
#act2-btn-arrive:not([hidden]) {
  animation: act2ArriveIn 0.45s var(--ease-out-expo) both;
}
/* The id rule above outranks .pulse-btn, so the pulse is restated alongside the entrance. */
#act2-btn-arrive.pulse-btn:not([hidden]) {
  animation: act2ArriveIn 0.45s var(--ease-out-expo) both, act2PulseBtn 1.8s 0.45s infinite;
}
@keyframes act2ArriveIn {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}

.act2-transport-hud-prepaid {
  font-size: 0.8rem;
  color: var(--palette-text-muted);
  border-top: 1px solid rgba(56, 36, 24, 0.1);
  padding-top: 0.5rem;
}

/* NOTE: .act2-transport-footer is defined once, further up. A second rule here set
   bottom/right without clearing the left+translateX centring, so the button got left:50%
   AND right:8% at once and stretched across the wheel. It also put the button back over
   the AC panel, which is the collision that was already fixed once. Keep one rule. */

.act2-handoff-card { text-align: center; width: min(620px, 86%); }

.act2-handoff-line {
  font-size: 1.05rem;
  line-height: 1.6;
  color: var(--palette-text-muted);
  margin: 0.7rem 0 1.2rem;
}

/* ==========================================================
   RESPONSIVE
   ========================================================== */

@media (max-width: 900px) {
  .act2-check-art {
    grid-template-columns: 1fr;
  }

  .act2-check-svg { grid-row: auto; }

  .act2-call-panel {
    width: min(340px, 46%);
    left: 1rem;
    right: auto;
  }
}

/* Per docs/design-language.md §9: at 768px the card flips to 4/3, the HUD shrinks to
   40px/32px, and modals widen to 96%. */
@media (max-width: 768px) {
  .act2-viewport-card {
    aspect-ratio: 4 / 3;
    width: min(96vw, 900px);
  }

  .act2-hud-bar,
  .act2-nav-bar {
    left: 0.9rem;
    right: 0.9rem;
    min-height: 40px;
  }

  .act2-hud-pill {
    font-size: 0.74rem;
    height: 32px;
    padding: 0 0.75rem;
  }

  .act2-hud-btn {
    font-size: 0.78rem;
    height: 34px;
    padding: 0 0.85rem;
  }

  .act2-call-panel {
    width: min(320px, 54%);
    left: 0.8rem;
    right: auto;
  }

  .act2-payoff-card,
  .act2-decision-card,
  .act2-waiting-card,
  .act2-cool-card ,
  .act2-check-card,
  .act2-handoff-card {
    width: 96%;
  }

  .act2-check-modal { padding: 1rem; }
}

@media (max-height: 700px) {
  .act2-payoff-card,
  .act2-decision-card,
  .act2-waiting-card,
  .act2-cool-card {
    max-height: 84%;
    padding: 1rem 1.1rem;
  }
}

/* ==========================================================
   REDUCED MOTION — every looping/entrance animation in this act
   ========================================================== */

@media (prefers-reduced-motion: reduce) {
  .act2-hud-pill.hints-pill,
  .act2-hud-btn.btn-action-primary.pulse-btn,
  .act2-hotspot,
  .act2-phone-dot,
  .act2-heat-lines path,
  .act2-pant-trace,
  .act2-tay-labored-abdomen,
  .act2-tay-svg .tay-labored-abdomen,
  .act2-tay-chest,
  .act2-tay-tongue,
  .act2-gum-blanch,
  .act2-gum-hand,
  /* Stopped streaks still show two dashes per line, so AC-on still reads. */
  .act2-transport-scene.ac-on .act2-air-line,
  .act2-road-stripe,
  .act2-drift,
  .act2-transport-scene.windows-open .act2-wind-line,
  .act2-transport-scene.windows-open .act2-inflow-line,
  .act2-diegetic-btn.needs-invite .act2-control-ring,
  .act2-diegetic-btn.needs-invite {
    animation: none !important;
  }
  .act2-gum-blanch {
    background-color: color-mix(in srgb, var(--gum-blanched) 40%, var(--gum-color)) !important;
  }
  .act2-gum-hand {
    transform: translate(var(--hand-offset-x, 8%), var(--hand-offset-y, 16%)) !important;
  }

  .act2-ac-knob-svg,
  .act2-window-pane {
    transition-duration: 0.01s !important;
  }

  /* the meter carries the wait, so it keeps running (it is a progress bar, not motion) */
  #act2-btn-arrive:not([hidden]) { animation: act2ArriveIn 0.01s both !important; }

  .act2-transport-scene.is-arriving .act2-clinic-approach {
    animation-duration: 0.01s !important;
    animation-delay: 0s !important;
  }

  /* Entrances are SHORTENED, never removed (design-language.md §5.3). act2CardIn ends on
     translate(-50%, -50%); killing it outright would drop the centring and the card would
     jump to the corner. Collapsing the duration keeps the final frame intact. */
  .act2-silence-card,
  .act2-call-panel,
  .act2-check-modal,
  .act2-payoff-card,
  .act2-decision-card,
  .act2-waiting-card,
  .act2-cool-card ,
  .act2-handoff-card {
    animation-duration: 0.01s !important;
    animation-delay: 0s !important;
  }

  .act2-viewport-card,
  .act2-scene-img,
  .act2-cooler-group,
  .act2-heat-wash,
  .act2-decision-option,
  .act2-cool-option,
  .act2-hud-btn,
  .act2-hotspot {
    transition: none !important;
  }

  .act2-decision-option:hover,
  .act2-decision-option:focus-visible,
  .act2-cool-option:hover,
  .act2-cool-option:focus-visible,
  .act2-hud-btn:hover:not(:disabled),
  .act2-hud-btn:focus-visible:not(:disabled) {
    transform: none;
  }

  /* The cooler still comes forward, by opacity alone. */
  .act2-cooler-group.is-tempting {
    transform: none;
  }
}



/* Block, not flex: the card is height-capped and scrolls, and flex items would be shrunk
   to zero, collapsing the 0fr -> 1fr reply row that should be opening. */
.act2-cool-replies {
  display: block;
}
.act2-cool-item.is-chosen > .act2-cool-reply-wrap > .act2-cool-reply-clip > .act2-cool-feedback {
  margin-top: 0.9rem;
}
.act2-cool-option[aria-disabled="true"] { cursor: default; }

.act2-cool-option.is-chosen {
  background-color: rgba(56, 36, 24, 0.05);
  border-color: rgba(56, 36, 24, 0.15);
  transform: none;
  box-shadow: none;
}
.act2-cool-option.is-chosen:hover {
  transform: none;
}

/* Collapsible reply. The 0fr -> 1fr grid trick (guideline-persistent-cards.md, Rule 3)
   collapses to zero inside this card — the card is absolutely positioned with its own
   max-height + overflow, and the fr track resolves against zero available space — so the
   same wrap/clip/box structure animates on max-height instead. The clip still carries the
   overflow and the visibility toggle, so there is no sliver and no hit-testing when closed. */
/* True accordion, per Rule 3 of docs/guideline-persistent-cards.md and matching Act 3's
   prevention card, which is the reference implementation.

   This was `max-height: 0 -> 1400px`. A max-height accordion animates to a number, not to
   the content, so a ~200px reply reached full height in the first fraction of the
   transition and the remaining duration ran empty — which is what made the reply read as
   popping in rather than opening. 0fr -> 1fr animates to the row's real height, so the
   open takes the whole duration however long the reply happens to be. */
.act2-cool-reply-wrap {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-base) var(--ease-out-expo);
}
.act2-cool-item.is-chosen > .act2-cool-reply-wrap {
  grid-template-rows: 1fr;
}

.act2-cool-reply-clip {
  overflow: hidden;
  min-height: 0;
  visibility: hidden;
  transition: visibility 0s linear var(--dur-base);
}
.act2-cool-item.is-chosen > .act2-cool-reply-wrap > .act2-cool-reply-clip {
  visibility: visible;
  transition-delay: 0s;
}

@media (prefers-reduced-motion: reduce) {
  .act2-cool-reply-wrap { transition: none; }
}


.act2-call-calling-pill.is-new-line {
  animation: act2SlideIn 0.3s ease forwards;
}

.is-entering .act2-silence-card {
  animation: act2FadeIn 0.6s ease forwards;
}

.is-entering .act2-call-panel {
  animation: act2SlideIn 0.35s var(--ease-out-expo) forwards;
}

.act2-check-modal {
  animation: act2FadeIn 0.25s ease forwards;
}

#screen-act2 .speech-bubble:not(.is-new-line) { animation: none; }

/* Accumulating conversation lines animations */
.act2-check-tech-line.is-new-line {
  animation: act2SlideFadeLeft var(--dur-base) var(--ease-out-expo) forwards;
}

.act2-check-callie-line.is-new-line {
  animation: act2SlideFadeRight var(--dur-base) var(--ease-out-expo) forwards;
}

@keyframes act2SlideFadeLeft {
  from {
    opacity: 0;
    transform: translateX(-15px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes act2SlideFadeRight {
  from {
    opacity: 0;
    transform: translateX(15px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

/* Reduced motion for conversation lines */
@media (prefers-reduced-motion: reduce) {
  .act2-check-tech-line.is-new-line,
  .act2-check-callie-line.is-new-line {
    animation-duration: 0.01s !important;
    animation-delay: 0s !important;
  }
}
