
:root {
  --tk-ease-nav: cubic-bezier(0.32, 0.72, 0, 1);
  --tk-ease-out: cubic-bezier(0.25, 0.46, 0.45, 0.94);

  --tk-spring: linear(0 0%, 0.0425 3.85%, 0.1453 7.69%, 0.2784 11.54%, 0.4201 15.38%,
    0.5561 19.23%, 0.6777 23.08%, 0.7806 26.92%, 0.8634 30.77%, 0.9269 34.62%,
    0.9731 38.46%, 1.0046 42.31%, 1.0243 46.15%, 1.0349 50%, 1.0388 53.85%,
    1.0383 57.69%, 1.0349 61.54%, 1.03 65.38%, 1.0245 69.23%, 1.0191 73.08%,
    1.0141 76.92%, 1.0098 80.77%, 1.0063 84.62%, 1.0036 88.46%, 1.0016 92.31%,
    1.0002 96.15%, 1 100%);

  --tk-pop: linear(0 0%, 0.0795 3.85%, 0.2682 7.69%, 0.5005 11.54%, 0.7268 15.38%,
    0.9156 19.23%, 1.0518 23.08%, 1.1333 26.92%, 1.1669 30.77%, 1.1642 34.62%,
    1.138 38.46%, 1.1003 42.31%, 1.0608 46.15%, 1.0258 50%, 0.9991 53.85%,
    0.9818 57.69%, 0.9731 61.54%, 0.9714 65.38%, 0.9745 69.23%, 0.9804 73.08%,
    0.9871 76.92%, 0.9934 80.77%, 0.9986 84.62%, 1.0021 88.46%, 1.0041 92.31%,
    1.0049 96.15%, 1 100%);

  --tk-nav: 460ms;
  --tk-sheet: 520ms;
  --tk-fade: 280ms;
  --tk-press: 110ms;
  --tk-release: 420ms;
  --tk-search: 420ms;
}

/* The materials — glass surfaces, the alert, the skeletons — live in
   assets/materials.css. None of them is on the path to the first frame, so
   app.js fetches that file once the first screen is up rather than making the
   browser wait for it before painting anything. */


.tk-screen[data-anim="out"], .tk-deskscreen[data-anim="out"] { pointer-events: none; }

/* Promoted for exactly as long as it is moving. `will-change` left on a resting
   element keeps a compositor layer — and its memory — alive for nothing; it is
   set by the same attribute that starts the animation and dies with it. */
.tk-screen[data-anim], .tk-deskscreen[data-anim], .tk-dim[data-anim] {
  will-change: transform, opacity;
}

.tk-screen[data-anim] { z-index: 1; }
.tk-screen[data-anim="in"][data-kind="push"],
.tk-screen[data-anim="in"][data-kind="sheet"],
.tk-screen[data-anim="in"][data-kind="fade"],
.tk-screen[data-anim="out"][data-kind="pop"],
.tk-screen[data-anim="out"][data-kind="unsheet"] { z-index: 3; }
.tk-dim { z-index: 2; }

.tk-screen[data-anim="in"][data-kind="push"] { animation: tk-push-in var(--tk-nav) var(--tk-ease-nav) both; }
.tk-screen[data-anim="out"][data-kind="push"] { animation: tk-push-out var(--tk-nav) var(--tk-ease-nav) both; }
.tk-screen[data-anim="in"][data-kind="pop"] { animation: tk-pop-in var(--tk-nav) var(--tk-ease-nav) both; }
.tk-screen[data-anim="out"][data-kind="pop"] { animation: tk-pop-out var(--tk-nav) var(--tk-ease-nav) both; }

.tk-screen[data-anim="in"][data-kind="sheet"] { animation: tk-sheet-in var(--tk-sheet) var(--tk-ease-nav) both; }
.tk-screen[data-anim="out"][data-kind="sheet"] { animation: tk-recede var(--tk-sheet) var(--tk-ease-nav) both; }
.tk-screen[data-anim="in"][data-kind="unsheet"] { animation: tk-return var(--tk-sheet) var(--tk-ease-nav) both; }
.tk-screen[data-anim="out"][data-kind="unsheet"] { animation: tk-sheet-out var(--tk-sheet) var(--tk-ease-nav) both; }

.tk-screen[data-anim="in"][data-kind="fade"],
.tk-deskscreen[data-anim="in"] { animation: tk-fade-in var(--tk-fade) var(--tk-ease-out) both; }
.tk-screen[data-anim="out"][data-kind="fade"],
.tk-deskscreen[data-anim="out"] { animation: tk-fade-out var(--tk-fade) var(--tk-ease-out) both; }

@keyframes tk-push-in { from { transform: translate3d(100%, 0, 0); } }
@keyframes tk-push-out { to { transform: translate3d(-26%, 0, 0); } }
@keyframes tk-pop-in { from { transform: translate3d(-26%, 0, 0); } }
@keyframes tk-pop-out { to { transform: translate3d(100%, 0, 0); } }

@keyframes tk-sheet-in { from { transform: translate3d(0, 100%, 0); } }
@keyframes tk-sheet-out { to { transform: translate3d(0, 100%, 0); } }
@keyframes tk-recede { to { transform: scale(.925); border-radius: 34px; } }
@keyframes tk-return { from { transform: scale(.925); border-radius: 34px; } }

@keyframes tk-fade-in { from { opacity: 0; transform: scale(1.014); } }
@keyframes tk-fade-out { to { opacity: 0; transform: scale(.99); } }

.tk-dim {
  position: absolute;
  inset: 0;
  background: #000;
  opacity: 0;
  pointer-events: none;
}
.tk-dim[data-anim="in"] { animation: tk-dim-in var(--tk-nav) var(--tk-ease-nav) both; }
.tk-dim[data-anim="out"] { animation: tk-dim-out var(--tk-nav) var(--tk-ease-nav) both; }
@keyframes tk-dim-in { from { opacity: 0; } to { opacity: .22; } }
@keyframes tk-dim-out { from { opacity: .22; } to { opacity: 0; } }

.tk[data-first] { animation: tk-app-in 520ms var(--tk-ease-out) both; }
@keyframes tk-app-in { from { opacity: 0; transform: scale(.988); } }

/* ------------------------------------------------------------ launch screen */

/* The mark from turn 20, held over the shell until the first screen is mounted
   and then handed over. It is one element with no picture to fetch: the mark is
   already in the document, so this costs a paint and nothing else. */
.tk-launch {
  position: absolute;
  inset: 0;
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg, #0B0B0B);
  pointer-events: none;
}
.tk-launch[hidden] { display: none; }
.tk-launch > svg { animation: tk-launch-mark 900ms var(--tk-spring) both; }
.tk-launch[data-anim="out"] { animation: tk-launch-out 340ms var(--tk-ease-out) both; }
@keyframes tk-launch-mark { from { opacity: 0; transform: scale(.86); } }
@keyframes tk-launch-out { to { opacity: 0; transform: scale(1.04); } }


.tk-tabbar[data-anim="in"] { animation: tk-bar-in var(--tk-nav) var(--tk-ease-nav) both; }
.tk-tabbar[data-anim="out"] { animation: tk-bar-out 260ms var(--tk-ease-out) both; }
@keyframes tk-bar-in { from { transform: translate3d(0, 130%, 0); opacity: 0; } }
@keyframes tk-bar-out { to { transform: translate3d(0, 130%, 0); opacity: 0; } }

.tk-tabbar a { position: relative; }
.tk-tabbar__pill { transition: transform var(--tk-release) var(--tk-spring); }
.tk-tabbar__pill { transform: translate3d(0, -50%, 0); }
.tk-tabbar[data-active="1"] .tk-tabbar__pill { transform: translate3d(100%, -50%, 0); }
.tk-tabbar[data-active="2"] .tk-tabbar__pill { transform: translate3d(200%, -50%, 0); }
.tk-tabbar[data-active="3"] .tk-tabbar__pill { transform: translate3d(300%, -50%, 0); }
.tk-tabbar[data-active="4"] .tk-tabbar__pill { transform: translate3d(400%, -50%, 0); }

.tk-tabbar {
  transition:
    transform var(--tk-nav) var(--tk-ease-nav),
    opacity var(--tk-nav) var(--tk-ease-nav),
    background-color var(--tk-fade) var(--tk-ease-out),
    box-shadow var(--tk-fade) var(--tk-ease-out);
}
.tk-tabbar[data-min] { transform: translate3d(0, 46%, 0) scale(.88); opacity: .82; }

.tk-tabbar a { transition: color var(--tk-fade) var(--tk-ease-out); }
.tk-tabbar a svg { transition: transform var(--tk-release) var(--tk-spring); }
.tk-tabbar a:active svg { transform: scale(.84); transition-duration: var(--tk-press); }
.tk-tabbar a[data-anim="select"] svg { animation: tk-tab-pop 460ms var(--tk-pop) both; }
@keyframes tk-tab-pop { from { transform: scale(.78); } }


/* Jede Fläche, die etwas tut, antwortet dem Finger — und zwar bevor sie
   antwortet, was sie tut. Die Liste ist absichtlich vollständig statt
   beispielhaft: `ticker-web.test.mjs` zählt die Bedienfamilien in allen
   Screens und schlägt fehl, sobald eine hier fehlt. Eine Reihe ohne Antwort
   fühlt sich kaputt an, lange bevor jemand merkt, dass sie nur nicht gedrückt
   aussieht. */
[data-nav],
[data-toggle] > [data-when],
[data-switch],
[data-hold] {
  transition: transform var(--tk-release) var(--tk-spring);
}
[data-nav]:active,
[data-toggle]:active > [data-when],
[data-switch]:active,
[data-hold][data-holding] {
  transform: scale(.965);
  transition-duration: var(--tk-press);
  transition-timing-function: var(--tk-ease-nav);
}
[data-nav]:active:has(> svg), [data-switch]:active { transform: scale(.9); }

/* The tab bar answers the finger before it answers the route: the symbol dips
   under the touch and springs back, whether or not the tab changes. */
.tk-tabbar a { transition: transform var(--tk-release) var(--tk-spring); }
.tk-tabbar a:active {
  transform: scale(.88);
  transition-duration: var(--tk-press);
  transition-timing-function: var(--tk-ease-nav);
}


[data-toggle][data-anim="select"] > [data-when] { animation: tk-select 480ms var(--tk-pop) both; }
@keyframes tk-select { from { transform: scale(.93); } }


[data-hold] { --tk-hold: 1100ms; cursor: pointer; overflow: hidden; }
[data-hold] > span { position: relative; z-index: 1; }
[data-hold] > div { z-index: 1; }

[data-hold]::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(11, 11, 11, .17);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 240ms var(--tk-ease-out);
  pointer-events: none;
}
[data-hold][data-holding]::after {
  transform: scaleX(1);
  transition: transform var(--tk-hold) linear;
}
[data-hold][data-filled]::after { transform: scaleX(1); transition: none; }

[data-hold]:focus-visible { outline: 2px solid var(--tx); outline-offset: 3px; }


[data-switch] { transition: background-color var(--tk-fade) var(--tk-ease-out), transform var(--tk-release) var(--tk-spring); }
[data-switch] > div { transition: transform var(--tk-release) var(--tk-spring); }
[data-switch]:not([data-on]) > div { transform: translate3d(-20px, 0, 0); }


.tk-island {
  position: absolute;
  top: 11px;
  left: 50%;
  z-index: 70;
  width: 104px;
  height: 30px;
  border-radius: 16px;
  background: #000;
  box-shadow: 0 0 0 1px #1E1E1E;
  color: #F5F5F3;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  transform: translateX(-50%);
  transition:
    width var(--tk-release) var(--tk-spring),
    height var(--tk-release) var(--tk-spring),
    border-radius var(--tk-release) var(--tk-spring);
}

.tk-island[data-state="compact"] { width: 188px; height: 38px; border-radius: 19px; }
.tk-island[data-state="full"] { width: 340px; height: 86px; border-radius: 30px; }
.tk-island[data-state="idle"] { cursor: default; }
.tk-island:not([data-state="idle"]) { cursor: pointer; box-shadow: 0 0 0 1px #1E1E1E, 0 18px 40px -14px rgba(0, 0, 0, .8); }

.tk-island__compact,
.tk-island__full {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 180ms var(--tk-ease-out), transform 320ms var(--tk-ease-nav);
}

.tk-island__compact { gap: 9px; padding: 0 14px; justify-content: space-between; transform: scale(.9); }
.tk-island__full { gap: 12px; padding: 0 16px; transform: scale(.92); }

.tk-island[data-state="compact"] .tk-island__compact,
.tk-island[data-state="full"] .tk-island__full { opacity: 1; transform: scale(1); }

.tk-island__dot { width: 9px; height: 9px; border-radius: 50%; background: #CBF24C; flex: none; }
.tk-island__short {
  font: 500 13px/1 'Outfit', system-ui, sans-serif;
  color: #F5F5F3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tk-island__mark {
  width: 36px;
  height: 36px;
  flex: none;
  border-radius: 11px;
  background: #CBF24C;
  color: #0B0B0B;
  display: flex;
  align-items: center;
  justify-content: center;
}
.tk-island__text { display: flex; flex-direction: column; gap: 3px; flex: 1; min-width: 0; }
.tk-island__title { font: 600 14.5px/1.2 'Outfit', system-ui, sans-serif; color: #F5F5F3; }
.tk-island__sub {
  font: 400 12.5px/1.3 'Outfit', system-ui, sans-serif;
  color: #8A8A90;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tk-island__ring { flex: none; transform: rotate(-90deg); }
.tk-island__track { stroke: #252525; }
.tk-island__value { stroke: #CBF24C; transition: stroke-dashoffset 320ms linear; }
.tk-island:not([data-progress]) .tk-island__ring { display: none; }

.tk-island__live {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

@media (max-width: 1099px), (max-height: 900px) {
  .tk-island { top: max(11px, env(safe-area-inset-top, 0px)); }
  .tk-island[data-state="idle"] { opacity: 0; pointer-events: none; }
}


:root[data-theme-changing] .tk-stage *,
:root[data-theme-changing] .tk-desk *,
:root[data-theme-changing] .tk-stage,
:root[data-theme-changing] .tk {
  transition: background-color 260ms var(--tk-ease-out), color 260ms var(--tk-ease-out),
    border-color 260ms var(--tk-ease-out), fill 260ms var(--tk-ease-out),
    stroke 260ms var(--tk-ease-out);
}


/* ----------------------------------------------------- pull to refresh */

/* While the finger is down the list follows it exactly, so there is no
   transition; on release the spring brings it home. */
[data-screen-label] { transition: transform var(--tk-release) var(--tk-spring); }
[data-screen-label][data-pulling] { transition: none; }

/* ------------------------------------------------------------- loading */

/* A route whose screen still has to be fetched says so with the one line iOS
   uses: a hairline that sweeps under the status bar. It only appears once the
   wait is long enough to notice, so a cached route shows nothing at all. */
.tk-stage::after {
  content: '';
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--acc, #CBF24C), transparent);
  transform: translate3d(-100%, 0, 0);
  opacity: 0;
  pointer-events: none;
  z-index: 70;
}
.tk[aria-busy="true"] .tk-stage::after {
  opacity: 1;
  animation: tk-sweep 1100ms var(--tk-ease-out) 180ms infinite;
}
@keyframes tk-sweep {
  from { transform: translate3d(-100%, 0, 0); }
  to { transform: translate3d(100%, 0, 0); }
}

/* ------------------------------------------------------------- live numbers */

/* A number that the backend owns says so quietly: while a request is in flight
   it breathes, and when it lands it settles rather than snapping. Values the
   design drew are untouched when there is no backend, so none of this shows. */
.tk-live { transition: color var(--tk-fade) var(--tk-ease-out); }
.tk-live--busy { animation: tk-live-breathe 1200ms var(--tk-ease-out) infinite; }
@keyframes tk-live-breathe { 50% { opacity: .55; } }

:root[data-live="on"] .tk-live[data-dir="up"] { color: var(--up, #CBF24C); }
:root[data-live="on"] .tk-live[data-dir="down"] { color: var(--dn, #FF6B5A); }

:root[data-motion="off"] *,
:root[data-motion="off"] *::before,
:root[data-motion="off"] *::after {
  animation: none !important;
  transition: none !important;
}

/* Reduced motion keeps every state and drops every journey between them: the
   list still fills, the alert still appears, nothing travels or overshoots. */
@media (prefers-reduced-motion: reduce) {
  .tk-launch > svg, .tk-launch[data-anim="out"] { animation: none; }
  .tk-screen[data-anim="in"], .tk-deskscreen[data-anim="in"] { animation: tk-fade-in 160ms linear both; }
  .tk-screen[data-anim="out"], .tk-deskscreen[data-anim="out"] { animation: none; opacity: 0; }
  .tk-dim[data-anim], .tk-tabbar[data-anim], .tk[data-first] { animation: none; }
  [data-toggle][data-anim="select"] > [data-when], .tk-tabbar a[data-anim="select"] svg { animation: none; }
  [data-nav]:active, [data-toggle]:active > [data-when], [data-switch]:active { transform: none; }
  .tk-island { transition-duration: 1ms; }
}

:root[data-motion="reduce"] .tk-screen[data-anim="in"],
:root[data-motion="reduce"] .tk-deskscreen[data-anim="in"] { animation: tk-fade-in 160ms linear both; }
:root[data-motion="reduce"] .tk-screen[data-anim="out"],
:root[data-motion="reduce"] .tk-deskscreen[data-anim="out"] { animation: none; opacity: 0; }
:root[data-motion="reduce"] .tk-dim[data-anim],
:root[data-motion="reduce"] .tk-tabbar[data-anim],
:root[data-motion="reduce"] .tk[data-first] { animation: none; }
:root[data-motion="reduce"] [data-toggle][data-anim="select"] > [data-when],
:root[data-motion="reduce"] .tk-tabbar a[data-anim="select"] svg { animation: none; }
:root[data-motion="reduce"] [data-nav]:active,
:root[data-motion="reduce"] [data-toggle]:active > [data-when],
:root[data-motion="reduce"] [data-switch]:active { transform: none; }
:root[data-motion="reduce"] .tk-island { transition-duration: 1ms; }
:root[data-motion="reduce"] .tk-tabbar__pill { transition-duration: 1ms; }
:root[data-motion="reduce"] .tk-launch > svg,
:root[data-motion="reduce"] .tk-launch[data-anim="out"] { animation: none; }
