/* Combtone fx.css (look agent): every SPEC §10.2 motion, stamps, logo, signage, podium, stickers, cans.
 *
 * PILLAR 1: nothing in this file ever targets a chip <rect> or the mat. Classes here go on pins, outlines, paper cards, bars,
 * tickets, stamps and signage only. The two classes that would otherwise contain chips (.fx-lens-in / .fx-lens-out) are scale-only
 * and are switched OFF (not faded) under reduced motion, because a fade would tint the chips.
 *
 * MOTION MODEL
 *   Every motion class sets  --fx-kf (keyframes)  --fx-d (duration)  and optionally --fx-n (iterations) --fx-ease.
 *   One shared rule turns that into:  animation: var(--fx-kf) min(var(--fx-d), var(--fx-cap)) ease var(--fx-delay) var(--fx-n) both.
 *   Callers stagger with  style="--fx-i:2"  (classes that stagger multiply it) or  style="--fx-delay:240ms".
 * REDUCED MOTION (SPEC §9.6: "every animation becomes a <= 120 ms fade with identical timing")
 *   Triggered by  @media (prefers-reduced-motion: reduce)  unless <html data-motion="full">, or by <html data-motion="reduce">
 *   (also accepts "reduced", the kit's spelling). Keyframes switch to fx-fade, duration is capped at 120 ms, the DELAY (stagger and
 *   sequence) is untouched, iterations drop to 1, so the moment at which each thing appears is identical; JS helpers in
 *   ui/signage.js resolve their promises at the original time. Endless idle loops (logo sway) simply stop.
 */

:root {
  --fx-ease-out: cubic-bezier(.2, .8, .2, 1);
  --fx-ink: var(--ink, #16171a);
  --fx-paper: var(--paper, #f4f2ed);
  --fx-card: var(--card, #ffffff);
}

/* ------------------------------------------------------------------ the one animation rule */
.fx-slam, .fx-shake, .fx-print, .fx-extend, .fx-chatter, .fx-deal, .fx-flip, .fx-ring-draw, .fx-trace, .fx-pin-drop, .fx-press,
.fx-tickup, .fx-blink, .fx-pop, .fx-type, .fx-rumble, .fx-rise, .fx-name-in, .fx-slide-up, .fx-lens-in, .fx-lens-out,
.fx-fade, .fx-out, .fx-fill, .fx-sway, .fx-nudge {
  animation: var(--fx-kf, fx-fade) min(var(--fx-d, 160ms), var(--fx-cap, 60s)) var(--fx-ease, var(--fx-ease-out)) var(--fx-delay, 0ms) var(--fx-n, 1) var(--fx-dir, normal) both;
}

/* ------------------------------------------------------------------ motion classes (SPEC §10.2) */
/* Stamp slam 160 ms: the stamp element keeps its static rotate(-6deg); only scale + opacity animate (individual properties compose). */
.fx-slam   { --fx-kf: fx-slam;    --fx-d: 160ms; --fx-ease: cubic-bezier(.3, .0, .2, 1); }
/* RETURNED card shake: 3 px x 3 cycles (120 ms each = 360 ms). Uses `translate` so it composes with any transform. */
.fx-shake  { --fx-kf: fx-shake;   --fx-d: 120ms; --fx-n: 3; --fx-ease: linear; }
/* Receipt print: the ticket prints DOWN in 220 ms (stepped, like a thermal head). .fx-extend = the Actually... line added, 220 ms. */
.fx-print  { --fx-kf: fx-print;   --fx-d: 220ms; --fx-ease: steps(11, end); }
.fx-extend { --fx-kf: fx-print;   --fx-d: 220ms; --fx-ease: steps(11, end); }
/* Counter Call "exact" receipt-printer chatter: 8 bursts in 320 ms. */
.fx-chatter{ --fx-kf: fx-print;   --fx-d: 320ms; --fx-ease: steps(8, end); }
/* Slip card dealt: slides up from the counter edge, 250 ms each, 80 ms stagger (set --fx-i = index). */
.fx-deal   { --fx-kf: fx-deal;    --fx-d: 250ms; --fx-delay: calc(var(--fx-i, 0) * 80ms); }
/* Card flip 300 ms (scaleX squash; ui/signage.js flipCard swaps the face at the 150 ms midpoint). */
.fx-flip   { --fx-kf: fx-flip;    --fx-d: 300ms; --fx-ease: ease-in-out; }
/* Ring outlines: draw on the wall chips 200 ms (.fx-ring-draw) / trace along the mat gaps 300 ms (.fx-trace). Put pathLength="1" on the <path>. */
.fx-ring-draw { --fx-kf: fx-dash; --fx-d: 200ms; --fx-ease: ease-out; stroke-dasharray: 1; }
.fx-trace  { --fx-kf: fx-dash;    --fx-d: 300ms; --fx-ease: ease-out; stroke-dasharray: 1; }
/* Pin placed / moved: drops 80 ms with a 2 px overshoot. Reveal staggers pins 40 ms apart (set --fx-i). */
.fx-pin-drop { --fx-kf: fx-pin-drop; --fx-d: 80ms; --fx-ease: ease-in; --fx-delay: calc(var(--fx-i, 0) * 40ms); }
/* Lock in: the pin head presses down 60 ms. */
.fx-press  { --fx-kf: fx-press;   --fx-d: 60ms; --fx-ease: ease-out; }
/* Digits tick up, 120 ms each. */
.fx-tickup { --fx-kf: fx-tickup;  --fx-d: 120ms; }
/* Reveal: the customer's chip OUTLINE (an overlay stroke, never the chip) blinks twice, 2 x 120 ms. Reduced: one fade-in that stays. */
.fx-blink  { --fx-kf: fx-blink;   --fx-d: 120ms; --fx-n: 2; --fx-ease: ease-in-out; }
/* Points pop 180 ms (+5, +3 +1 Steady). */
.fx-pop    { --fx-kf: fx-pop;     --fx-d: 180ms; --fx-ease: cubic-bezier(.3, 1.4, .5, 1); --fx-delay: calc(var(--fx-i, 0) * 40ms); }
/* Customer line types in over 300 ms (set --fx-steps to the character count for a true typewriter feel). */
.fx-type   { --fx-kf: fx-type;    --fx-d: 300ms; --fx-ease: steps(var(--fx-steps, 14), end); }
/* Paint-shaker rumble under the first two reveal steps: put on the BOTTOM BAR or ticket, never on the wall. 16 Hz, ~0.9 s. */
.fx-rumble { --fx-kf: fx-rumble;  --fx-d: 62ms; --fx-n: 14; --fx-ease: linear; }
/* Podium block rises 400 ms (stagger with --fx-delay). */
.fx-rise   { --fx-kf: fx-rise;    --fx-d: 400ms; }
/* Player joins: name tag slides in from the right, 200 ms. */
.fx-name-in{ --fx-kf: fx-name-in; --fx-d: 200ms; }
/* Daily share card slides up. */
.fx-slide-up { --fx-kf: fx-slide-up; --fx-d: 320ms; }
/* Lens: scales from the tap point 120 ms, closes in 90 ms. Set --fx-ox / --fx-oy (e.g. 40px) on the lens. SCALE ONLY (lens holds chips). */
.fx-lens-in  { --fx-kf: fx-lens-in;  --fx-d: 120ms; transform-origin: var(--fx-ox, 50%) var(--fx-oy, 50%); }
.fx-lens-out { --fx-kf: fx-lens-out; --fx-d: 90ms;  --fx-ease: ease-in; transform-origin: var(--fx-ox, 50%) var(--fx-oy, 50%); }
/* Generic */
.fx-fade   { --fx-kf: fx-fade;    --fx-d: 120ms; --fx-ease: ease-out; }
.fx-out    { --fx-kf: fx-out;     --fx-d: 200ms; --fx-ease: ease-in; }
.fx-nudge  { --fx-kf: fx-nudge;   --fx-d: 120ms; }
/* Paint can fills with ink from the bottom up. */
.fx-fill   { --fx-kf: fx-fill;    --fx-d: 420ms; --fx-ease: ease-out; }
/* Title idle: the logo fan sways +-2 degrees on a 4 s loop. */
.fx-sway   { --fx-kf: fx-sway;    --fx-d: 4s; --fx-n: infinite; --fx-ease: ease-in-out; --fx-dir: normal; }

@keyframes fx-fade    { from { opacity: 0; } to { opacity: 1; } }
@keyframes fx-out     { from { opacity: 1; } to { opacity: 0; } }
@keyframes fx-slam {
  0%   { opacity: 0; scale: 1.9; }
  55%  { opacity: 1; scale: .94; }
  80%  { scale: 1.03; }
  100% { opacity: 1; scale: 1; }
}
@keyframes fx-shake   { 0%, 100% { translate: 0 0; } 25% { translate: -3px 0; } 75% { translate: 3px 0; } }
@keyframes fx-print   { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes fx-deal    { from { translate: 0 var(--fx-from, 110px); opacity: 0; } to { translate: 0 0; opacity: 1; } }
@keyframes fx-flip    { 0% { transform: scaleX(1); } 50% { transform: scaleX(.02); } 100% { transform: scaleX(1); } }
@keyframes fx-dash    { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes fx-pin-drop {
  0%   { translate: 0 -16px; opacity: 0; }
  70%  { translate: 0 2px;   opacity: 1; }
  100% { translate: 0 0;     opacity: 1; }
}
@keyframes fx-press   { 0% { scale: 1; translate: 0 0; } 50% { scale: .88; translate: 0 1.5px; } 100% { scale: 1; translate: 0 0; } }
@keyframes fx-tickup  { from { translate: 0 45%; opacity: 0; } to { translate: 0 0; opacity: 1; } }
@keyframes fx-blink   { 0%, 100% { opacity: 0; } 50% { opacity: 1; } }
@keyframes fx-pop {
  0%   { scale: .4; opacity: 0; translate: 0 6px; }
  60%  { scale: 1.15; opacity: 1; translate: 0 -1px; }
  100% { scale: 1; opacity: 1; translate: 0 0; }
}
@keyframes fx-type    { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes fx-rumble  { 0%, 100% { translate: 0 0; } 25% { translate: .8px -.8px; } 75% { translate: -.8px .8px; } }
@keyframes fx-rise    { from { clip-path: inset(100% 0 0 0); translate: 0 14px; } to { clip-path: inset(0 0 0 0); translate: 0 0; } }
@keyframes fx-name-in { from { translate: 60px 0; opacity: 0; } to { translate: 0 0; opacity: 1; } }
@keyframes fx-slide-up{ from { translate: 0 100%; opacity: 0; } to { translate: 0 0; opacity: 1; } }
@keyframes fx-lens-in { from { scale: .2; } to { scale: 1; } }
@keyframes fx-lens-out{ from { scale: 1; } to { scale: .2; } }
@keyframes fx-nudge   { 0% { translate: 0 0; } 50% { translate: 0 -2px; } 100% { translate: 0 0; } }
@keyframes fx-fill    { from { clip-path: inset(100% 0 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes fx-sway    { 0%, 100% { transform: rotate(-2deg); } 50% { transform: rotate(2deg); } }

/* ------------------------------------------------------------------ REDUCED MOTION: <= 120 ms fade, identical delays/timing */
@media (prefers-reduced-motion: reduce) {
  :root:not([data-motion="full"]) [class^="fx-"], :root:not([data-motion="full"]) [class*=" fx-"] {
    --fx-kf: fx-fade; --fx-cap: 120ms; --fx-n: 1; --fx-ease: ease-out;
    animation-duration: min(var(--fx-d, 160ms), 120ms) !important; animation-iteration-count: 1 !important;   /* beats any global `*{animation-duration:0!important}` */
  }
  :root:not([data-motion="full"]) .fx-sway, :root:not([data-motion="full"]) .fx-rumble,
  :root:not([data-motion="full"]) .fx-lens-in, :root:not([data-motion="full"]) .fx-lens-out { animation: none; }
  :root:not([data-motion="full"]) .fx-out { --fx-kf: fx-out; }
  :root:not([data-motion="full"]) .fx-lens-out { visibility: hidden; }
  :root:not([data-motion="full"]) .fx-card-flipper { transition: none; }
}
:root[data-motion="reduce"] [class^="fx-"], :root[data-motion="reduce"] [class*=" fx-"],
:root[data-motion="reduced"] [class^="fx-"], :root[data-motion="reduced"] [class*=" fx-"] {
  --fx-kf: fx-fade; --fx-cap: 120ms; --fx-n: 1; --fx-ease: ease-out;
  animation-duration: min(var(--fx-d, 160ms), 120ms) !important; animation-iteration-count: 1 !important;
}
:root[data-motion="reduce"] .fx-sway, :root[data-motion="reduce"] .fx-rumble, :root[data-motion="reduce"] .fx-lens-in, :root[data-motion="reduce"] .fx-lens-out,
:root[data-motion="reduced"] .fx-sway, :root[data-motion="reduced"] .fx-rumble, :root[data-motion="reduced"] .fx-lens-in, :root[data-motion="reduced"] .fx-lens-out { animation: none; }
:root[data-motion="reduce"] .fx-out, :root[data-motion="reduced"] .fx-out { --fx-kf: fx-out; }
:root[data-motion="reduce"] .fx-lens-out, :root[data-motion="reduced"] .fx-lens-out { visibility: hidden; }

/* ------------------------------------------------------------------ stamps (SPEC §7.8) */
.fx-stamp {
  display: inline-block; line-height: 0; rotate: -6deg; transform-origin: 50% 50%;
  pointer-events: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
  color: var(--stamp-ink, var(--fx-ink));
}
.fx-stamp > svg { display: block; width: 100%; height: auto; overflow: visible; }
.fx-stamp-host { position: relative; }
.fx-stamp-abs { position: absolute; z-index: 5; left: var(--sx, 50%); top: var(--sy, 50%); translate: -50% -50%; }
.fx-stamp-abs.fx-slam { translate: -50% -50%; }

/* ------------------------------------------------------------------ logo */
.fx-logo { display: inline-block; line-height: 0; color: var(--fx-ink); }
.fx-logo > svg { display: block; width: 100%; height: auto; overflow: visible; }
.fx-sway-g { transform-box: view-box; }

/* ------------------------------------------------------------------ receipt ticket (paper strip with a torn bottom edge) */
.fx-ticket { position: relative; background: var(--fx-card); color: var(--fx-ink); }
.fx-ticket-edge { display: block; width: 100%; height: 7px; color: var(--fx-card); }
.fx-ticket-line { overflow: hidden; }

/* ------------------------------------------------------------------ flip card (faces swap via data-face; ui/signage.js flipCard) */
.fx-card { display: inline-block; position: relative; }
.fx-card[data-face="down"] > .fx-face-up, .fx-card[data-face="up"] > .fx-face-down { display: none; }

/* ------------------------------------------------------------------ confetti canvas (ui/confetti.js; fixed, clipped, never takes a tap) */
.fx-confetti { position: fixed; left: 0; pointer-events: none; z-index: 60; }

/* ------------------------------------------------------------------ count digits */
.fx-count { font-variant-numeric: tabular-nums; display: inline-block; }

/* ------------------------------------------------------------------ podium (SPEC §10.2 Final) */
.fx-podium { display: flex; align-items: flex-end; justify-content: center; gap: 6px; width: 100%; max-width: 420px; margin: 0 auto; color: var(--fx-ink); }
.fx-pod { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; }
.fx-pod-who { display: flex; flex-wrap: wrap; gap: 6px 8px; justify-content: center; align-items: flex-end; padding: 0 2px 8px; max-width: 100%; }
.fx-pod-seat { display: flex; flex-direction: column; align-items: center; gap: 2px; min-width: 0; max-width: 92px; text-align: center; font: 700 14px/1.15 system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
.fx-pod-badge { width: 40px; height: 40px; border-radius: 50%; background: var(--fx-card); border: 2px solid var(--fx-ink); display: grid; place-items: center; font: 900 14px/1 "Arial Black", "Arial Bold", "Helvetica Neue", system-ui, sans-serif; letter-spacing: -.01em; }
.fx-pod-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 92px; }
.fx-pod-score { font-weight: 800; font-variant-numeric: tabular-nums; font-size: 16px; }
.fx-pod-block { width: 100%; background: var(--fx-ink); color: var(--fx-paper); border: 3px solid var(--fx-ink); border-radius: 4px 4px 0 0; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; padding-top: 6px; box-sizing: border-box; position: relative; }
.fx-pod-block::before, .fx-pod-block::after { content: ""; position: absolute; top: 5px; width: 5px; height: 5px; border-radius: 50%; background: var(--fx-paper); }
.fx-pod-block::before { left: 5px; } .fx-pod-block::after { right: 5px; }
.fx-pod-num { font: 900 34px/1 "Arial Black", "Arial Bold", "Helvetica Neue", system-ui, sans-serif; letter-spacing: -.01em; margin-top: 8px; }
.fx-pod-tie { font: 800 11px/1 system-ui, sans-serif; letter-spacing: .08em; text-transform: uppercase; margin-top: 4px; }
.fx-pod-rest { margin: 10px auto 0; max-width: 420px; padding: 0; list-style: none; font: 600 16px/1.35 system-ui, sans-serif; }

/* ------------------------------------------------------------------ stickers (Store Display reactions) */
.fx-stickers { position: relative; width: 100%; height: 100%; pointer-events: none; overflow: hidden; }
.fx-sticker { position: absolute; left: var(--sx); top: var(--sy); rotate: var(--sr, 0deg); line-height: 0; pointer-events: none; transform-origin: 50% 50%; }
.fx-sticker > svg { display: block; width: var(--sw, 150px); height: auto; overflow: visible; }

/* ------------------------------------------------------------------ paint cans, signage wrappers */
.fx-cans { display: flex; gap: 10px; justify-content: center; align-items: flex-end; color: var(--fx-ink); }
.fx-cans svg { display: block; overflow: visible; }
.fx-signage { display: inline-block; line-height: 0; max-width: 100%; }
.fx-signage > svg { display: block; width: 100%; height: auto; overflow: visible; }
.fx-signage.fx-mono { color: var(--fx-ink); }
