/* OneOneTyping v6 — motion.
 *
 * One vocabulary of movement for the whole site, modelled on how iOS moves:
 * nothing slides at a constant speed, everything is a spring. Things you
 * press sink quickly and come back with a little bounce; things that appear
 * rise into place and settle; things that change position glide there.
 *
 *   --spring-snappy   small, fast feedback (presses, toggles)      ~0.43 s
 *   --spring-smooth   things moving to a new place (indicators)    ~0.62 s
 *   --spring-bouncy   playful arrivals (menus, badges, cards)      ~0.80 s
 *   --spring-gentle   big surfaces (pages, sheets)                 ~0.85 s
 *   --spring-wobbly   celebration only                             ~1.19 s
 *
 * The curves are real damped springs sampled into linear() easings by
 * tools/motion/springs.cjs. Everything here switches off for people who ask
 * their system for reduced motion.
 */

:root {
  --spring-snappy: linear(0, 0.0355, 0.1011, 0.2003, 0.2939, 0.4038, 0.4937, 0.5899, 0.6633, 0.7376, 0.7917, 0.8375, 0.8812, 0.9114, 0.9392, 0.9577, 0.9741, 0.9845, 0.9933, 0.9986, 1.0022, 1.0048, 1.006, 1.0067, 1.0067, 1.0064, 1.0059, 1.0052, 1.0045, 1.0038, 1.0032, 1.0027, 1.0021, 1.0017, 1.0013, 1.001, 1.0007, 1.0005, 1.0004, 1.0002, 1);
  --dur-snappy: 430ms;
  --spring-smooth: linear(0, 0.0338, 0.0996, 0.1823, 0.2714, 0.3699, 0.4537, 0.5306, 0.5998, 0.6672, 0.7197, 0.765, 0.8038, 0.84, 0.8673, 0.8903, 0.9094, 0.927, 0.9401, 0.9508, 0.9597, 0.9678, 0.9737, 0.9786, 0.9825, 0.9861, 0.9887, 0.9908, 0.9925, 0.9941, 0.9952, 0.9961, 0.9969, 0.9975, 0.998, 0.9984, 0.9987, 0.999, 0.9992, 0.9993, 1);
  --dur-smooth: 617ms;
  --spring-bouncy: linear(0, 0.0666, 0.2066, 0.3838, 0.5691, 0.7411, 0.8867, 0.9991, 1.0772, 1.1236, 1.1433, 1.1425, 1.1275, 1.1043, 1.0776, 1.0512, 1.0278, 1.0087, 0.9946, 0.9853, 0.9804, 0.979, 0.9803, 0.9832, 0.9869, 0.9908, 0.9944, 0.9975, 0.9999, 1.0016, 1.0026, 1.003, 1.003, 1.0027, 1.0022, 1.0017, 1.0011, 1.0006, 1.0002, 0.9999, 1);
  --dur-bouncy: 803ms;
  --spring-gentle: linear(0, 0.0301, 0.0981, 0.1847, 0.2706, 0.3631, 0.4504, 0.5302, 0.5963, 0.6595, 0.7143, 0.7614, 0.7985, 0.8328, 0.8616, 0.8857, 0.9044, 0.9213, 0.9354, 0.947, 0.9559, 0.9639, 0.9704, 0.9758, 0.9799, 0.9836, 0.9866, 0.9891, 0.991, 0.9926, 0.994, 0.9951, 0.996, 0.9967, 0.9973, 0.9978, 0.9982, 0.9985, 0.9988, 0.999, 1);
  --dur-gentle: 850ms;
  --spring-wobbly: linear(0, 0.092, 0.3056, 0.5687, 0.8227, 1.0285, 1.1668, 1.2334, 1.2452, 1.213, 1.1555, 1.0898, 1.0294, 0.9825, 0.954, 0.9403, 0.9406, 0.9506, 0.9657, 0.9818, 0.9954, 1.0061, 1.0126, 1.015, 1.0142, 1.0113, 1.0074, 1.0037, 1.0004, 0.998, 0.9966, 0.9963, 0.9966, 0.9974, 0.9984, 0.9993, 1.0001, 1.0006, 1.0009, 1.0009, 1);
  --dur-wobbly: 1190ms;
  --press-scale: 0.955;
}
@supports not (transition-timing-function: linear(0, 1)) {
  :root {
    --spring-snappy: cubic-bezier(0.25, 1, 0.5, 1);
    --spring-smooth: cubic-bezier(0.22, 1, 0.36, 1);
    --spring-bouncy: cubic-bezier(0.34, 1.56, 0.64, 1);
    --spring-gentle: cubic-bezier(0.22, 1, 0.36, 1);
    --spring-wobbly: cubic-bezier(0.34, 1.8, 0.64, 1);
  }
}

/* ------------------------------------------------ page to page
   Navigation cross-fades with the new page rising a few pixels into place;
   the nav bar is its own layer, so it stays put while the content moves. */
@view-transition { navigation: auto; }
#nav { view-transition-name: site-nav; }
::view-transition-old(root) { animation: vt-out 0.18s cubic-bezier(0.4, 0, 1, 1) both; }
::view-transition-new(root) { animation: vt-in var(--dur-smooth) var(--spring-smooth) both; }
::view-transition-group(site-nav) { animation-duration: 0s; }
@keyframes vt-out { to { opacity: 0; transform: scale(0.992); } }
@keyframes vt-in { from { opacity: 0; transform: translateY(10px); } }

/* ------------------------------------------------ press & hover
   Press: sink fast. Release: spring back with a little overshoot. */
.btn, .nav-icon-btn, .nav-links a, .lb-boards button, .sfx-chip, .shot-cap, .shot-sound,
.cc-card, .game-card, .mb-benefit, .guest-card .btn, .set-switch, .tt-seg button, .lb-seg button,
.set-seg button, .al-chips button, .ct-item, .pf-tabs button, .dd-legend button {
  transition-property: transform, background-color, color, box-shadow, border-color, opacity;
  transition-duration: var(--dur-bouncy), 0.18s, 0.18s, 0.25s, 0.18s, 0.18s;
  transition-timing-function: var(--spring-bouncy), ease, ease, ease, ease, ease;
}
.btn:active, .nav-icon-btn:active, .lb-boards button:active, .sfx-chip:active, .shot-sound:active,
.set-switch:active, .tt-seg button:active, .lb-seg button:active, .set-seg button:active,
.al-chips button:active, .ct-item:active, .pf-tabs button:active, .dd-legend button:active, .shot-cap:active {
  transform: scale(var(--press-scale));
  transition-duration: 0.08s;
  transition-timing-function: cubic-bezier(0.3, 0, 0.6, 1);
}
/* clickable cards lift under the pointer, and press down when clicked */
@media (hover: hover) {
  .cc-card:hover, .game-card:hover, .mb-benefit:hover { transform: translateY(-4px); }
  .lb-boards button:hover { transform: translateY(-2px); }
}
.cc-card:active, .game-card:active { transform: translateY(-1px) scale(0.985); transition-duration: 0.1s; }

/* switches: the knob springs across */
.set-switch i { transition: transform var(--dur-bouncy) var(--spring-bouncy), background-color 0.2s; }

/* ------------------------------------------------ segmented controls
   motion.js puts one ink pill behind the selected option and glides it to
   the next one (like iOS's segmented control) instead of repainting. */
.has-seg-ink { position: relative; isolation: isolate; }
.seg-ink {
  position: absolute;
  z-index: -1;
  top: 0; left: 0;
  pointer-events: none;
  transition: transform var(--dur-smooth) var(--spring-smooth), width var(--dur-smooth) var(--spring-smooth),
    height var(--dur-smooth) var(--spring-smooth);
}
.has-seg-ink > .is-inked { background: transparent !important; box-shadow: none !important; border-color: transparent !important; }

/* ------------------------------------------------ menus, sheets, toasts */
.nav-menu:not([hidden]) { animation: pop-in var(--dur-bouncy) var(--spring-bouncy) both; transform-origin: top right; }
@keyframes pop-in { from { opacity: 0; transform: scale(0.9) translateY(-6px); } }
.cert-modal .cert-box, .ad-modal { transition-timing-function: var(--spring-bouncy) !important; transition-duration: var(--dur-bouncy) !important; }
.ad-modal { animation: sheet-in var(--dur-bouncy) var(--spring-bouncy) both; }
.ad-modal-backdrop { animation: fade-in 0.2s ease both; }
@keyframes sheet-in { from { opacity: 0; transform: translateY(18px) scale(0.96); } }
@keyframes fade-in { from { opacity: 0; } }
.guest-card { transition-timing-function: ease, var(--spring-bouncy) !important; transition-duration: 0.28s, var(--dur-bouncy) !important; }
details[open] > :not(summary) { animation: unfold var(--dur-smooth) var(--spring-smooth) both; }
@keyframes unfold { from { opacity: 0; transform: translateY(-6px); } }

/* ------------------------------------------------ arrivals
   Blocks below the fold rise into place as they scroll in, a few at a time. */
[data-reveal] { opacity: 0; transform: translateY(18px) scale(0.985); }
[data-reveal].is-revealed {
  opacity: 1; transform: none;
  transition: opacity 0.45s ease, transform var(--dur-gentle) var(--spring-gentle);
  transition-delay: var(--reveal-delay, 0s);
}

/* result stars, badges and medals land with a bounce */
.rs-stars svg.is-on { animation: star-pop var(--dur-wobbly) var(--spring-wobbly) both; }
.rs-stars svg.is-on:nth-child(2) { animation-delay: 0.08s; }
.rs-stars svg.is-on:nth-child(3) { animation-delay: 0.16s; }
.rs-stars svg.is-on:nth-child(4) { animation-delay: 0.24s; }
.rs-stars svg.is-on:nth-child(5) { animation-delay: 0.32s; }
@keyframes star-pop { from { transform: scale(0.2) rotate(-40deg); opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
  [data-reveal] { opacity: 1; transform: none; }
  .seg-ink, .set-switch i { transition: none; }
  .nav-menu:not([hidden]), .ad-modal, .rs-stars svg.is-on, details[open] > :not(summary) { animation: none; }
  .btn:active, .nav-icon-btn:active { transform: none; }
}
