/* Peek and Tell (Memory & Focus Games, D-217): the video recall format. Engine prefix kfpt-.
   Every number comes from concepts/video-recall-game/DESIGN-SPEC-GAME.md REVISION 4.2 (Nova); the solve in
   kf-peek-tell.js writes the measured sizes onto the stage as custom properties:
     --kfpt-bcue                                                                           the cue under Listen (R41)
     --kfpt-splitl                                     SPLIT's first column: 340, or less for the widest option word (R55)
     --kfpt-barw                            SPLIT's bar: its column less 48, never under its tools row (R70, round 5)
     --kfpt-pad, --kfpt-rowgap, --kfpt-headh, --kfpt-barh, --kfpt-barrowgap, --kfpt-mainh    the rows
     --kfpt-lineh, --kfpt-bubw, --kfpt-host, --kfpt-hostgap, --kfpt-bpv, --kfpt-bph, --kfpt-bgap   the head row (R25, R30)
     --kfpt-colw, --kfpt-og, --kfpt-band, --kfpt-p                                         the options (picture side P)
     --kfpt-cuerowh, --kfpt-scue                                                           SPLIT's cue row (R22)
     --kfpt-thw, --kfpt-thh                                                                the memory strip
     --kfpt-stw, --kfpt-sth, --kfpt-cues                                                   the find still and its cue
     --kfpt-pkw, --kfpt-pkh                                                                the peek photo
     --kfpt-endpad, --kfpt-endgap, --kfpt-btngap, --kfpt-pocketv, --kfpt-pocketh, --kfpt-jarw, --kfpt-jarh   the end
   Gold means Peek, help and found only (R15): no hover or press turns anything gold. Nothing loops, nothing flashes;
   reduced motion is declared at the end with !important and class selectors, because tokens.css zeroes every
   duration with !important (the Costume lesson).
   PROPOSED TOKENS (DESIGN-SPEC-GAME section 7, R52): a literal that stands for one of the eight proposed house
   tokens carries a short comment naming that token on its own line (the peek ground's says --scrim-dusk); the
   tokens.css addition is the release package's prepared edit T1 for the next shared tokens pass, which swaps these
   literals for var(). The 1.35rem literals are var(--text-child-floor) already (tokens.css: 1.35rem, owner rule 5). */

/* the jar's fill rises once, continuously (2.12): a registered number interpolates, a gradient does not */
@property --kf-jar { syntax: '<number>'; inherits: false; initial-value: 0; }

.kf-peek-tell { display: block; }
/* (REVISION 4, Sage F6: the board's room before the engine runs is reserved only by the play page's own head style,
   and only once its boot script has run; this sheet loads with JavaScript off too, so it reserves nothing) */
.kfpt-fslead { height: 0; }
/* the shared layer pads the FIRST child by 24 px in full screen; ours is the empty lead (the Look and Remember
   lesson: a two-class rule loses to the layer's selector, so this one is written long enough to win) */
[data-kf-fs].kf-peek-tell.kf-fs-on[data-kf-fs-wide] > .kfpt-fslead,
[data-kf-fs].kf-peek-tell.kf-fs-fake[data-kf-fs-wide] > .kfpt-fslead { padding-top: 0 !important; }
/* F-r4-1 (2.2 REVISION 4): in full screen a stage taller than the screen (a text-spacing override on the smallest
   phones) starts at the screen's top and the rest scrolls inside full screen, never above it, where no scroll reaches
   (a centring flex column put 22.5 px of the head row above a 320 px screen). Auto margins centre a stage that fits
   and fall to 0 for one that does not, in every engine. This also overrides the house layer's faked-mode
   `overflow: hidden`, for this root only. */
[data-kf-fs].kf-peek-tell.kf-fs-on[data-kf-fs-wide],
[data-kf-fs].kf-peek-tell.kf-fs-fake[data-kf-fs-wide] { display: flex; flex-direction: column; justify-content: flex-start; align-items: center; overflow-y: auto; overscroll-behavior: contain; }
[data-kf-fs].kf-peek-tell.kf-fs-on[data-kf-fs-wide] > .kfpt-stage,
[data-kf-fs].kf-peek-tell.kf-fs-fake[data-kf-fs-wide] > .kfpt-stage { flex: 0 0 auto; margin: auto; }

.kfpt-sr,
.kfpt-probe {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
/* the word probe measures an option word at its real size, out of sight */
.kfpt-probe { width: auto; height: auto; clip-path: none; left: -9999px; top: 0; visibility: hidden; display: inline-block; }
/* the line probe (R30): Ori's lines at the real line-box width, with whatever line styles are live */
.kfpt-lprobe { position: absolute; left: -9999px; top: 0; visibility: hidden; pointer-events: none; }
.kfpt-lprobe .kfpt-line-t { display: block; }

/* ---------- the stage: one row per child (2.1, 2.2) ---------- */
.kfpt-stage {
  position: relative;
  box-sizing: border-box;
  margin: 0 auto;
  max-width: 100%;
  background: var(--kf-lilac-soft);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-soft);
  padding: var(--kfpt-pad, 24px);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: var(--kfpt-headh, 95px) var(--kfpt-barh, 72px) var(--kfpt-mainh, 400px);
  row-gap: var(--kfpt-rowgap, 12px);
  overflow: hidden;
  font-synthesis: none;
}
/* a phone held sideways: Ori, the cue row and the bar on the left (340 px), the question on the right (R22) */
.kfpt-stage--split {
  /* R55: the engine writes the first column (340 unless the widest option word needs room, never under 280) */
  grid-template-columns: var(--kfpt-splitl, 340px) minmax(0, 1fr);
  grid-template-rows: var(--kfpt-headh) var(--kfpt-cuerowh, 0px) var(--kfpt-barh);
  column-gap: 16px;
}
.kfpt-stage--split .kfpt-head { grid-column: 1; grid-row: 1; }
/* R70 (2.2 REVISION 4.2, Pip P4-N2): on a phone held sideways the bar ends 48 px inside its column (the engine writes
   --kfpt-barw: the column less 48, never narrower than the tools row), so the red X, still the bar's last element
   above full screen, keeps 64 px from the answer cards instead of 16; the room beside it is the stage's lilac */
.kfpt-stage--split .kfpt-bar { grid-column: 1; grid-row: 3; width: var(--kfpt-barw, 100%); justify-self: start; }
.kfpt-stage--split .kfpt-main { grid-column: 2; grid-row: 1 / span 3; }

/* ---------- the head row: Ori | bubble (Listen | cue | line) (2.4) ---------- */
/* the head row and the bar sit above a floating bubble (z 6) and under the flights (z 30): R16's backstop */
.kfpt-head,
.kfpt-bar,
.kfpt-cuerow { position: relative; z-index: 8; }
.kfpt-head { display: flex; align-items: center; gap: var(--kfpt-hostgap, 12px); min-width: 0; height: var(--kfpt-headh, 95px); }
/* Ori: one circle at every size (R25), 88 / 44 / 40 px; the engine places the picture inside it */
.kfpt-host {
  position: relative;
  flex: none;
  width: var(--kfpt-host, 88px);
  height: var(--kfpt-host, 88px);
  border-radius: 50%;
  overflow: hidden;
  background: #fff6e8;
  box-shadow: 0 0 0 2px var(--kf-lilac);
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition: transform 150ms ease;
}
.kfpt-host img { position: absolute; left: 0; top: 0; max-width: none; display: block; pointer-events: none; }
.kfpt-host.is-pressed { transform: scale(0.96); }
/* R36: a tap on Ori while he talks gets a nod, never a stop (2.9c): 1 to 1.06 to 1, 400 ms, after the press */
.kfpt-host.is-nod { animation: kfpt-orinod 400ms ease-in-out 1; }
@keyframes kfpt-orinod { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.06); } }
/* R54c (Pip P3-N3, 2.9c REVISION 4): on PHONE, TINY and SPLIT (the 44 and 40 px circle) the nod is stronger, two
   channels at once: the face grows by about the tablet's amount in px (1.14: 44 to 50.2 px), and at the peak the 2 px
   lilac ring becomes 3 px purple-deep (1.92:1 to 12.51:1 against the stage). It never stops him. */
.kfpt-stage--small .kfpt-host.is-nod { animation: kfpt-orinod-small 400ms ease-in-out 1; }
@keyframes kfpt-orinod-small {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 2px var(--kf-lilac); }
  50% { transform: scale(1.14); box-shadow: 0 0 0 3px var(--kf-purple-deep); }
}
/* no picture at all (even the format's own failed): no empty ring and no tail pointing at nothing (2.20) */
.kfpt-stage--nohost .kfpt-host { display: none; }
.kfpt-stage--nohost .kfpt-bubble::before { display: none; }

.kfpt-bubble {
  position: relative;
  box-sizing: border-box;
  height: 100%;
  display: flex;
  align-items: center;
  gap: var(--kfpt-bgap, 14px);
  padding: var(--kfpt-bpv, 10px) var(--kfpt-bph, 14px);
  background: var(--color-surface);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
  /* one width per layout on WIDE and STACKED (the widest row of any line): the right edge never moves */
  width: var(--kfpt-bubw, 36rem);
  max-width: 100%;
  flex: none;
}
/* the 13 px tail, toward Ori's circle centre */
.kfpt-bubble::before {
  content: '';
  position: absolute;
  left: -13px;
  top: 50%;
  margin-top: -10px;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
  border-right: 13px solid var(--color-surface);
}
.kfpt-stage--small .kfpt-bubble { flex: 1 1 auto; width: auto; min-width: 0; }
.kfpt-listen { flex: none; }
.kfpt-listen[hidden] { display: none; }
/* round 6b (Nova's R64 ruling): while a slow clip is waited for, the Listen pill breathes, opacity 1 to 0.55 and back in
   one 1.2 s ease-in-out cycle; no colour, no text, nothing flashes. Reduced motion: held at 0.7 (below) */
.kfpt-listen.is-waiting { animation: kfpt-waiting 1.2s ease-in-out infinite; }
@keyframes kfpt-waiting { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
.kfpt-stage .kfpt-listen:focus-visible { outline: 3px solid var(--kf-purple-deep); outline-offset: 3px; }
/* the cue slot (WIDE and STACKED): its box is there for the whole game; what is in it shows only with the ask line */
.kfpt-cueslot { position: relative; flex: none; width: 72px; height: 72px; display: block; }
.kfpt-cueslot[hidden],
.kfpt-stage--small .kfpt-cueslot { display: none; }
.kfpt-cueslot > .kfpt-cue,
.kfpt-cueslot > .kfpt-chip { position: absolute; inset: 0; }
.kfpt-cue { display: block; }
.kfpt-cue[hidden] { display: none; }
.kfpt-cue img { width: 100%; height: 100%; object-fit: contain; display: block; pointer-events: none; }
/* the sound chip on a listen moment: it plays the song's own snippet (a press while it plays starts it again) */
.kfpt-chip {
  width: 72px;
  height: 72px;
  box-sizing: border-box;
  display: grid;
  place-items: center;
  padding: 0;
  border-radius: 50%;
  background: linear-gradient(180deg, #fff6dc 0%, #ffe9a8 100%); /* --pill-hint-grad */
  border: 3px solid var(--kf-gold);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.kfpt-chip[hidden] { display: none; }
.kfpt-chip svg { display: block; }
.kfpt-chip.is-playing { background: #ffe9a8; border-color: var(--kf-purple-deep); }
.kfpt-chip:focus-visible { outline: 3px solid var(--kf-purple-deep); outline-offset: 3px; box-shadow: none; }
/* R14: every cue and the chip belong to the ask line: during the intro or a found line their box stays, empty */
.kfpt-stage:not(.kfpt-stage--cue-on) .kfpt-cueslot > *,
.kfpt-stage:not(.kfpt-stage--cue-on) .kfpt-pcue,
.kfpt-stage:not(.kfpt-stage--cue-on) .kfpt-scue,
.kfpt-stage:not(.kfpt-stage--cue-on) .kfpt-findcue { visibility: hidden; }
/* a cue answers a tap (R21): pointer only, it nods once */
.kfpt-cuetap { cursor: pointer; -webkit-tap-highlight-color: transparent; user-select: none; }
.kfpt-cuetap.is-nod { animation: kfpt-cuenod 400ms ease-in-out 1; }
@keyframes kfpt-cuenod { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.06); } }
/* Ori's line: its box is MEASURED from the video's tallest line (R30), so the bar and the options never move */
.kfpt-line {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  height: var(--kfpt-lineh, 60px);
  display: flex;
  align-items: center;
}
.kfpt-line-t {
  display: block;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: var(--text-child-floor);
  line-height: 1.3;
  color: var(--kf-purple-deep);
  text-align: left;
  text-wrap: pretty;
}
/* R41 (2.2): on PHONE and TINY, where the measured head row leaves 40 px or more under Listen, the bubble is a grid
   for the whole game: Listen over the cue slot in Listen's own 64 px column, the line beside both, so the line box
   keeps its width and no line changes rows. The slot shows a pick moment's picture cue only, with the ask line. */
.kfpt-stage--bcue .kfpt-bubble {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr);
  grid-template-rows: 64px var(--kfpt-bcue, 48px);
  grid-template-areas: "listen line" "cue line";
  column-gap: var(--kfpt-bgap, 8px);
  row-gap: var(--kfpt-bgap, 8px);
  align-content: center;
}
.kfpt-stage--bcue .kfpt-listen { grid-area: listen; }
.kfpt-stage--bcue .kfpt-line { grid-area: line; align-self: center; }
.kfpt-stage--bcue .kfpt-cueslot:not([hidden]) {
  display: block;
  grid-area: cue;
  justify-self: center;
  align-self: center;
  width: var(--kfpt-bcue, 48px);
  height: var(--kfpt-bcue, 48px);
}
.kfpt-stage--bcue .kfpt-cueslot > .kfpt-chip,
.kfpt-stage--bcue:not([data-type="pick"]) .kfpt-cueslot > .kfpt-cue { display: none; }
/* R52 (N2-5): nothing follows the end line, so in the end phase the cue slot goes, in the same frame (the line then
   starts 14 px after Listen and the bubble keeps its one width); written to beat the bubble grid above */
.kfpt-stage[data-phase="end"] .kfpt-bubble > .kfpt-cueslot { display: none; }

/* ---------- SPLIT: the cue row in the left column (R22) ---------- */
.kfpt-cuerow { display: none; }
.kfpt-stage--split .kfpt-cuerow { display: flex; align-items: center; justify-content: center; grid-column: 1; grid-row: 2; min-height: 0; overflow: visible; }
.kfpt-scue { display: none; width: var(--kfpt-scue, 0px); height: var(--kfpt-scue, 0px); }
.kfpt-stage--scue .kfpt-scue:not([hidden]) { display: block; }
.kfpt-scue img { width: 100%; height: 100%; object-fit: contain; display: block; pointer-events: none; }

/* ---------- the bar: memory strip | peek, sound, full screen | red X (2.5) ---------- */
.kfpt-bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  grid-template-areas: "strip tools x";
  align-items: center;
  column-gap: 8px;
  min-width: 0;
  height: var(--kfpt-barh, 72px);
}
.kfpt-stage--two .kfpt-bar {
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "strip x" "tools tools";
  grid-template-rows: auto 64px;
  row-gap: var(--kfpt-barrowgap, 8px);
}
/* the strip starts empty and draws nothing (5b.6): no plate, no outline, no count */
.kfpt-strip { grid-area: strip; position: relative; list-style: none; margin: 0; padding: 0; height: var(--kfpt-thh, 56px); min-width: 0; }
.kfpt-strip li {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--kfpt-thw, 100px);
  height: var(--kfpt-thh, 56px);
  box-sizing: border-box;
  border: 3px solid #fff;
  border-radius: 8px;
  overflow: hidden;
  background: #fdf6e7;
  box-shadow: 0 2px 6px rgba(45, 27, 78, 0.22);
  transition: box-shadow 200ms ease;
}
.kfpt-strip li img { width: 100%; height: 100%; object-fit: cover; display: block; }
.kfpt-strip li.is-lit { box-shadow: 0 0 0 3px var(--kf-gold), 0 2px 6px rgba(45, 27, 78, 0.22); }
.kfpt-strip li.is-fade { opacity: 0; transition: opacity 300ms ease; }
.kfpt-strip li.is-fade.is-on { opacity: 1; }
.kfpt-tools { grid-area: tools; display: flex; align-items: center; justify-content: flex-end; gap: 8px; min-width: 0; }
/* the peek pill: the house hint pill, always there (2.5) */
.kfpt-peekbtn,
.kfpt-backbtn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 64px;
  padding: 0 22px 0 14px;
  box-sizing: border-box;
  background: linear-gradient(180deg, #fff6dc 0%, #ffe9a8 100%); /* --pill-hint-grad */
  border: 3px solid var(--kf-gold);
  border-radius: var(--radius-pill);
  color: var(--kf-purple-deep);
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: var(--text-child-floor);
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--shadow-soft);
  -webkit-tap-highlight-color: transparent;
  white-space: nowrap;
}
.kfpt-peekbtn[hidden] { display: none; }
.kfpt-peekbtn svg,
.kfpt-backbtn svg { display: block; flex: none; }
.kfpt-peekbtn.is-open { background: #ffe9a8; border-color: var(--kf-purple-deep); }
.kfpt-peekbtn:focus-visible { outline: 3px solid var(--kf-purple-deep); outline-offset: 3px; box-shadow: var(--shadow-soft); }
/* the 30-second helper and the muted bell's answer: one glow at --glow-hint-full, 700 in, 600 held, 700 out
   (2.13, 2.15; round 1's soft glow was barely seen) */
.kfpt-peekbtn::after,
.kfpt-mute::after {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: inherit;
  box-shadow: var(--glow-hint-full);
  opacity: 0;
  pointer-events: none;
}
.kfpt-peekbtn.is-glow::after,
.kfpt-mute.is-glow::after { animation: kfpt-glow 2s ease-in-out 1; }
@keyframes kfpt-glow { 0% { opacity: 0; } 35%, 65% { opacity: 1; } 100% { opacity: 0; } }
.kfpt-barbtn {
  position: relative;
  min-width: 64px;
  min-height: 64px;
  box-sizing: border-box;
  display: grid;
  place-items: center;
  padding: 0;
  background: var(--color-surface);
  border: 2px solid var(--kf-lilac);
  border-radius: var(--radius-md);
  color: var(--kf-purple-deep);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.kfpt-barbtn[hidden] { display: none; }
.kfpt-barbtn svg { display: block; }
@media (hover: hover) { .kfpt-barbtn:hover { border-color: var(--kf-purple-deep); } }
.kfpt-barbtn:focus-visible { outline: 3px solid var(--kf-purple-deep); outline-offset: 3px; box-shadow: none; }
.kfpt-exit {
  grid-area: x;
  width: 72px;
  height: 72px;
  margin-left: 4px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  display: grid;
  place-items: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.kfpt-exit-img { width: 66px; height: 66px; display: block; filter: drop-shadow(0 2px 4px rgba(15, 10, 36, 0.28)); }
.kfpt-exit:focus-visible { outline: 3px solid var(--kf-purple-deep); outline-offset: 2px; box-shadow: none; }
.kfpt-stage--small .kfpt-exit { width: 64px; height: 64px; margin-left: 0; }
.kfpt-stage--small .kfpt-exit-img { width: 50px; height: 50px; }

/* ---------- the main row (2.6) ---------- */
.kfpt-main {
  position: relative;
  height: var(--kfpt-mainh, 400px);
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.kfpt-board { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; transition: opacity 300ms ease; }
.kfpt-board.is-entering { opacity: 0; transition: none; }
/* the question: the cards, and on PHONE the pick moment's cue over them (R22) */
.kfpt-qwrap { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; width: 100%; }
.kfpt-pcue { display: none; flex: none; width: 56px; height: 56px; }
.kfpt-stage--pcue .kfpt-pcue { display: block; }
.kfpt-pcue img { width: 100%; height: 100%; object-fit: contain; display: block; pointer-events: none; }

/* ---------- option cards: one component, two orientations (2.7) ---------- */
.kfpt-opts { display: flex; align-items: center; justify-content: center; gap: var(--kfpt-og, 32px); }
.kfpt-stage--small .kfpt-opts { flex-direction: column; width: 100%; }
.kfpt-opt {
  position: relative;
  flex: none;
  display: flex;
  flex-direction: column;
  width: calc(var(--kfpt-p, 200px) + 6px);
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  background: var(--color-surface);
  border: 3px solid var(--kf-lilac);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
  overflow: hidden;
  font: inherit;
  color: var(--kf-purple-deep);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform 160ms ease, border-color 160ms ease, box-shadow 200ms ease, opacity 300ms ease;
}
.kfpt-opt-pic {
  position: relative;
  flex: none;
  display: block;
  width: var(--kfpt-p, 200px);
  height: var(--kfpt-p, 200px);
  background: #fdf6e7;
  border-radius: 15px 15px 0 0;
  overflow: hidden;
  transition: background-color 150ms ease;
}
/* the same cream ground and disc under every option, drawn here, so no picture can differ by its ground (AC-6) */
.kfpt-opt-pic::before {
  content: '';
  position: absolute;
  left: 6%;
  top: 6%;
  width: 88%;
  height: 88%;
  border-radius: 50%;
  background: #f5ead3;
  transition: opacity 150ms ease;
}
.kfpt-opt-pic img { position: relative; width: 100%; height: 100%; object-fit: contain; display: block; user-select: none; -webkit-user-drag: none; }
.kfpt-opt-word {
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--kfpt-band, 52px);
  padding: 0 8px;
  box-sizing: border-box;
  text-align: center;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: var(--text-child-label);
  line-height: 1.15;
  color: var(--kf-purple-deep);
  text-wrap: balance;
  transition: opacity 200ms ease;
}
.kfpt-stage--small .kfpt-opt { flex-direction: row; width: 100%; height: calc(var(--kfpt-p, 100px) + 6px); }
.kfpt-stage--small .kfpt-opt-pic { border-radius: 15px 0 0 15px; }
.kfpt-stage--small .kfpt-opt-word { height: auto; flex: 1 1 auto; justify-content: flex-start; padding: 0 16px; text-align: left; }
/* a column under 200 px (SPLIT on the 320 px phone held sideways, R43): the word keeps the band's 8 px sides, so the
   pilot's longest option word (75 px) fits beside a 79 px picture in a 180 px card */
.kfpt-stage--colnarrow .kfpt-opt-word { padding: 0 8px; }

/* the colour cards (R23): the asked object drawn from the data, filled with each card's colour; no inner disc */
.kfpt-opt--drawn .kfpt-opt-pic::before { display: none; }
.kfpt-draw { position: absolute; overflow: visible; }
.kfpt-draw-shade { fill: rgba(45, 27, 78, 0.38); }
.kfpt-draw-sheen { fill: #fff; opacity: 0.38; }
.kfpt-draw-line { fill: none; stroke: #2d1b4e; stroke-linecap: round; stroke-linejoin: round; stroke-width: max(2.5px, calc(var(--kfpt-p, 200px) * 0.0224)); }
.kfpt-draw-line > * { vector-effect: non-scaling-stroke; }
/* a colour card from a video without a drawing: the round-1 disc (one identical sheen on all three) */
.kfpt-swatch {
  position: absolute;
  left: 15%;
  top: 15%;
  width: 70%;
  height: 70%;
  border-radius: 50%;
  background: var(--kfpt-swatch, #ccc);
  box-shadow: inset 0 0 0 3px #2d1b4e;
}
.kfpt-swatch::after {
  content: '';
  position: absolute;
  left: 19%;
  top: 18%;
  width: 22%;
  height: 12%;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.35);
}
/* a picture that did not come: its word, large, on the cream ground; the card keeps its neighbours' box and the
   band its height (2.7, Sage nice 15) */
.kfpt-opt-alt { display: none; }
.kfpt-opt--noart .kfpt-opt-pic img { display: none; }
.kfpt-opt--noart .kfpt-opt-alt {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px;
  box-sizing: border-box;
  text-align: center;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: calc(var(--text-child-label) * 1.4);
  line-height: 1.1;
  color: var(--kf-purple-deep);
}
.kfpt-opt--noart .kfpt-opt-word { display: none; }
.kfpt-opt--noart { height: calc(var(--kfpt-p, 200px) + 6px + var(--kfpt-band, 52px)); }
.kfpt-stage--small .kfpt-opt--noart { height: calc(var(--kfpt-p, 100px) + 6px); }
/* loading: three outlines, cream picture areas, no shimmer */
.kfpt-opt--ghost {
  cursor: default;
  box-shadow: none;
  height: calc(var(--kfpt-p, 200px) + 6px + var(--kfpt-band, 52px));
  background: linear-gradient(#fdf6e7, #fdf6e7) top / 100% var(--kfpt-p, 200px) no-repeat, var(--color-surface);
}
.kfpt-stage--small .kfpt-opt--ghost { height: calc(var(--kfpt-p, 100px) + 6px); background: linear-gradient(#fdf6e7, #fdf6e7) left / var(--kfpt-p, 100px) 100% no-repeat, var(--color-surface); }

/* states (2.7): no grey, no dimming, no shake, no red, no cross; gold only for help and found (R15) */
@media (hover: hover) {
  .kfpt-board:not(.kfpt-board--rest) .kfpt-opt:not([aria-disabled="true"]):not(.kfpt-opt--ghost):not(.is-float):not(.is-pressed):hover { transform: translateY(-2px); box-shadow: var(--shadow-lift); }
}
/* every press shows for at least 160 ms, judged or not (the engine holds the class): purple-deep, never gold */
.kfpt-opt.is-pressed:not(.is-float):not(.is-right) { transform: scale(0.97); box-shadow: none; transition: transform 80ms ease, border-color 80ms ease, box-shadow 80ms ease; }
.kfpt-opt.is-pressed:not(.is-float):not(.is-right):not(.is-help) { border-color: var(--kf-purple-deep); }
.kfpt-opt:focus-visible { outline: 3px solid var(--kf-purple-deep); outline-offset: 3px; box-shadow: var(--shadow-soft); }
.kfpt-opt[aria-disabled="true"] { cursor: default; }
/* help: the answer alone, a gold border and the strong ring pair; WIDE and STACKED add the full glow outside, the
   small layouts an inner glow (the 10 px stage padding holds the rings but not an outer glow). The picture nods,
   the card never moves, so nothing reaches the stage's edge. */
.kfpt-opt.is-help,
.kfpt-opt.is-help:focus-visible { border-color: var(--kf-gold); box-shadow: var(--halo-select-strong), var(--glow-hint-full); }
.kfpt-stage--small .kfpt-opt.is-help,
.kfpt-stage--small .kfpt-opt.is-help:focus-visible { box-shadow: var(--halo-select-strong), inset 0 0 18px 4px rgba(212, 168, 67, 0.55); } /* --glow-hint-inset */
.kfpt-opt.is-help .kfpt-opt-pic > img,
.kfpt-opt.is-help .kfpt-opt-pic > svg { animation: kfpt-picnod 1200ms ease-in-out 300ms 1; }
@keyframes kfpt-picnod { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.08); } }
.kfpt-opt.is-right,
.kfpt-opt.is-right:focus-visible { border-color: var(--kf-gold); box-shadow: var(--halo-select-strong); }
.kfpt-opt.is-leaving { opacity: 0; transition: opacity 300ms ease; }
.kfpt-opt.is-right.is-leaving { transition: opacity 400ms ease; }
.kfpt-opt.is-gone { display: none; }
/* the card words fade under an open peek (Pip nice 10); R52 (Pip R2-N2): so does everything else in the main row,
   the pictures, the PHONE cue over them, the find still and its cue, so nothing beside the photo reads as part of the
   help. They are inert under the panel, so nothing that could be pressed is lost. */
.kfpt-stage.is-peeking .kfpt-opt-word { opacity: 0; }
.kfpt-board > * { transition: opacity 200ms ease; }
.kfpt-stage.is-peeking .kfpt-board > * { opacity: 0; }

/* a mistap: the picture floats away in a see-through bubble that stays inside the main row (2.8, R16). The engine
   sets --kfpt-dx and --kfpt-dy from the card's own box; the scale ends at .55 around the picture's centre. */
.kfpt-opt.is-float {
  z-index: 6;
  overflow: visible;
  pointer-events: none;
  border-color: transparent;
  background-color: transparent;
  box-shadow: none;
  transform-origin: 50% calc(3px + var(--kfpt-p, 200px) / 2);
  animation: kfpt-float 1100ms cubic-bezier(0.3, 0.6, 0.4, 1) forwards;
}
.kfpt-stage--small .kfpt-opt.is-float { transform-origin: calc(3px + var(--kfpt-p, 100px) / 2) 50%; }
.kfpt-opt.is-float .kfpt-opt-word { opacity: 0; }
.kfpt-opt.is-float .kfpt-opt-pic { background-color: transparent; clip-path: circle(46% at 50% 50%); }
.kfpt-opt.is-float .kfpt-opt-pic::before { opacity: 0; }
/* the rim is inside the circle (the clip cuts anything outside it): 2 px white outside, 2 px lilac inside, a faint
   film and one glint */
.kfpt-opt.is-float .kfpt-opt-pic::after {
  content: '';
  position: absolute;
  inset: 4%;
  border-radius: 50%;
  box-shadow: inset 0 0 0 2px #fff, inset 0 0 0 4px var(--kf-lilac);
  background:
    radial-gradient(ellipse 22% 12% at 30% 24%, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0) 100%),
    radial-gradient(circle, transparent 62%, rgba(255, 255, 255, 0.16) 86%, rgba(184, 160, 210, 0.26) 100%);
  animation: kfpt-fadein 200ms ease both;
}
@keyframes kfpt-float {
  0% { transform: translate(0, 0) scale(1); opacity: 1; }
  45% { opacity: 1; }
  85% { opacity: 0; }
  100% { transform: translate(var(--kfpt-dx, 0px), var(--kfpt-dy, 0px)) scale(0.55); opacity: 0; }
}
@keyframes kfpt-fadein { from { opacity: 0; } to { opacity: 1; } }
@keyframes kfpt-fadeout { to { opacity: 0; } }
@keyframes kfpt-dip { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
@keyframes kfpt-cuedip { 0%, 100% { opacity: 1; } 50% { opacity: 0.72; } }

/* ---------- find (2.6): the still, the places for the keyboard, the rings ---------- */
.kfpt-find { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; width: 100%; height: 100%; }
.kfpt-findcue { display: none; }
.kfpt-stage--phone .kfpt-findcue,
.kfpt-stage--tiny .kfpt-findcue,
.kfpt-stage--split.kfpt-stage--fcue .kfpt-findcue { display: block; flex: none; width: var(--kfpt-cues, 72px); height: var(--kfpt-cues, 72px); }
/* R56 (2.2 REVISION 4): on SPLIT, with the left row under 56 px, the find moment's cue picture sits above the still
   (R1's own place); the left row's cue is off on that moment */
.kfpt-stage--fcue .kfpt-scue { display: none !important; }
.kfpt-findcue img { width: 100%; height: 100%; object-fit: contain; display: block; pointer-events: none; }
.kfpt-still {
  position: relative;
  flex: none;
  width: var(--kfpt-stw, 640px);
  height: var(--kfpt-sth, 360px);
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: 0 2px 10px rgba(45, 27, 78, 0.22);
  background: #3b2a5e;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.kfpt-still[hidden] { display: none; }
.kfpt-still-img { width: 100%; height: 100%; object-fit: cover; display: block; user-select: none; -webkit-user-drag: none; }
/* pointer taps pass through the places to the picture (the hit circle decides); a press on a place uses the grid */
.kfpt-grid { position: absolute; inset: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-rows: repeat(3, minmax(0, 1fr)); pointer-events: none; }
.kfpt-cell { pointer-events: none; margin: 12px; padding: 0; border: 0; border-radius: 12px; background: transparent; }
/* controls on art: the two-tone ring (2.17) */
.kfpt-cell:focus-visible { outline: 3px solid var(--kf-purple-deep); outline-offset: 3px; box-shadow: 0 0 0 9px #fdf8ee; } /* --focus-on-art-shadow */
.kfpt-rings { position: absolute; inset: 0; pointer-events: none; }
/* the miss ring, two-tone so one band holds on any part of the still (nice item): 2 px lilac-deep on 3 px white */
.kfpt-missring {
  position: absolute;
  width: 72px;
  height: 72px;
  margin: -36px 0 0 -36px;
  box-sizing: border-box;
  border-radius: 50%;
  border: 2px solid var(--kf-lilac-deep);
  box-shadow: 0 0 0 3px #fff;
  animation: kfpt-miss 500ms ease-out forwards;
}
@keyframes kfpt-miss { from { transform: scale(0.333); opacity: 1; } to { transform: scale(1); opacity: 0; } }
@keyframes kfpt-missfade { from { opacity: 1; } to { opacity: 0; } }
.kfpt-helpring,
.kfpt-foundring { position: absolute; box-sizing: border-box; border-radius: 50%; border: 4px solid var(--kf-gold); }
.kfpt-helpring { box-shadow: 0 0 0 2px #2d1b4e, var(--glow-hint-full); }
.kfpt-foundring { box-shadow: var(--halo-select-strong); }

/* ---------- the peek: a photo panel over the main row only (2.10) ---------- */
.kfpt-peek { position: absolute; inset: 0; z-index: 10; }
.kfpt-peek[hidden] { display: none; }
/* the scrim is purple-deep, a warm dusk (nice item; round 1's navy .55 looked like a disabled grey) */
.kfpt-peek-ground { position: absolute; inset: 0; border-radius: var(--radius-md); background: rgba(45, 27, 78, 0.6); opacity: 0; transition: opacity 200ms ease; cursor: pointer; } /* --scrim-dusk */
.kfpt-peek-photo {
  position: absolute;
  margin: 0;
  box-sizing: border-box;
  border: 6px solid #fff;
  border-radius: 14px;
  overflow: hidden;
  background: #fff;
  box-shadow: 0 10px 30px rgba(15, 10, 36, 0.4);
  opacity: 0;
  transform: scale(0.96);
  transition: opacity 200ms ease, transform 200ms ease;
  cursor: pointer;
}
.kfpt-peek-photo img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 8px; }
.kfpt-backbtn {
  position: absolute;
  min-width: 132px;
  padding: 0 20px 0 12px;
  gap: 8px;
  box-shadow: 0 0 0 2px #2d1b4e, var(--shadow-soft);
  opacity: 0;
  transition: opacity 200ms ease;
}
.kfpt-backbtn:focus-visible { outline: 3px solid var(--kf-purple-deep); outline-offset: 3px; box-shadow: 0 0 0 9px #fdf8ee; } /* --focus-on-art-shadow */
.kfpt-peek.is-open .kfpt-peek-ground { opacity: 1; transition: opacity 250ms ease; }
/* R52 (Sage r2-N4): the photo's frame fades in once its picture has decoded (is-ready), at the latest 800 ms after
   the panel opened; the scrim and Back show at once, so the child never meets an empty white frame */
.kfpt-peek.is-open .kfpt-peek-photo.is-ready { opacity: 1; transform: none; transition: opacity 300ms ease-out, transform 300ms ease-out; }
.kfpt-peek.is-open .kfpt-backbtn { opacity: 1; transition: opacity 300ms ease-out; }

/* ---------- flights: the memory photo and the end's comets (2.9, 2.12) ---------- */
.kfpt-fx { position: absolute; inset: 0; z-index: 30; pointer-events: none; overflow: hidden; border-radius: inherit; }
.kfpt-memo {
  position: absolute;
  box-sizing: border-box;
  border: 6px solid #fff;
  border-radius: 12px;
  overflow: hidden;
  background: #fff;
  box-shadow: 0 10px 30px rgba(15, 10, 36, 0.35);
}
.kfpt-memo img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 6px; }
.kfpt-memo.is-fade { opacity: 0; transition: opacity 300ms ease; }
.kfpt-memo.is-fade.is-on { opacity: 1; }
.kfpt-comet { position: absolute; width: 0; height: 0; }
.kfpt-comet-photo { position: absolute; left: 0; top: 0; box-sizing: border-box; border: 2px solid #fff; border-radius: 6px; object-fit: cover; transform: translate(-50%, -50%); }
.kfpt-comet-star { position: absolute; left: -7px; top: -7px; width: 14px; height: 14px; opacity: 0; }
/* a 1.5 px purple rim so the star reads over the white card and the lilac stage on its way (2.12) */
.kfpt-comet-star svg { display: block; filter: drop-shadow(0 0 1.5px rgba(45, 27, 78, 0.6)); }
.kfpt-comet-dot { position: absolute; width: 4px; height: 4px; margin: -2px 0 0 -2px; border-radius: 50%; background: #f2c53d; opacity: 0; }

/* ---------- the end: a celebration card in the main row, the X stays reachable (2.12) ---------- */
.kfpt-end {
  box-sizing: border-box;
  max-width: 100%;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--kfpt-endgap, 24px);
  padding: var(--kfpt-endpad, 32px);
  background: var(--color-surface);
  border: 3px solid var(--kf-gold);
  border-radius: var(--radius-lg);
  box-shadow: 0 10px 30px rgba(15, 10, 36, 0.18);
  opacity: 0;
  transition: opacity 300ms ease;
}
.kfpt-end.is-on { opacity: 1; }
/* R65 (2.12 REVISION 4.2, Sage SG4-2): the end card holds the focus the last answer had (tabindex -1, a group named by
   the jar); the house ring on keyboard focus only (12.51:1 on the stage's lilac), none after a pointer's last tap */
.kfpt-end:focus { outline: none; }
.kfpt-end:focus-visible { outline: 3px solid var(--kf-purple-deep); outline-offset: 3px; }
/* the night pocket (R17): the jar sits on the dark ground it was painted for, canon colours only, inside the white
   card; the art itself is never repainted */
.kfpt-pocket {
  flex: none;
  display: grid;
  place-items: center;
  /* R52 (N2-7): the pocket keeps the reduced-motion halo inside its night, never on the white card */
  overflow: hidden;
  padding: var(--kfpt-pocketv, 16px) var(--kfpt-pocketh, 24px);
  border-radius: var(--radius-lg);
  background: radial-gradient(ellipse 75% 62% at 50% 44%, var(--kf-purple-deep) 0%, var(--kf-navy-dark) 100%); /* --surface-night-pocket */
}
.kfpt-stage--small .kfpt-pocket { border-radius: var(--radius-md); }
.kfpt-jar { position: relative; flex: none; width: var(--kfpt-jarw, 260px); height: var(--kfpt-jarh, 348px); }
.kfpt-jar img { position: absolute; inset: 0; width: 100%; height: 100%; display: block; user-select: none; }
/* the painted full jar, revealed from its base (the storybook formula, kf-storybook.js) */
.kfpt-jar-full {
  -webkit-mask-image: linear-gradient(to top, #000 0, #000 calc(var(--kf-jar) * 100% - 9%), rgba(0, 0, 0, 0.55) calc(var(--kf-jar) * 100% - 3%), transparent calc(var(--kf-jar) * 100%));
          mask-image: linear-gradient(to top, #000 0, #000 calc(var(--kf-jar) * 100% - 9%), rgba(0, 0, 0, 0.55) calc(var(--kf-jar) * 100% - 3%), transparent calc(var(--kf-jar) * 100%));
}
.kfpt-jar-full.is-rising { transition: --kf-jar 2400ms linear; }
.kfpt-jar.is-bloom { animation: kfpt-bloom 700ms ease-in-out 1; }
@keyframes kfpt-bloom {
  0%, 100% { filter: none; }
  50% { filter: drop-shadow(0 0 14px rgba(255, 214, 122, 0.95)) brightness(1.18); }
}
.kfpt-jar-after { opacity: 0; }
.kfpt-jar-after.is-on { opacity: 1; transition: opacity 600ms ease; }
.kfpt-jar.is-halo::before {
  content: '';
  position: absolute;
  inset: -12%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 214, 122, 0.75), rgba(255, 214, 122, 0));
}
/* two equal white pills, present from the start and hidden so nothing jumps (AC-11, VR-C10); above the confetti
   (the end row is z 26, the confetti 25); on WIDE and STACKED both take the wider pill's width (nice item) */
.kfpt-endrow {
  position: relative;
  z-index: 26;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  width: max-content;
  max-width: 100%;
  gap: var(--kfpt-btngap, 16px);
  visibility: hidden;
  opacity: 0;
  transition: opacity 300ms ease;
}
.kfpt-endrow.is-on { visibility: visible; opacity: 1; }
.kfpt-endbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 72px;
  min-width: 240px;
  padding: 0 24px;
  box-sizing: border-box;
  border-radius: var(--radius-pill);
  border: 3px solid var(--kf-purple-deep);
  background: var(--color-surface);
  color: var(--kf-purple-deep);
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: var(--text-child-floor);
  line-height: 1.1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: box-shadow 200ms ease;
}
.kfpt-endbtn svg { display: block; flex: none; }
@media (hover: hover) { .kfpt-endbtn:hover { box-shadow: var(--shadow-lift); } }
.kfpt-endbtn:focus-visible { outline: 3px solid var(--kf-purple-deep); outline-offset: 3px; box-shadow: none; }
.kfpt-stage--small .kfpt-endrow { grid-auto-flow: row; grid-auto-columns: auto; width: 100%; align-self: stretch; }
/* the small layouts: the pill is the card's width (2.2). R43 (N2-2): padding 4 12 and an 8 px icon gap, so both labels
   take one line at every spec pair (round 2's 4 16 / 10 broke "Watch the song" by 2.2 px at 667 x 375). A label takes
   a second balanced line only where the column cannot hold one (a 320 px phone held sideways, 200% zoom); two lines
   at 1.05 x 22.95 px = 48.2 px fit the pill's 50 px inside. */
.kfpt-stage--small .kfpt-endbtn { min-height: 64px; min-width: 0; width: 100%; padding: 4px 12px; gap: 8px; line-height: 1.05; white-space: normal; text-align: center; text-wrap: balance; }
/* R43: an end card column under 200 px: 10 px sides, a 24 px icon and a 6 px gap leave 94 px of label (two lines) */
.kfpt-stage--endnarrow .kfpt-endbtn { padding: 0 10px; gap: 6px; }
.kfpt-stage--endnarrow .kfpt-endbtn svg { width: 24px; height: 24px; }
.kfpt-confetti { position: absolute; inset: 0; z-index: 25; overflow: hidden; pointer-events: none; }
.kfpt-confetti span { position: absolute; top: -14px; width: 10px; height: 14px; border-radius: 3px; animation: kfpt-fall 1.9s ease-in forwards; }
@keyframes kfpt-fall { to { transform: translateY(110vh) rotate(540deg); opacity: 0.2; } }

/* ---------- state cards: error, an unknown song, a find still that did not come (2.20) ---------- */
.kfpt-statecard {
  display: grid;
  place-items: center;
  padding: 32px;
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-soft);
}
.kfpt-statepill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 64px;
  padding: 0 28px;
  box-sizing: border-box;
  background: linear-gradient(180deg, #ffd94d 0%, #f0b929 100%); /* --pill-gold-grad */
  border: 3px solid var(--kf-purple-deep);
  border-radius: var(--radius-pill);
  color: var(--kf-purple-deep);
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: var(--text-child-floor);
  text-decoration: none;
  cursor: pointer;
}
.kfpt-statepill:focus-visible { outline: 3px solid var(--kf-purple-deep); outline-offset: 3px; box-shadow: none; }
/* R69 (2.20 REVISION 4.1 and 4.2, Nova N-r4-2, Sage SG4-12): on the small layouts the state cards (the unknown song,
   the data error, the find still's card) keep their pill's word on one line: on the 320 px phone held sideways the
   180 px column left 54 px for "Pick a song", which broke into a three-line gold circle. No white-space rule: under a
   user's text spacing a label may take two lines inside its card, never run past it */
.kfpt-stage--small .kfpt-statecard { padding: 16px 12px; }
.kfpt-stage--small .kfpt-statepill { padding: 0 16px; }

/* ---------- reduced motion (2.16) ----------
   What goes: the lift, the press scale, the bubble's rise, the close-ranks glide, the nods, the peek's scale, the
   memory photo's flight, the comets, the jar's rise and bloom, the falling confetti. What stays: opacity, declared
   again here because tokens.css zeroes every duration with !important. */
@media (prefers-reduced-motion: reduce) {
  .kfpt-listen.is-waiting { animation: none !important; opacity: 0.7; }
  .kfpt-board { transition: opacity 300ms ease !important; }
  .kfpt-board.is-entering { transition: none !important; }
  .kfpt-opt,
  .kfpt-opt:hover,
  .kfpt-opt.is-pressed,
  .kfpt-host.is-pressed { transform: none !important; }
  .kfpt-opt.is-float { animation: kfpt-fadeout 400ms ease 200ms forwards !important; transform: none !important; }
  .kfpt-opt.is-float .kfpt-opt-pic::after { animation: kfpt-fadein 200ms ease both !important; }
  .kfpt-opt.is-float .kfpt-opt-word,
  .kfpt-opt-word { transition: opacity 200ms ease !important; }
  .kfpt-opt.is-dip { animation: kfpt-dip 200ms ease 1 !important; }
  .kfpt-opt.is-help .kfpt-opt-pic > img,
  .kfpt-opt.is-help .kfpt-opt-pic > svg { animation: none !important; }
  /* the nods answer a tap without movement (2.16, R36): a cue dips its opacity, Ori's ring turns purple-deep */
  .kfpt-cuetap.is-nod { animation: kfpt-cuedip 300ms ease-in-out 1 !important; transform: none !important; }
  .kfpt-host.is-nod { animation: none !important; transform: none !important; box-shadow: 0 0 0 2px var(--kf-purple-deep); }
  /* R54c: on the small layouts the ring is 3 px (no scale) */
  .kfpt-stage--small .kfpt-host.is-nod { box-shadow: 0 0 0 3px var(--kf-purple-deep) !important; }
  /* the main row's content under an open peek fades the same way (R52) */
  .kfpt-board > * { transition: opacity 200ms ease !important; }
  .kfpt-opt.is-leaving { transition: opacity 300ms ease !important; }
  .kfpt-peek-ground,
  .kfpt-backbtn { transition: opacity 200ms ease !important; }
  .kfpt-peek-photo { transform: none !important; transition: opacity 200ms ease !important; }
  .kfpt-peek.is-open .kfpt-peek-ground,
  .kfpt-peek.is-open .kfpt-peek-photo.is-ready,
  .kfpt-peek.is-open .kfpt-backbtn { transition: opacity 250ms ease !important; }
  .kfpt-missring { animation: kfpt-missfade 400ms ease forwards !important; transform: none !important; }
  .kfpt-memo.is-fade,
  .kfpt-strip li.is-fade { transition: opacity 300ms ease !important; }
  .kfpt-strip li { transition: box-shadow 300ms ease !important; }
  .kfpt-end { transition: opacity 300ms ease !important; }
  .kfpt-jar-after.is-on { transition: opacity 600ms ease !important; }
  .kfpt-jar.is-bloom { animation: none !important; }
  .kfpt-endrow { transition: opacity 300ms ease !important; }
  .kfpt-peekbtn.is-glow::after,
  .kfpt-mute.is-glow::after { animation: kfpt-glow 2s ease-in-out 1 !important; }
  .kfpt-confetti { opacity: 0; transition: opacity 300ms ease !important; }
  .kfpt-confetti.is-on { opacity: 1; }
  .kfpt-confetti span { animation: none !important; }
}
