/* Find the Differences / Farkları Bul (Memory & Focus Games)
 * Engine sheet, prefix kfsd-. Companion of kf-spot-diff.js.
 *
 * Game Shell (layout-patterns 5 + 5b): top bar 64 (56 on phones), the two
 * pictures fill the remaining budget (the engine measures and sets their
 * pixel size, side by side or stacked, whichever makes them larger), message
 * band 72 (64). Tokens only. Every highlight is a static state or one short
 * self-ending animation; nothing loops except the hint pulse the engine
 * removes after 2.2s; nothing flashes; nothing travels across the screen.
 */

.kf-spot-diff { position: relative; }
/* the shared full-screen layer's own X stays hidden inside THIS stage: the
   engine's top-bar red X does that job (a child never meets two X buttons) */
.kf-spot-diff > .kf-fs-x { display: none !important; }

/* ---------- stage ---------- */
.kfsd-stage {
  position: relative;
  /* the bar and the band are exactly as wide as the two pictures (the engine
     measures them into --kfsd-w), so no control ever drifts away from the
     picture it belongs to */
  width: var(--kfsd-w, auto);
  max-width: 100%;
  margin: 0 auto;
  box-sizing: border-box;
  background: var(--kf-lilac-soft);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-soft);
  /* air on every side: no heading, no band and no picture ever touches an
     edge (Deniz, 2026-08-19: "kenarlarda her zaman padding olmalı... hiçbir
     yazı başlık sınıra tepeye ya da alta"). Phones get the tighter step
     below, where the height is worth more than the air. */
  padding: var(--space-3);
  display: grid;
  /* ONE ROW PER CHILD, in order: heading, bar, pictures, message band. The
     pictures' row is the only one that stretches. Adding a child without
     adding a row here does not add a row - it SHIFTS every child up one, and
     that is exactly how the pictures came to be drawn over the buttons. */
  grid-template-rows: auto auto minmax(0, 1fr) auto;
  gap: 8px;
  overflow: hidden;
}
.kfsd-stage--phone { padding: var(--space-2); }
.kfsd-fslead { height: 0; }
/* the shared layer pads the first child by 24px in wide mode (air above a
   game's own button row); here the bar is not the first child and that padding
   only pushed the whole centred block 24px down (measured: 153 above, 129
   below). The block centres itself, so the air is not needed. */
/* the layer's rule is [data-kf-fs].kf-fs-on[data-kf-fs-wide] > :first-child,
   which outranks a two-class selector even with !important; this one is
   deliberately one step stronger (measured: without it the block sat 24px low,
   153 above / 129 below on an 800px screen) */
[data-kf-fs].kf-spot-diff.kf-fs-on[data-kf-fs-wide] > .kfsd-fslead,
[data-kf-fs].kf-spot-diff.kf-fs-fake[data-kf-fs-wide] > .kfsd-fslead { padding-top: 0 !important; }
/* FULL SCREEN KEEPS THE PAGE'S FORM (Deniz, 2026-08-19: "bu normal ekrandaki
   form ve yerleşim tam ekranda da korunmalı ... sakın yukarda kalsın, sayfaya
   ortalı büyümeli ... butonlar resimlerden kopacak şekilde ayrı köşede
   olmamalı"). The stage is NOT stretched to the screen: it stays exactly as
   tall as bar + pictures + band and is CENTRED, and its width follows the
   pictures (the engine sets --kfsd-w), so the red X and the button row sit on
   the pictures' own corners instead of the screen's. */
.kf-spot-diff.kf-fs-on,
.kf-spot-diff.kf-fs-fake { display: flex; flex-direction: column; justify-content: center; }
.kf-spot-diff.kf-fs-on .kfsd-stage,
.kf-spot-diff.kf-fs-fake .kfsd-stage,
.kf-spot-diff.kf-fs-on > .kf-fs-grow,
.kf-spot-diff.kf-fs-fake > .kf-fs-grow {
  flex: 0 1 auto;
  min-height: 0;
  height: auto;
  margin: auto;
  border-radius: var(--radius-lg);
  box-shadow: none;
}

/* the board's heading: how many differences THIS picture hides. Centred over
   the bar, quiet enough that the pictures stay the loudest thing on screen. */
.kfsd-title {
  margin: 2px 0 4px;
  text-align: center;
  font-family: var(--font-heading);
  font-weight: 800;
  font-size: 1.25rem;
  line-height: 1.2;
  color: var(--kf-purple-deep);
}
.kfsd-stage--phone .kfsd-title { font-size: 1.05rem; margin-bottom: 4px; }

/* ---------- top bar ---------- */
/* positioned: the volume box anchors to this bar, not to the stage */
.kfsd-bar {
  position: relative;
  /* FLEX, NOT GRID, because the row has to be allowed to BREAK. Stars first,
     buttons last (Deniz's mockup). A two-column grid held them on one line at
     any width, and on a 768 portrait tablet the stage is ~420px wide: the
     buttons kept their size and ate the star pill, which was measured showing
     28px of its own 228px. Wrapping puts the buttons on their own line there
     instead, and nothing is cut. */
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  /* every line hugs the RIGHT: the stars push themselves left with an auto
     margin, so on a narrow stage a wrapped line (the tools, or the X on its
     own) still ends where the picture ends instead of starting at the left */
  justify-content: flex-end;
  gap: 8px;
  min-height: 72px;
}
/* phones: five controls and a star row do not share 375px in one line (the
   stars folded into a 42px column and the bar grew to 184px, measured); the
   bar becomes two rows: the stars, then the five buttons centred */
.kfsd-stage--phone .kfsd-bar,
.kfsd-stage--tight .kfsd-bar { min-height: 56px; row-gap: 6px; }
/* the four tools take the whole second line and centre on it; the X stays on
   the first line with the stars, pushed to the right edge */
.kfsd-stage--phone .kfsd-barright,
.kfsd-stage--tight .kfsd-barright { flex: 1 0 100%; order: 1; justify-content: center; }
.kfsd-barbtn {
  min-width: 64px;
  min-height: 64px;
  box-sizing: border-box;
  display: grid;
  place-items: center;
  background: var(--color-surface);
  border: 2px solid var(--kf-lilac);
  border-radius: var(--radius-md);
  color: var(--kf-purple-deep);
  cursor: pointer;
  padding: 0;
  -webkit-tap-highlight-color: transparent;
}
.kfsd-barbtn:hover { border-color: var(--kf-gold); }
.kfsd-barbtn:focus-visible { outline: 3px solid var(--kf-purple-deep); outline-offset: 3px; }
.kfsd-barbtn[aria-pressed='true'] { background: var(--kf-teal-soft); border-color: var(--kf-teal); }
/* THE HINT IS A GOLD PILL, the same one Look and Remember got (Deniz, 2026-08-20:
   "8 farki bul oyunundaki butonlari da bu son yaptigin sevimli buton ile
   degistirir misin"). Its word sits BESIDE the lantern instead of under it, so
   both can be big enough to read; the other tools keep the white card, which is
   what the two games already shared. */
.kfsd-barbtn.kfsd-hint {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  padding: 0 22px 0 16px;
  background: linear-gradient(180deg, #fff6dc 0%, #ffe9a8 100%);
  border: 3px solid var(--kf-gold);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-soft);
}
.kfsd-barbtn.kfsd-hint:hover { border-color: var(--kf-gold); filter: brightness(1.04); }
.kfsd-barbtn.kfsd-hint .kfsd-barword { font-size: 1.05rem; font-weight: 800; }
.kfsd-barbtn.kfsd-hint svg { display: block; }
.kfsd-stage--phone .kfsd-barbtn.kfsd-hint,
.kfsd-stage--tight .kfsd-barbtn.kfsd-hint { padding: 0 16px 0 12px; }
.kfsd-stage--phone .kfsd-barbtn.kfsd-hint .kfsd-barword,
.kfsd-stage--tight .kfsd-barbtn.kfsd-hint .kfsd-barword { font-size: 0.95rem; }
.kfsd-stage--phone .kfsd-barbtn,
.kfsd-stage--tight .kfsd-barbtn { min-width: 56px; min-height: 56px; }
/* The way out is not a fifth tool: no card behind it, and bigger than the
   buttons it stands beside (Deniz's mockup). The bar's min-height carries the
   larger size, so the row does not grow taller than the X itself. */
.kfsd-exit { background: transparent; border-color: transparent; min-width: 72px; min-height: 72px; margin-left: 4px; }
.kfsd-exit:hover { border-color: transparent; }
.kfsd-exit-img { width: 66px; height: 66px; display: block; filter: drop-shadow(0 2px 4px rgba(15, 10, 36, 0.28)); }
.kfsd-stage--phone .kfsd-exit,
.kfsd-stage--tight .kfsd-exit { min-width: 56px; min-height: 56px; margin-left: 0; }
.kfsd-stage--phone .kfsd-exit-img,
.kfsd-stage--tight .kfsd-exit-img { width: 48px; height: 48px; }
/* pushed to the far end of the row; when the row breaks, it lands on its own
   line and stays right-aligned there (the phone rule centres it instead) */
.kfsd-barright { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.kfsd-mute { grid-auto-flow: row; row-gap: 0; padding: 4px 10px; min-width: 76px; }
.kfsd-mute svg { display: block; }
.kfsd-stage--phone .kfsd-mute,
.kfsd-stage--tight .kfsd-mute { min-width: 64px; padding: 2px 6px; }
/* the volume box: anchored under the speaker button, one row high, never a
   card in the middle of the screen (the room's pattern, D-121) */
.kfsd-volbox {
  position: absolute;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: var(--color-surface);
  border: 2px solid var(--kf-lilac);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-lift);
}
.kfsd-volbox[hidden] { display: none; }
.kfsd-volmute {
  min-width: 44px;
  min-height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--kf-purple-deep);
  cursor: pointer;
}
.kfsd-volrange { width: 160px; height: 44px; accent-color: var(--kf-teal); cursor: pointer; }
.kfsd-stage--phone .kfsd-volrange { width: 120px; }
/* the lantern carries its word (icon + text, never a bare glyph for a child) */
.kfsd-hint,
.kfsd-zoom { grid-auto-flow: row; row-gap: 0; padding: 4px 10px; min-width: 76px; }
.kfsd-hint svg,
.kfsd-zoom svg { display: block; }
.kfsd-barword { font-family: var(--font-heading); font-weight: 700; font-size: 0.85rem; line-height: 1; color: var(--kf-purple-deep); }
.kfsd-stage--phone .kfsd-hint,
.kfsd-stage--phone .kfsd-zoom { min-width: 64px; padding: 2px 6px; }
.kfsd-stage--phone .kfsd-barword { font-size: 0.75rem; }
/* the stuck nudge: the lantern BUTTON glows teal three times and scales a
   little, so "tap the lantern" points at the button and not at a lantern
   in the picture (Pip V6); the engine removes the class after 2.4s */
.kfsd-hint.is-nudge { animation: kfsd-nudge 800ms ease-in-out 3; }
@keyframes kfsd-nudge { 0%, 100% { transform: scale(1); box-shadow: none; } 50% { transform: scale(1.08); box-shadow: 0 0 0 4px #fff, 0 0 0 8px var(--kf-teal), 0 0 22px 8px rgba(46, 196, 182, 0.55); } }
/* pictorial progress: one star per difference, lit as they are found */
.kfsd-stars {
  flex: 0 1 auto;
  margin-right: auto;
  display: inline-flex;
  gap: 5px;
  align-items: center;
  /* the score reads at a glance, like the X beside it (Deniz: "yıldızlı sayım
     butonu da büyüsün") */
  padding: 9px 16px;
  border-radius: var(--radius-pill);
  background: var(--surface-on-art);
  box-shadow: var(--rim-on-art);
  max-width: 100%;
  flex-wrap: wrap;
  justify-content: center;
}
.kfsd-star { display: inline-flex; color: rgba(253, 250, 244, 0.28); }
.kfsd-star.is-lit { color: var(--kf-gold); }
.kfsd-star svg { display: block; width: 26px; height: 26px; }
.kfsd-stage--phone .kfsd-star svg { width: 18px; height: 18px; }

/* ---------- main: the two pictures ---------- */
.kfsd-main {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  min-width: 0;
}
.kfsd-pics {
  display: flex;
  flex-direction: row;
  gap: var(--pgap, 10px);
  align-items: center;
  justify-content: center;
  flex: none;
}
.kfsd-pics.is-stacked { flex-direction: column; }
.kfsd-pic {
  position: relative;
  flex: none;
  overflow: hidden;
  border-radius: var(--radius-md);
  background: var(--kf-teal-soft);
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.85);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  -webkit-user-select: none;
}
/* the browser must not scroll or pinch while the child drags a zoomed
   picture; at 1x the page keeps its normal touch behaviour */
.kfsd-pics.is-zoomed .kfsd-pic { touch-action: none; cursor: grab; }
.kfsd-pics.is-zoomed .kfsd-pic:active { cursor: grabbing; }
.kfsd-sheet {
  position: absolute;
  inset: 0;
  transform-origin: 0 0;
  will-change: transform;
}
.kfsd-img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: fill;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}
.kfsd-fxlayer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
/* NO RING, NO FRAME (Deniz, 2026-08-19, after playing it: "böyle çerçeveli
   olmasın kötü duruyor ... effect kalıcı olmasın sadece numaralar kalıcı
   olsun"). What a found difference gets is LIGHT: sparkles around it and a glow
   on the item itself, both gone in about a second and a half. The number beside
   it is the only lasting mark. */
.kfsd-fx { pointer-events: none; }
.kfsd-sparkle {
  fill: #ffe27a;
  stroke: #fdfaf4;
  stroke-width: 0.08;
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
  filter: drop-shadow(0 0 0.4px rgba(255, 226, 122, 0.9));
  animation: kfsd-twinkle 1000ms ease-out 1 forwards;
}
@keyframes kfsd-twinkle {
  0%   { opacity: 0; transform: scale(0.2) rotate(-25deg); }
  35%  { opacity: 1; transform: scale(1.15) rotate(0deg); }
  70%  { opacity: 0.85; transform: scale(0.95) rotate(12deg); }
  100% { opacity: 0; transform: scale(0.35) rotate(25deg); }
}
.kfsd-fx.is-hint .kfsd-sparkle { fill: #9df3ea; animation-duration: 1600ms; }
/* the hint's pointer: a soft ring of light with no edge (the blur is set inline
   in the picture's own units, so it stays soft at every zoom), breathing three
   times where the difference is; the engine removes it */
.kfsd-hint-fx { pointer-events: none; animation: kfsd-hintpulse 700ms ease-in-out 3; }
.kfsd-halo { fill: rgba(46, 196, 182, 0.34); }   /* light OVER the item, never
   thick enough to hide it: the child still has to compare what is underneath */
@keyframes kfsd-hintpulse { 0%, 100% { opacity: 0.25; } 50% { opacity: 0.9; } }

/* THE LAYER'S LIGHT (Deniz, 2026-08-19: "layerlı verdim tüm değişiklikleri ve
   bunu iyi kullanman, eğlenceli güzel bir efekt vermen lazım", then after
   playing it: "büyüme sallanma olmasın"). The found item's own cut-out is laid
   exactly over its place and lights up once: it does NOT grow and does NOT
   wobble, only light moves, and then it fades. It sits inside the zoomed sheet,
   so it follows the picture's own zoom and pan.
   Never clickable, never in the reading order. */
.kfsd-pop {
  position: absolute;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
  will-change: filter;
  z-index: 2;
  animation: kfsd-bloom 1500ms ease-out 1 both;
}
/* light only: the item does NOT grow and does NOT wobble (Deniz: "hareket
   derken büyüme sallanma olmasın kötü durdu o da"). It sits exactly where it
   already is, lights up from inside, and fades. The same rule holds for the
   puff below: nothing in this effect moves except light. */
@keyframes kfsd-bloom {
  0%   { filter: drop-shadow(0 0 0 rgba(255, 226, 122, 0)); opacity: 0.9; }
  18%  { filter: drop-shadow(0 0 14px rgba(255, 255, 235, 1)) drop-shadow(0 0 30px rgba(255, 226, 122, 0.9)) drop-shadow(0 0 52px rgba(212, 168, 67, 0.65)); opacity: 1; }
  55%  { filter: drop-shadow(0 0 7px rgba(255, 255, 235, 0.8)) drop-shadow(0 0 20px rgba(255, 226, 122, 0.6)) drop-shadow(0 0 36px rgba(212, 168, 67, 0.4)); opacity: 1; }
  100% { filter: drop-shadow(0 0 0 rgba(255, 226, 122, 0)); opacity: 0; }
}
/* where the item is not on that picture (it vanished, or it only arrives in
   the second one) there is no layer to light up, so its place glows instead:
   the child's finger is answered on BOTH pictures either way.
   It is LIGHT and nothing else. It had a 2px ring inside it and it grew, which
   is the very frame and the very growing Deniz threw out; both are gone. The
   gradient fades to nothing well before the box edge, so there is no edge to
   see, and only the opacity moves. */
.kfsd-puff {
  position: absolute;
  pointer-events: none;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, rgba(255, 255, 235, 0.85) 0%, rgba(255, 226, 122, 0.6) 30%, rgba(212, 168, 67, 0.28) 55%, rgba(212, 168, 67, 0) 76%);
  z-index: 2;
  animation: kfsd-puff 1100ms ease-out 1 both;
}
@keyframes kfsd-puff {
  0%   { opacity: 0; }
  22%  { opacity: 1; }
  100% { opacity: 0; }
}
/* the miss ripple: a ring that grows out from the finger and fades, 600ms */
.kfsd-ripple {
  position: absolute;
  width: 20px;
  height: 20px;
  margin: -10px 0 0 -10px;
  border-radius: 50%;
  border: 3px solid rgba(253, 250, 244, 0.95);
  box-shadow: 0 0 0 2px rgba(45, 27, 78, 0.35);
  pointer-events: none;
  animation: kfsd-ripple 600ms ease-out 1 forwards;
  z-index: 3;
}
@keyframes kfsd-ripple { 0% { transform: scale(0.6); opacity: 1; } 100% { transform: scale(3.4); opacity: 0; } }
/* the number badge beside a found difference (Deniz: "numara belirsin işaretin
   yanında"): a 30px gold disc with the found order, constant CSS size (it
   lives outside the zoomed sheet and is re-placed by the engine) */
.kfsd-badges { position: absolute; inset: 0; pointer-events: none; z-index: 4; }
.kfsd-badge {
  position: absolute;
  width: 30px;
  height: 30px;
  margin: -15px 0 0 -15px;
  border-radius: 50%;
  background: var(--kf-gold);
  color: var(--kf-navy-dark);
  border: 2px solid #fdfaf4;
  box-shadow: 0 2px 6px rgba(15, 10, 36, 0.35);
  font-family: var(--font-heading);
  font-weight: 800;
  font-size: 1.05rem;
  line-height: 26px;
  text-align: center;
  animation: kfsd-badgein 400ms cubic-bezier(0.2, 0.9, 0.3, 1.2) 1;
}
@keyframes kfsd-badgein { 0% { transform: scale(0.4); opacity: 0; } 100% { transform: scale(1); opacity: 1; } }
/* a tap on a difference already found: its number nods once; nothing else
   happens, and the miss streak is untouched */
.kfsd-badge.is-nod { animation: kfsd-nod 420ms ease-in-out 1; }
@keyframes kfsd-nod { 0%, 100% { transform: scale(1); } 45% { transform: scale(1.25); } }
/* small pictures (under 500 CSS px, phones): 20px discs so eight numbers do
   not cover the eight things they mark (Pip V3) */
.kfsd-pics.is-small .kfsd-badge { width: 20px; height: 20px; margin: -10px 0 0 -10px; line-height: 16px; font-size: 0.8rem; border-width: 2px; }
.kfsd-badge[hidden] { display: none; }
/* keyboard targets: invisible, never a pointer tell (no cursor, no hover);
   the focus ring is the only paint, and only for keyboard focus */
.kfsd-targets { position: absolute; inset: 0; pointer-events: none; }
.kfsd-target {
  position: absolute;
  padding: 0;
  margin: 0;
  border: 0;
  background: transparent;
  border-radius: 50%;
  pointer-events: none;
}
.kfsd-target:focus-visible { outline: 4px solid var(--kf-gold); outline-offset: 2px; }
.kfsd-target[hidden] { display: none; }
/* loading skeleton: soft pulse until both pictures arrive */
.kfsd-pics.is-loading .kfsd-pic { animation: kfsd-skeleton 1.4s ease-in-out infinite alternate; }
@keyframes kfsd-skeleton { from { background-color: var(--kf-teal-soft); } to { background-color: var(--kf-lilac-soft); } }
.kfsd-error {
  position: absolute;
  inset: 0;
  z-index: 11;
  display: grid;
  place-content: center;
  gap: var(--space-3);
  text-align: center;
  padding: var(--space-3);
  background: var(--kf-cream);
  border-radius: var(--radius-md);
}
.kfsd-error p { margin: 0; font-size: var(--text-base); color: var(--color-text); }

/* ---------- message band: always populated, reserved height ---------- */
.kfsd-msg {
  min-height: 72px;
  box-sizing: border-box;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  padding: 6px 10px;
  background: var(--color-surface);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
}
.kfsd-stage--phone .kfsd-msg { min-height: 64px; padding: 4px 8px; gap: 8px; }
/* The opening line got longer when Deniz asked it to say what to look for and
   how many there are (2026-08-20). On a 375px phone that is three lines, and
   the pictures were squeezed from 200 to 190px to pay for it, which house rule
   5b.3 does not allow. The line pays for itself instead: smaller type and a
   tighter leading on the phone only, measured back to 200. */
.kfsd-stage--phone .kfsd-msg-text { font-size: 0.98rem; line-height: 1.18; }
.kfsd-msg-glyph { display: inline-flex; }
.kfsd-msg-text {
  margin: 0;
  text-align: center;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: clamp(1.05rem, 0.9rem + 0.6vw, 1.3rem);
  line-height: 1.25;
  color: var(--kf-purple-deep);
}
.kfsd-listen[hidden] { display: none; }

/* ---------- overlays: exit confirm + celebration (pattern 6 / 7) ---------- */
.kfsd-overlay {
  position: absolute;
  inset: 0;
  background: var(--scrim-navy);
  display: grid;
  place-items: center;
  z-index: 30;
}
.kfsd-card {
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lift);
  padding: var(--space-4);
  margin: var(--space-3);
  max-width: 26rem;
  text-align: center;
  max-height: calc(100% - 2 * var(--space-3));
  overflow-y: auto;
  box-sizing: border-box;
}
.kfsd-card h2 {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: var(--text-xl);
  color: var(--kf-purple-deep);
  margin: 0 0 var(--space-3);
}
.kfsd-card p { margin: 0 0 var(--space-3); font-size: var(--text-base); line-height: 1.45; color: var(--color-text); }
.kfsd-pills { display: flex; justify-content: center; flex-wrap: wrap; gap: var(--space-3); }
.kfsd-pill {
  min-height: 64px;
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: var(--radius-pill);
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 1.15rem;
  padding: 0 var(--space-4);
  cursor: pointer;
  text-decoration: none;
  color: var(--kf-navy-dark);
}
.kfsd-pill--gold { background: linear-gradient(180deg, #ffd94d 0%, #f7c832 100%); color: var(--kf-purple-deep); }
.kfsd-pill--purple { background: var(--kf-purple-deep); color: #fff; }
.kfsd-pill:focus-visible { outline: 3px solid var(--kf-purple-deep); outline-offset: 3px; }
.kfsd-pill:disabled { cursor: default; opacity: 0.85; }
.kfsd-burst-static {
  position: absolute;
  left: 50%;
  top: 40%;
  width: 220px;
  height: 220px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(212, 168, 67, 0.5) 0%, rgba(212, 168, 67, 0.18) 45%, transparent 70%);
  pointer-events: none;
  z-index: 25;
}
.kfsd-stage .kfe-confetti { border-radius: var(--radius-lg); z-index: 26; }

/* ---------- screen-reader-only ---------- */
.kfsd-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- phones ---------- */
/* phones: the bleed lives on the ROOT, not the stage, so the shared layer's
   start curtain (absolute inside the root) covers the whole width; a stage
   that bled past its root left two unblurred strips beside the veil (Pip V11) */
@media (max-width: 480px) {
  .kf-spot-diff {
    margin-left: calc(-1 * var(--space-4));
    margin-right: calc(-1 * var(--space-4));
  }
  .kfsd-stage { border-radius: 0; }
}

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  .kfsd-pics.is-loading .kfsd-pic,
  .kfsd-hint.is-nudge,
  .kfsd-badge,
  .kfsd-badge.is-nod,
  .kfsd-ripple { animation: none; }
  .kfsd-hint-fx { animation: none; opacity: 1; }
  .kfsd-sparkle { animation: none; opacity: 0; }
  .kfsd-ripple { opacity: 0.9; transform: scale(2.2); }
  /* the layer still answers the tap, it just holds STILL. Not a gentler
     animation: the site's reduced-motion reset (tokens.css) forces every
     animation to 0.01ms with !important, so a "calm" keyframe would land on its
     last frame instantly and show nothing at all (measured). So the state is
     written as plain properties: the item sits in its own place and glows gold
     for as long as the engine keeps it, then the engine removes it. */
  .kfsd-pop {
    animation: none;
    opacity: 1;
    filter: drop-shadow(0 0 10px rgba(255, 226, 122, 0.95)) drop-shadow(0 0 20px rgba(212, 168, 67, 0.6));
  }
  .kfsd-puff { animation: none; opacity: 0.9; }
}
