/* Miri's Mixing Tree (kf-mixing-tree.js) - game-page sheet, D-071.
 * Loaded on the play pages only, AFTER kf-games.css (which supplies the shared
 * .kfe-confetti). Engine prefix: kfmt-.
 *
 * UPDATE 3 (owner redesign): the disc renders DROPS of liquid light. The
 * petal-overlay layers and mix-blend-mode are gone from this sheet; the disc
 * face wears a code scrim so the vivid drops pop, and the drop itself is an
 * engine-drawn SVG blob (gradient + specular + glow, all inline). Every
 * animated property here is transform/opacity/filter; tokens.css zeroes
 * durations under prefers-reduced-motion and the engine's live REDUCED flag
 * swaps the choreography. No flashing anywhere: the fastest repeating motion
 * is the 0.4Hz idle micro-wobble, and every glow breathes at 0.9s ease. */

.kf-mixingtree {
  position: relative;
  margin: 0 auto;
  max-width: 1180px;
}

/* ---------- stage ---------- */
.kfmt-stage {
  position: relative;
  width: 100%;
  height: clamp(420px, 76vh, 900px);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--stage-night, #1a1140);
  box-shadow: var(--shadow-soft);
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}
.kfmt-stage:fullscreen {
  height: 100%;
  border-radius: 0;
}
@media (max-width: 480px) {
  .kfmt-stage { height: min(78vh, 640px); }
}

/* entry: dark stage fades in 300ms (U16); the opening line rides it and
   never blocks input */
.kfmt-stage > * { transition: opacity 0.3s ease; }
.kfmt-stage.kfmt-enter > * { opacity: 0; transition: none; }

.kfmt-surround {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}

/* visually-hidden live region */
.kfmt-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- disc: painted art + U10 code scrim ---------- */
.kfmt-disc {
  position: absolute;
  /* the scrim multiplies against the art's face only, never the night stage */
  isolation: isolate;
  pointer-events: none;
  z-index: 6;
}
.kfmt-disc-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
/* U10: warm moonstone scrim (~25% darker than the v1 cream) + soft edge
   vignette, so the vivid drops pop; the art's rim stays untouched outside
   this circle. No art regeneration: this is the whole dimming. */
.kfmt-ground {
  position: absolute;
  border-radius: 50%;
  background: #b9ad8a;
  mix-blend-mode: multiply;
}
.kfmt-ground::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle, transparent 52%, rgba(63, 52, 30, 0.4) 100%);
}

/* one gentle breath at entry */
.kfmt-disc.kfmt-breathe { animation: kfmt-breathe 0.9s ease 1; }
@keyframes kfmt-breathe {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.02); }
}

/* U15b: the EMPTY-disc tap answer, restored. Brightness only, one soft
   400ms ripple, deliberately NOT in the gold hint-glow family (no
   box-shadow, no gold); the engine throttles it to once per 2s and only
   fires it when no drop is on the disc. */
.kfmt-ground.kfmt-shimmer-ripple { animation: kfmt-discshimmer 0.4s ease 1; }
@keyframes kfmt-discshimmer {
  0%, 100% { filter: brightness(1); }
  45% { filter: brightness(1.13); }
}
/* reduced motion: one static brightness step, ~300ms (engine-timed) */
.kfmt-ground.kfmt-shimmer-step { filter: brightness(1.09); }

/* ---------- the drop (U9/U10) ---------- */
/* One resident element, an engine-drawn SVG blob. As a single un-merged drop
   it is a real button (tab stop, Enter = splash home); merged it leaves the
   tab order and only jelly-wobbles. The blob IS the hit target, >=84px. */
.kfmt-drop {
  position: absolute;
  z-index: 7;
  background: transparent;
  border: none;
  padding: 0;
  cursor: pointer;
  border-radius: 50%;
}
.kfmt-drop svg,
.kfmt-blob svg {
  width: 100%;
  height: 100%;
  display: block;
}
/* idle micro-wobble: +-1.5% scale at 0.4Hz (2.5s), U10; reduced: none via
   tokens.css plus the explicit block below */
.kfmt-drop { animation: kfmt-microwobble 2.5s ease-in-out infinite; }
@keyframes kfmt-microwobble {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.015); }
}
/* jelly wobble: the merged resident's happy answer, 400ms, throttled 2s by
   the engine; distinct from every gold hint (no box-shadow, no color) */
.kfmt-drop.kfmt-wobble { animation: kfmt-jelly 0.4s ease 1; }
@keyframes kfmt-jelly {
  0%, 100% { transform: scale(1, 1); }
  30% { transform: scale(1.08, 0.92); }
  60% { transform: scale(0.94, 1.06); }
  80% { transform: scale(1.03, 0.97); }
}
/* reduced-motion wobble answer: one static brightness step */
.kfmt-drop.kfmt-wobble-static { filter: brightness(1.12) !important; }
/* during the swirl the resident stirs very slightly */
.kfmt-drop.kfmt-swirl { animation: kfmt-stir 0.7s ease-in-out 1; }
@keyframes kfmt-stir {
  0%, 100% { transform: rotate(0deg) scale(1); }
  50% { transform: rotate(8deg) scale(1.05); }
}

/* transient blobs: drips, drags, merges, splashes; never controls */
.kfmt-blob {
  position: absolute;
  z-index: 8;
  pointer-events: none;
}
.kfmt-blob--drag { opacity: 0.9; }

/* landing ripple: one expanding ring in the drop's own color */
.kfmt-ripple {
  position: absolute;
  z-index: 7;
  width: 20px;
  height: 20px;
  margin: -10px 0 0 -10px;
  border: 3px solid rgba(255, 255, 255, 0.7);
  border-radius: 50%;
  pointer-events: none;
  animation: kfmt-rippleout 0.42s ease-out 1;
  opacity: 0;
}
@keyframes kfmt-rippleout {
  0% { transform: scale(0.4); opacity: 0.9; }
  100% { transform: scale(3.2); opacity: 0; }
}
/* reduced motion: a static ring, shown briefly by the engine */
.kfmt-ripple--static {
  animation: none;
  transform: scale(2);
  opacity: 0.6;
}

/* deeper shade: one soft inner pulse ring on the resident (U9) */
.kfmt-pulsering {
  position: absolute;
  inset: 12%;
  border: 3px solid rgba(255, 255, 255, 0.8);
  border-radius: 50%;
  pointer-events: none;
  animation: kfmt-pulserring 0.6s ease-out 1;
  opacity: 0;
}
@keyframes kfmt-pulserring {
  0% { transform: scale(0.5); opacity: 0.9; }
  100% { transform: scale(1.05); opacity: 0; }
}
.kfmt-pulsering--static {
  animation: none;
  transform: scale(0.9);
  opacity: 0.7;
}

/* sparkle clear-away motes (shake-off) */
.kfmt-spark {
  position: absolute;
  z-index: 9;
  width: 8px;
  height: 8px;
  margin: -4px 0 0 -4px;
  border-radius: 50%;
  pointer-events: none;
  animation: kfmt-sparkfly 0.45s ease-out 1;
  opacity: 0;
}
@keyframes kfmt-sparkfly {
  0% { transform: translate(0, 0) scale(1); opacity: 1; }
  100% { transform: translate(var(--kfmt-sx, 30px), var(--kfmt-sy, -30px)) scale(0.4); opacity: 0; }
}

/* ---------- rail sources ---------- */
/* U25a: the rail wash. A soft interlayer between the night forest and the
   shelf, which is Deniz's own first suggestion kept for the job it is
   actually good at. It is NOT the contrast mechanism (the rim is): its job
   is to quiet a backdrop whose luminance ran from 0.008 to 0.70 under the
   leaves, so the rail reads as one tray and the value gradient carries the
   eye up to the disc, where the mixing happens. Alpha 0.42 is the ceiling
   Nova measured: it pulls the moss highlights from 0.53 down to 0.18 while
   the shelf art keeps 4.10:1 of its own internal range, where 0.55 would
   flatten it to 2.91:1 and kill the texture. Static: no animation, no
   transition, nothing to flash. */
.kfmt-railwash {
  position: absolute;
  z-index: 5; /* over the shelf art (4), under the disc (6) and rails (7) */
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(15, 10, 36, 0) 0%,
    rgba(15, 10, 36, 0.23) 40%,
    rgba(15, 10, 36, 0.42) 78%,
    rgba(15, 10, 36, 0.42) 100%
  );
}
/* Windows high contrast: the rim survives (a filter is not color-forced, and
   the light/dark pair separates against either forced canvas), so the wash,
   which is decoration, steps aside. */
@media (forced-colors: active) {
  .kfmt-railwash { display: none; }
}
.kfmt-shelf {
  position: absolute;
  pointer-events: none;
  z-index: 4;
}
.kfmt-rail {
  position: absolute;
  z-index: 7;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: transparent;
  border: none;
  padding: 0;
  cursor: pointer;
  filter: drop-shadow(0 6px 10px rgba(15, 10, 36, 0.55));
}
.kfmt-rail img {
  height: 100%;
  width: auto;
  pointer-events: none;
  /* U25 (owner, hands-on: "burada özellikle siyah yaprak belli olmuyor").
     ONE rule for all five sources, not a patch on the black one. Nova
     measured the shipped rail against the night forest: 54-98% of the black
     leaf's edge AND 68-96% of the other four fell under 3:1. A single-color
     interlayer cannot fix that, because darkening the ground rescues the
     white leaf and buries the black one; the two leaves are only 4.13:1
     apart, so no one backdrop can give both 3:1. The two-ring rim can: the
     rings are 18.51:1 apart from EACH OTHER, so whatever sits behind them,
     the better ring never reads below sqrt(18.51) = 4.30:1. Measured after:
     no edge pixel under 4.30:1 at five stage sizes. The rim lives on the
     IMG so the button's own drop-shadow and :hover brightness cannot
     overwrite it, and it is static, so it is identical under reduced
     motion and can never flash. */
  filter: var(--rim-sprite);
}
.kfmt-rail:hover { filter: drop-shadow(0 8px 14px rgba(15, 10, 36, 0.7)) brightness(1.08); }
/* U23's moon-glow slot backing under the tiny black leaf is GONE (U25). It
   was measured and it was not earning its place: its bright core sat under
   the leaf and its alpha had fallen to 0.00 by the bottom edge, where the
   leaf actually sits, so the edge it was meant to rescue never saw it. Its
   soft alpha also muddied the new rim. The two rules that existed only to
   stack the leaf above that glow went with it (one of them re-declared
   .kfmt-rail's own alignment). The 55% art size and the invisible padding
   to the 75px touch floor are untouched: they live in the engine. */

/* U24 round 2: the caught color as liquid inside the bottle, masked by the
   pixel-perfect interior mask derived from the sprite's own alpha. Geometry:
   the sprite is width-constrained inside the round button (percentage
   max-height is indefinite in the auto grid track, so the bottle art hangs
   its full 190:300 height from the padding box top; that IS the shipped
   look). The liquid box mirrors that exact rule, width 100% of the same
   padding box + the same aspect ratio + top anchored, so the mask stays
   glued to the glass at every scale in every browser. The level is a
   clip-path inset driven by the engine. */
.kfmt-phial > img {
  width: 100%;
  height: auto;
  max-height: none;
}
.kfmt-phial-liquid {
  position: absolute;
  inset: 8px;
  pointer-events: none;
}
.kfmt-liquid-box {
  display: block;
  position: relative;
  width: 100%;
  aspect-ratio: 190 / 300;
}
.kfmt-liquid-masked {
  position: absolute;
  inset: 0;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
}
.kfmt-liquid-color {
  position: absolute;
  inset: 0;
}
.kfmt-liquid-surf {
  position: absolute;
  left: 10%;
  right: 10%;
  height: 9px;
  border-radius: 50%;
}
.kfmt-liquid-spec {
  position: absolute;
  left: 26%;
  top: 62%;
  width: 16%;
  height: 6%;
  border-radius: 50%;
  background: #fff;
  opacity: 0.6;
}

/* engine-tinted overlays (wisher fill, ribbon, phial contents) */
.kfmt-tint {
  position: absolute;
  inset: 0;
  pointer-events: none;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  transition: opacity 0.4s ease, background-color 0.4s ease;
}
.kfmt-tint--mul { mix-blend-mode: multiply; opacity: 0.9; }

/* the message-free cap answer: one small sway, then stillness */
.kfmt-sway { animation: kfmt-sway 0.4s ease 1; }
@keyframes kfmt-sway {
  0%, 100% { transform: rotate(0deg); }
  30% { transform: rotate(-4deg); }
  70% { transform: rotate(3deg); }
}

/* ---------- on-stage controls (phial + shake-off leaf) ---------- */
.kfmt-phial,
.kfmt-shake {
  position: absolute;
  z-index: 9;
  display: grid;
  place-items: center;
  background: rgba(184, 160, 210, 0.14);
  border: 2px solid rgba(184, 160, 210, 0.55);
  border-radius: 50%;
  cursor: pointer;
  padding: 8px;
  box-sizing: border-box;
  isolation: isolate;
}
.kfmt-phial img,
.kfmt-shake img {
  max-width: 100%;
  max-height: 100%;
  pointer-events: none;
}
.kfmt-phial:hover,
.kfmt-shake:hover { border-color: var(--kf-gold); }
.kfmt-phial-ready { box-shadow: var(--glow-hint-soft); }
/* U20: the phial rests dim until the session's first merged resident,
   then glimmers once while Melo introduces it */
.kfmt-phial-dim { opacity: 0.45; filter: saturate(0.6); }
.kfmt-glimmer { animation: kfmt-glimmer 1.2s ease 1; }
@keyframes kfmt-glimmer {
  0%, 100% { box-shadow: none; }
  40% { box-shadow: var(--glow-hint-full); }
  70% { box-shadow: var(--glow-hint-soft); }
}
.kfmt-glimmer-static { box-shadow: var(--glow-hint-soft); }

/* hint ladder rungs (D-027 + U9 amendment: the shake-off leaf may join) */
.kfmt-hint-soft { box-shadow: var(--glow-hint-soft); }
.kfmt-hint-full { animation: kfmt-hintbreathe 0.9s ease infinite; }
.kfmt-hint-full-static { box-shadow: var(--glow-hint-full); }
@keyframes kfmt-hintbreathe {
  0%, 100% { box-shadow: var(--glow-hint-soft); }
  50% { box-shadow: var(--glow-hint-full); }
}

/* ---------- branch band ---------- */
.kfmt-branchwrap {
  position: absolute;
  z-index: 5;
  pointer-events: none;
}
.kfmt-branchwrap img {
  width: 100%;
  height: 100%;
  display: block;
}
.kfmt-leafglow {
  --kfmt-c: #f2d94b;
  position: absolute;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--kfmt-c) 0%, transparent 70%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.6s ease;
}
.kfmt-leafglow.kfmt-lit { opacity: 0.95; }
.kfmt-leafglow.kfmt-shimmer { animation: kfmt-leafshimmer 1.2s ease 1; }
.kfmt-leafglow.kfmt-shimmer-static { opacity: 0.9; }
@keyframes kfmt-leafshimmer {
  0% { opacity: 0; transform: rotate(0deg); }
  35% { opacity: 1; transform: rotate(4deg); }
  70% { opacity: 0.85; transform: rotate(-3deg); }
  100% { opacity: 0; transform: rotate(0deg); }
}

/* U18: the BIG target petal, top-center above the disc (the ribbon and the
   dusk side-by-side chips retired with owner round 2, U22) */
.kfmt-targetwrap {
  position: absolute;
  z-index: 10;
  pointer-events: none;
}
.kfmt-targetwrap.kfmt-grow { animation: kfmt-grow 0.4s ease 1; }
@keyframes kfmt-grow {
  0% { transform: scale(0.2); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}
.kfmt-target {
  position: absolute;
  inset: 0;
  pointer-events: auto;
  background: transparent;
  border: none;
  padding: 0;
  cursor: pointer;
  isolation: isolate;
  filter: drop-shadow(0 4px 10px rgba(15, 10, 36, 0.55));
}
.kfmt-target img {
  position: absolute;
  inset: 0;
  height: 100%;
  left: 50%;
  transform: translateX(-50%);
  pointer-events: none;
}
/* the asked color, visible inside the glass: exact result hex at reduced
   glow, clearly not yet filled (U18 glance test) */
.kfmt-corebg,
.kfmt-core,
.kfmt-fillov {
  position: absolute;
  inset: 0;
  pointer-events: none;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  transition: opacity 0.4s ease, background-color 0.4s ease;
}
.kfmt-target.kfmt-lit { filter: drop-shadow(0 0 14px rgba(255, 244, 200, 0.8)); }
.kfmt-target.kfmt-pull { animation: kfmt-hintbreathe 0.9s ease infinite; border-radius: 40%; }
.kfmt-target.kfmt-pull-static { box-shadow: var(--glow-hint-full); border-radius: 40%; }

/* ---------- streams ---------- */
.kfmt-streamdot {
  position: absolute;
  z-index: 30;
  width: 18px;
  height: 18px;
  margin: -9px 0 0 -9px;
  border-radius: 50%;
  pointer-events: none;
}

/* ---------- toolbar (Game Shell chrome on --surface-dark) ---------- */
.kfmt-toolbar {
  position: absolute;
  left: 0;
  right: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 4px 8px;
  min-height: 72px;
  box-sizing: border-box;
  pointer-events: none;
  /* The wash used to be a FLAT fill, which drew a hard horizontal line across
     the artwork wherever the bar ended (Deniz, 2026-08-13: "ustte neden gene
     cok keskin bir cizgi var?"). It is most visible in landscape and in
     fullscreen, where the bar sits at the TOP over the forest. Same colour,
     same coverage under the buttons, but it now fades out over the last third
     instead of stopping dead. The gradient direction follows the bar: it fades
     DOWNWARD when the bar is at the top, UPWARD when it is at the bottom. */
  background: linear-gradient(
    to bottom,
    var(--surface-dark, rgba(184, 160, 210, 0.14)) 0%,
    var(--surface-dark, rgba(184, 160, 210, 0.14)) 62%,
    transparent 100%
  );
}
.kfmt-stage[data-orient='p'] .kfmt-toolbar {
  bottom: 0;
  background: linear-gradient(
    to top,
    var(--surface-dark, rgba(184, 160, 210, 0.14)) 0%,
    var(--surface-dark, rgba(184, 160, 210, 0.14)) 62%,
    transparent 100%
  );
}
.kfmt-stage[data-orient='l'] .kfmt-toolbar { top: 0; }
.kfmt-toolbar > * { pointer-events: auto; }

.kfmt-tbtn {
  box-sizing: border-box;
  min-width: 64px;
  min-height: 64px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 3px solid var(--kf-lilac);
  border-radius: var(--radius-pill);
  background: rgba(253, 250, 244, 0.94);
  color: var(--kf-purple-deep);
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 1rem;
  padding: 6px 16px;
  cursor: pointer;
  text-decoration: none;
  box-shadow: 0 3px 12px rgba(15, 10, 36, 0.28);
}
.kfmt-tbtn:hover { background: #fff; }
.kfmt-tbtn svg { display: block; }
.kfmt-exit .kfmt-exit-arrow {
  color: var(--color-link);
  display: inline-flex;
  align-items: center;
}
.kfmt-exit span:last-child { white-space: nowrap; }
@media (max-width: 430px) {
  .kfmt-exit { font-size: 0.9rem; padding: 6px 12px; }
}

/* Miri's speaking indicator: the shared kf-speak glyph as a quiet chip */
.kfmt-speakchip {
  pointer-events: none;
  cursor: default;
  min-height: 64px;
  width: 64px;
  border-color: transparent;
  background: transparent;
  opacity: 0.35;
  transition: opacity 0.3s ease;
}
.kfmt-speakchip.kfmt-speaking { opacity: 1; }
.kfmt-speakchip .kf-speak-ico { background: var(--kf-lilac); color: #2d1b4e; }
.kfmt-speakchip.kfmt-speaking .kf-speak-ico { background: var(--kf-gold); }

/* fullscreen nudge: one 600ms pulse; static ring under reduced motion */
.kfmt-fs-nudge { animation: kfmt-fspulse 0.6s ease 1; }
.kfmt-fs-nudge-static { box-shadow: 0 0 0 5px var(--kf-gold); }
@keyframes kfmt-fspulse {
  0%, 100% { box-shadow: 0 3px 12px rgba(15, 10, 36, 0.28); }
  50% { box-shadow: 0 0 0 9px rgba(212, 168, 67, 0.75); }
}

/* muted board hint: no direction word, the toolbar moves (Milo 5e) */
.kfmt-muted-hint {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  z-index: 41;
  max-width: min(86%, 30rem);
  background: rgba(15, 10, 36, 0.78);
  color: #fdfaf4;
  font-family: var(--font-body);
  font-size: 0.9rem;
  border-radius: var(--radius-md);
  padding: 8px 14px;
  text-align: center;
  pointer-events: none;
}
.kfmt-stage[data-orient='p'] .kfmt-muted-hint { bottom: 76px; }
.kfmt-stage[data-orient='l'] .kfmt-muted-hint { top: 76px; }

/* ---------- loading skeleton ---------- */
.kfmt-skeleton {
  position: absolute;
  inset: 0;
  z-index: 50;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  background: var(--stage-night, #1a1140);
}
.kfmt-skeleton-disc {
  width: min(46%, 300px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 246, 221, 0.28) 0%, rgba(255, 246, 221, 0.06) 70%);
  animation: kfmt-skelpulse 1.6s ease-in-out infinite;
}
@keyframes kfmt-skelpulse {
  0%, 100% { opacity: 0.5; }
  50% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .kfmt-skeleton-disc { animation: none; opacity: 0.8; }
}
.kfmt-loading-line {
  color: #d9d0ee;
  font-family: var(--font-heading);
  font-weight: 700;
  margin: 0;
}

/* ---------- overlays: quit sheet, celebration, error ---------- */
.kfmt-overlay {
  position: absolute;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--scrim-navy, rgba(15, 10, 36, 0.62));
  padding: var(--space-3);
  box-sizing: border-box;
}
.kfmt-card {
  position: relative;
  width: min(90vw, 30rem);
  max-height: 94%;
  overflow: auto;
  background: var(--color-surface, #fff);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lift);
  padding: var(--space-4);
  box-sizing: border-box;
  text-align: center;
}
.kfmt-card h2 {
  font-family: var(--font-heading);
  color: var(--kf-purple-deep);
  font-size: var(--text-xl);
  margin: var(--space-2) 0 var(--space-2);
}
.kfmt-card p {
  color: var(--color-text);
  margin: 0 0 var(--space-3);
}
.kfmt-littree {
  width: 100%;
  height: auto;
  aspect-ratio: 1376 / 768;
  object-fit: cover;
  border-radius: var(--radius-md);
  display: block;
}
.kfmt-miri {
  width: 92px;
  height: auto;
  margin: calc(-1 * var(--space-4)) auto 0;
  position: relative;
  display: block;
}
.kfmt-miri--sm { width: 76px; margin: 0 auto var(--space-2); }
.kfmt-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
}
.kfmt-pill {
  box-sizing: border-box;
  min-height: 64px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  border: none;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 1.05rem;
  padding: 10px 26px;
  cursor: pointer;
  text-decoration: none;
}
.kfmt-pill--gold { background: var(--kf-gold); color: var(--kf-navy-dark); }
.kfmt-pill--gold:hover { background: #e0b755; }
.kfmt-pill--purple { background: var(--kf-purple-deep); color: #fdfaf4; }
.kfmt-pill--purple:hover { background: #3c2766; }
.kfmt-close {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 64px;
  height: 64px;
  border: none;
  background: transparent;
  color: var(--kf-purple-deep);
  font-size: 2rem;
  line-height: 1;
  cursor: pointer;
  border-radius: 50%;
}
.kfmt-close:hover { background: var(--kf-lilac-soft); }
.kfmt-card--closable { padding-top: var(--space-5); }
.kfmt-snap {
  position: relative;
  width: 72%;
  margin: 0 auto var(--space-2);
}
.kfmt-snap img {
  width: 100%;
  height: auto;
  display: block;
  filter: brightness(0.6);
}
.kfmt-snap-petal {
  position: absolute;
  width: 14px;
  height: 20px;
  margin: -4px 0 0 -7px;
  border-radius: 50% 50% 50% 50% / 42% 42% 58% 58%;
  box-shadow: 0 0 10px 3px rgba(255, 244, 200, 0.7);
}

/* static celebration answer under reduced motion */
.kfmt-burst-static {
  position: absolute;
  left: 50%;
  top: 40%;
  width: 240px;
  height: 240px;
  margin: -120px 0 0 -120px;
  z-index: 55;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(212, 168, 67, 0.55) 0%, transparent 70%);
  pointer-events: none;
}

/* ---------- reduced-motion fallbacks the tokens sheet cannot infer -------- */
@media (prefers-reduced-motion: reduce) {
  .kfmt-stage > * { transition: none; }
  .kfmt-drop { animation: none; }
  .kfmt-drop.kfmt-wobble { animation: none; filter: brightness(1.12); }
  .kfmt-drop.kfmt-swirl { animation: none; }
  .kfmt-ripple { animation: none; transform: scale(2); opacity: 0.6; }
  .kfmt-pulsering { animation: none; transform: scale(0.9); opacity: 0.7; }
  .kfmt-spark { animation: none; opacity: 0; }
  .kfmt-target.kfmt-pull { animation: none; box-shadow: var(--glow-hint-full); }
  .kfmt-hint-full { animation: none; box-shadow: var(--glow-hint-full); }
  .kfmt-fs-nudge { animation: none; box-shadow: 0 0 0 5px var(--kf-gold); }
  .kfmt-leafglow.kfmt-shimmer { animation: none; opacity: 0.9; }
  .kfmt-ground.kfmt-shimmer-ripple { animation: none; filter: brightness(1.09); }
  .kfmt-glimmer { animation: none; box-shadow: var(--glow-hint-soft); }
}
