/* Native feel and motion for every app page (injected into each page's <head> by scripts/build-assets.mjs).
   Native feel: no scrollbars, no rubber-band or pull-to-refresh, no zoom, no text selection or callouts on the chrome,
   no grey tap flash. Motion: the tokens from the motion board (design/app-build/motion.py), press feedback on everything
   you can tap, and a cross-page transition. Sheet, toast and entrance motion run from native.js; the table's from ink-motion.js.
   Transform and opacity only. Under prefers-reduced-motion it all becomes a 150 ms crossfade (at the end). */
:root {
  /* springs as linear(), from the motion board's token sheet */
  --m-press: linear(0,.081,.242,.411,.56,.68,.772,.84,.889,.924,.948,.965,.976,.984,.989,.993,.995,.997,1);
  --m-smooth: linear(0,.081,.242,.411,.56,.68,.772,.84,.889,.924,.948,.965,.976,.984,.989,.993,.995,.997,1);
  --m-glide: linear(0,.072,.224,.394,.551,.682,.784,.86,.913,.949,.973,.987,.996,1,1.002,1.003,1.003,1.002,1);
  --m-snap: linear(0,.071,.229,.415,.592,.742,.857,.939,.992,1.022,1.035,1.038,1.035,1.029,1.022,1.015,1.009,1.005,1);
  --m-exit: cubic-bezier(.4,0,1,1);
  --m-count: cubic-bezier(.16,1,.3,1);
  --m-press-ms: 260ms; --m-smooth-ms: 520ms; --m-glide-ms: 600ms; --m-snap-ms: 500ms; --m-exit-ms: 160ms; --m-count-ms: 900ms;
}

/* ---- native feel */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; overscroll-behavior: none; scrollbar-width: none; }
body { overscroll-behavior: none; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; touch-action: manipulation; }
html::-webkit-scrollbar, body::-webkit-scrollbar, *::-webkit-scrollbar { display: none; width: 0; height: 0; }
* { scrollbar-width: none; -webkit-tap-highlight-color: transparent; }
/* a sheet's own scroll stops at its edge instead of dragging the page under it */
.k-sheet, dialog { overscroll-behavior: contain; }
/* chrome isn't text: no selection, no long-press callout, no image drag. Fields and anything marked selectable keep it. */
body { -webkit-user-select: none; user-select: none; cursor: default; }
input, textarea, [contenteditable], .selectable, .selectable * { -webkit-user-select: text; user-select: text; -webkit-touch-callout: default; }
img, svg { -webkit-user-drag: none; user-drag: none; }
a, button, [role="button"], label, summary, .k-tile, .k-row, .k-choice { cursor: pointer; }
/* no blue focus ring on tap; keyboard focus keeps the kit's own ring */
:focus:not(:focus-visible) { outline: none; }

/* ---- press: a pressed thing dips at once and springs back on release (press token). Nothing that sits on the table. */
.k-btn, .k-ibtn, .k-tile, .k-choice, .k-row[href], a.k-row, button.k-row, .k-seg > *, .k-tabs > *, .tb {
  transition: transform var(--m-press-ms) var(--m-press), opacity var(--m-press-ms) var(--m-press);
}
.k-btn:active, .k-ibtn:active, .k-seg > *:active, .k-tabs > *:active, .tb:active {
  transform: scale(.97); transition-duration: 0ms;
}
.k-choice:active { transform: scale(.985); transition-duration: 0ms; }
/* level up (LvMotionSpec, Press): tiles .97 and pills .96 on touch down, back on release */
.k-tile:active { transform: scale(.97); transition-duration: 0ms; }
a.pill, button.pill { transition: transform var(--m-press-ms) var(--m-press); }
a.pill:active, button.pill:active { transform: scale(.96); transition-duration: 0ms; }
a.k-row:active, .k-row[href]:active, button.k-row:active { opacity: .6; transition-duration: 0ms; }
.k-btn.off:active, .k-btn[disabled]:active { transform: none; }
/* m45: a link that loads another page stays pressed until that page comes (native.js .nv-going), so the click answers at once */
.k-tile.nv-going, .k-btn.nv-going, .k-ibtn.nv-going, a.pill.nv-going { transform: scale(.97); transition-duration: 0ms; }
a.k-row.nv-going, .k-row[href].nv-going { opacity: .6; transition-duration: 0ms; }
/* legacy .button keeps its own press (components.css) */

/* ---- toggles (MotionSpec: the press token; transform and opacity only, a colour change is a crossfade between two layers).
   The kit's switch (kit.css, generated) moves its knob by left and swaps colours at once; here the knob slides by translateX
   and the lit track and knob fade in as layers over the unlit ones. At rest it draws exactly as the kit does. */
.k-switch>i { transition: transform var(--m-press-ms) var(--m-press); }
.k-switch.on>i { left: 2px; transform: translateX(20px); background: var(--knob); }
.k-switch.on { background: rgba(var(--fg-rgb), .16); }
.k-switch::before, .k-switch>i::after { content: ''; position: absolute; inset: 0; border-radius: inherit; opacity: 0; pointer-events: none;
  transition: opacity var(--m-press-ms) var(--m-press); }
.k-switch::before { background: var(--ivory); }
.k-switch>i::after { background: var(--on-ivory); }
.k-switch.on::before, .k-switch.on>i::after { opacity: 1; }
/* The kit's knob drops its shadow when on (box-shadow: none), which popped as the knob set off. The shadow is a layer of its
   own here, the kit's off shadow exactly, and fades out on the press spring as the knob slides (V1 38.94). */
.k-switch>i, .k-switch.on>i { box-shadow: none; }
.k-switch>i::before { content: ''; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  box-shadow: 0 2px 6px rgba(var(--shade-rgb), calc(.35 * var(--shade-a))), 0 0 0 .5px rgba(var(--shade-rgb), calc(.15 * var(--shade-a)));
  transition: opacity var(--m-press-ms) var(--m-press); }
.k-switch.on>i::before { opacity: 0; }

/* ---- going between pages (LvMotionSpec "Open Rank, a table or a setting"): a page you open slides in from the right over the
   one you left, which eases a little to the left and stays whole underneath; Back slides it away to the right. Neither page
   ever fades, so there is no dark frame between them. native.js types each transition: push (a link), back (Back or a swipe
   back) or none of them (a reload or a replace), which keeps the plain rise. Table opens keep their own (html.k-opening,
   table-open.js). The tab bar stays put. */
@view-transition { navigation: auto; }
.k-tabs { view-transition-name: suited-tabs; }
/* a view-transition name must be unique on the page, or the browser drops the whole transition (Motion M1). The tabs shell
   (Home, Stats, Profile) draws a bar in each of its three panes as well as its own: only the shell's own bar keeps the name. */
.sh-pane .k-tabs { view-transition-name: none; }
::view-transition-old(root) { animation: nv-out var(--m-exit-ms) var(--m-exit) both; }
::view-transition-new(root) { animation: nv-in var(--m-smooth-ms) var(--m-smooth) both; }
::view-transition-group(suited-tabs) { animation-duration: 0ms; }
html:active-view-transition-type(push):not(.k-opening)::view-transition-old(root) { animation: nv-park var(--m-smooth-ms) var(--m-smooth) both; }
html:active-view-transition-type(push):not(.k-opening)::view-transition-new(root) { animation: nv-push var(--m-smooth-ms) var(--m-smooth) both; }
html:active-view-transition-type(back):not(.k-opening)::view-transition-old(root) { z-index: 1; animation: nv-push var(--m-smooth-ms) var(--m-smooth) reverse both; }
html:active-view-transition-type(back):not(.k-opening)::view-transition-new(root) { animation: nv-park var(--m-smooth-ms) var(--m-smooth) reverse both; }
@keyframes nv-out { to { opacity: 0; } }
@keyframes nv-in { from { opacity: 0; transform: translateY(12px); } }
@keyframes nv-push { from { transform: translateX(100%); } }
@keyframes nv-park { to { transform: translateX(-24%); } }

/* ---- numbers roll in per-digit columns (digits.js): a window one line tall over a column that slides, faded at its edges */
.digit-window { display: inline-block; height: 1.2em; height: 1lh; overflow: hidden; vertical-align: top;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 22%, #000 78%, transparent 100%); mask-image: linear-gradient(180deg, transparent 0, #000 22%, #000 78%, transparent 100%); }
.digit-strip { display: flex; flex-direction: column; line-height: inherit; will-change: transform; }
.number-accessible { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* ---- the live dot breathes (Home's "Live now") */
.hero-t .dot, .k-live .dot, .live-dot { animation: nv-live 2s ease-in-out infinite; }
@keyframes nv-live { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
/* a live table's tag breathes slowly, every 2.4 s, as long as the game runs (LvMotionSpec, Live) */
.k-tag.now::before { animation: nv-live 2.4s ease-in-out infinite; }

/* a sheet's grab bar and head follow your finger down (native.js), so the page doesn't take the gesture as a scroll */
.k-sheet .k-grab, .k-sheet .k-sheet-hd, .k-sheet .lv-mis-hd { touch-action: none; }

/* ---- level-up moments (native.js): the light that crosses the felt and your card once, in a clipped layer of its own */
.nv-sheen { position: absolute; inset: 0; overflow: hidden; border-radius: inherit; pointer-events: none; z-index: 3; }
.nv-sheen > i { position: absolute; top: -20%; bottom: -20%; left: 0; width: 40%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.14), transparent); }
/* Scroll: pictures in tiles drift a little slower than their tiles, so the page has depth */
@supports (animation-timeline: view()) {
  .k-home .k-tile .vi > * { animation: nv-drift linear both; animation-timeline: view(); animation-range: cover; }
}
@keyframes nv-drift { from { transform: translateY(-6px); } to { transform: translateY(6px); } }

/* ---- motion used by native.js and ink-motion.js */
@keyframes nv-rise { from { opacity: 0; transform: translateY(12px); } }
@keyframes nv-sheet { from { transform: translateY(100%); } }
@keyframes nv-fade { from { opacity: 0; } }
@keyframes nv-toast { from { opacity: 0; transform: translateY(16px) scale(.98); } }

/* ---- Reduce Motion (Motion spec): every motion becomes a 150 ms crossfade. Nothing travels, turns or grows: transitions keep
   only opacity and colour, at 150 ms, and keyframe motion lands on its last frame, except the ones that only fade in, which
   fade in 150 ms. Pages change with a crossfade. A press still answers. (.k-app * matches kit-app.css's own rule.) */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after, .k-app *, .k-app *::before, .k-app *::after {
    transition-property: opacity, color, background-color, border-color, fill, stroke !important;
    transition-duration: 150ms !important; transition-delay: 0ms !important; transition-timing-function: linear !important;
    animation-duration: 0ms !important; animation-delay: 0ms !important; animation-iteration-count: 1 !important;
  }
  .k-tag.now::before, .k-home .k-tile .vi > * { animation: none !important; }
  .nv-sheen { display: none; }
  /* nothing shrinks: a link on its way to its page dims instead */
  .k-tile.nv-going, .k-btn.nv-going, .k-ibtn.nv-going, a.pill.nv-going { transform: none; opacity: .6; }
  .k-notify, .k-install, .k-install-tip, .k-net-toast, .k-pro .k-sheet, .k-pro .k-veil { animation: nv-fade 150ms linear both !important; }
  ::view-transition-old(root) { animation: nv-out 150ms linear both; }
  ::view-transition-new(root) { animation: nv-fade 150ms linear both; }
  html:active-view-transition-type(push, back)::view-transition-old(root) { z-index: auto; animation: nv-out 150ms linear both; }
  html:active-view-transition-type(push, back)::view-transition-new(root) { animation: nv-fade 150ms linear both; }
}

/* Can't reach sign-in (J9; auth.js unreachable()): on any page that shows auth.js's status, the offline mark and a short line
   with Try again beside it, never an exception's words. */
[data-auth-status][data-auth-state]{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:8px 12px;color:var(--text-2)}
[data-auth-status] .auth-ind{display:inline-flex;align-items:center;gap:4px;white-space:nowrap}
[data-auth-status] .auth-retry{flex:none}
