:root {
  --bg: #000000;
  --panel: #1a1a1a;
  --text: #f5e9d3;
  --muted: #9ca3af;
  --accent: #d1d5db;
  --border: #3a3a3a;
  --lane: #3d2856;
  --lane-alt: #362248;
  --track-gap: 0px;
  --horse-height: 60px;
  --sprite-scale: 2;
  --label-col: 124px;
  --label-mid: 23%;  /* vertical centre of the name-tag — aligned with the horse's middle */
  --ticker-h: 2.6rem;
  --pixel-font: "VT323", "Courier New", ui-monospace, monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--pixel-font);
  font-size: 20px;
  line-height: 1.25;
  min-height: 100vh;
  image-rendering: pixelated;
  -webkit-font-smoothing: none;
  -moz-osx-font-smoothing: grayscale;
}

#app { min-height: 100vh; display: flex; flex-direction: column; }

/* ── Home ──────────────────────────────────────────── */

.home {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 32px;
  padding: 32px;
  text-align: center;
}
.home h1 {
  font-size: clamp(2.5rem, 8vw, 4rem);
  color: var(--accent);
  letter-spacing: 0.08em;
  margin: 0;
  display: flex;
  align-items: center;
  gap: 0.4em;
}
.horse-face {
  height: 1em;
  width: auto;
  image-rendering: pixelated;
  shape-rendering: crispEdges;
  flex-shrink: 0;
}
.horse-face-flip {
  display: inline-flex;
  transform: scaleX(-1);
}
.home p { color: var(--muted); margin: 0; max-width: 36ch; }
.home form { display: flex; gap: 8px; }
.home input {
  background: var(--panel);
  color: var(--text);
  border: 2px solid var(--border);
  padding: 12px 16px;
  font: inherit;
  font-size: 1.25rem;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  width: 180px;
}
.home input:focus { outline: none; border-color: var(--accent); }
.home button {
  background: var(--accent);
  color: var(--bg);
  border: none;
  padding: 12px 24px;
  font: inherit;
  font-size: 1rem;
  font-weight: bold;
  cursor: pointer;
}
.home button:hover { filter: brightness(1.1); }

.btn {
  background: var(--accent);
  color: var(--bg);
  border: none;
  padding: 8px 14px;
  font: inherit;
  font-size: 0.9rem;
  font-weight: bold;
  letter-spacing: 0.03em;
  cursor: pointer;
  border-radius: 3px;
}
.btn:hover { filter: brightness(1.1); }

.home-divider {
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.15em;
  font-size: 0.75rem;
  margin: -8px 0 -8px;
}
.install-line.terminal {
  margin-top: auto;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  background: #050a05;
  border: 2px solid #1f5a1f;
  box-shadow: 0 0 12px rgba(74, 222, 128, 0.18) inset, 0 0 0 1px #000;
  color: #4ade80;
  font-size: 1rem;
  letter-spacing: 0.05em;
  text-shadow: 0 0 6px rgba(74, 222, 128, 0.55);
}
.terminal-prompt { color: #4ade80; opacity: 0.7; }
.terminal-cmd { color: #4ade80; }
.terminal-cursor {
  display: inline-block;
  color: #4ade80;
  animation: terminal-blink 1s steps(2, start) infinite;
}
@keyframes terminal-blink {
  to { visibility: hidden; }
}

/* ── Org view ──────────────────────────────────────── */

.org {
  flex: 1;
  display: flex;
  flex-direction: column;
}
.org-header {
  padding: 16px 24px;
  border-bottom: 2px solid var(--panel);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 16px;
}
.org-header h1 {
  margin: 0;
  color: var(--accent);
  font-size: 1.5rem;
  letter-spacing: 0.05em;
  display: flex;
  align-items: center;
  gap: 0.4em;
}
.org-body {
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 32px;
}
.org-status { color: var(--muted); }
/* Live section pins to the viewport top; the bg + padding mask the rows
   scrolling beneath it (negative margins keep the resting layout unchanged). */
.org-section-live {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--bg);
  /* mask the full 32px org-body gap below so scrolling rows don't peek through */
  padding: 12px 0 32px;
  margin: -12px 0 -32px;
}
.org-section-live:not(:last-child) { border-bottom: 2px solid var(--panel); }
.org-section h2 {
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: 1rem;
  margin: 0 0 12px;
}
.race-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.race-row a {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
  padding: 12px 16px;
  background: var(--panel);
  border: 2px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  text-decoration: none;
}
.race-row a:hover { border-color: var(--accent); }
.race-row-sprite {
  flex: 0 0 auto;
  width: 56px;
  height: 40px;
  display: flex;
  align-items: flex-end;
}
.race-row-sprite .horse-sprite {
  width: 100%;
  height: 100%;
}
.race-row-ident {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
  flex: 1 1 200px;
}
.race-row-name { font-weight: bold; }
.race-row-meta {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 0.75rem;
}
.race-row-code {
  color: var(--accent);
  letter-spacing: 0.05em;
}
.race-row-meta .race-row-date { color: var(--muted); }
.race-row-meta .race-row-date::before,
.race-row-meta .race-row-countdown::before { content: '· '; font-weight: normal; color: var(--muted); }
.race-row-label {
  font-size: 0.7rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.race-row-info {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  margin-left: auto;
  text-align: right;
  font-size: 0.8rem;
  color: var(--muted);
}
.race-row-countdown { font-weight: bold; color: var(--text); }
.race-row-winner,
.race-row-leader {
  color: var(--text);
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

/* ── Race view ─────────────────────────────────────── */

.race {
  display: grid;
  grid-template-rows: auto auto 1fr;
  min-height: 100vh;
}
.race-header {
  padding: 6px 24px;
  border-bottom: 2px solid var(--panel);
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
}
.race-header h1 { margin: 0; color: var(--accent); font-size: 1.25rem; letter-spacing: 0.05em; display: flex; align-items: center; gap: 0.4em; }
.race-header .meta { color: var(--muted); display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
.race-header .meta b { color: var(--text); font-weight: normal; }
.race-status { text-transform: uppercase; letter-spacing: 0.1em; }
.race-status--pending { color: var(--accent); }
.race-status--live { color: #7bed9f; }
.race-status--finished { color: var(--muted); }

.crowd {
  width: 100%;
  justify-self: center;
  height: calc(var(--sprite-scale) * 32px);
  display: flex;
  image-rendering: pixelated;
}
.crowd-cap, .crowd-body {
  height: 100%;
  background-size: calc(var(--sprite-scale) * 32px) calc(var(--sprite-scale) * 128px);
  background-position: 0 0;
  image-rendering: pixelated;
  animation: crowd-cheer 1s steps(4) infinite;
}
.crowd-cap {
  flex: 0 0 calc(var(--sprite-scale) * 32px);
  background-repeat: no-repeat;
}
.crowd-cap-left  { background-image: url('img/crowd-1-left.png'); }
.crowd-cap-right { background-image: url('img/crowd-1-right.png'); }
.crowd-body {
  flex: 1 1 auto;
  background-image: url('img/crowd-1.png');
  background-repeat: repeat-x;
}
.race.finished .crowd-cap,
.race.finished .crowd-body { animation-play-state: paused; }
@keyframes crowd-cheer {
  from { background-position-y: 0; }
  to   { background-position-y: calc(var(--sprite-scale) * -128px); }
}

.track {
  padding: 0 4px 24px 4px;
  display: flex;
  flex-direction: column;
  gap: var(--track-gap);
}

.lane {
  /* Never let a crowded field compress lanes below the sprite height — the
     track scrolls (autoscroll drives it in TV mode) instead of squashing
     horses on top of each other. */
  flex: 0 0 var(--horse-height);
  height: var(--horse-height);
  display: flex;
  align-items: stretch;
}
/* Fixed name-tag column at the start of every lane — names/levels/tokens all
   line up here instead of floating in front of / behind the moving horse. */
.lane-info {
  flex: 0 0 var(--label-col);
  position: relative;
  pointer-events: none;
}
/* Bordered chip, vertically aligned with the horse's middle (not the lane
   centre line), giving each lane a distinct edge. */
.lane-info-box {
  position: absolute;
  top: var(--label-mid);
  left: 4px;
  right: 6px;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 1px 6px;
  background: #1d1d24;          /* slightly lifted off the page's pure black */
  border: 1px solid var(--border);
  border-radius: 4px;
  overflow: hidden;
  line-height: 1.0;
  letter-spacing: 0.02em;
}
/* Each row clips; .row-scroll marquees its content when it overflows. */
.horse-name-row {
  overflow: hidden;
  white-space: nowrap;
}
/* Total tokens: permanent (no longer part of the rotator), sits under the name.
   Negative margins pull the lower two rows up so the three rows sit tight
   (the pixel glyphs don't fill their line box, so a small overlap never clips). */
.horse-tokens-row {
  overflow: hidden;
  white-space: nowrap;
  margin-top: -2px;
}
.row-scroll {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  will-change: transform;
}
.row-scroll.is-scrolling {
  animation: label-marquee 7s ease-in-out infinite;
}
@keyframes label-marquee {
  0%, 16%   { transform: translateX(0); }
  46%, 54%  { transform: translateX(var(--shift, 0)); }
  84%, 100% { transform: translateX(0); }
}
/* Row 2 stacks its views in one cell and cross-fades between them. */
.horse-stats-row {
  display: grid;
  align-items: center;
  overflow: hidden;
  margin-top: -2px;
}
.stat-view {
  grid-area: 1 / 1;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  animation: stat-cycle 12s ease-in-out infinite;
}
.stat-view:nth-child(2) { animation-delay: -9s; }   /* level    — 2nd */
.stat-view:nth-child(3) { animation-delay: -6s; }   /* pace     — 3rd */
.stat-view:nth-child(4) { animation-delay: -3s; }   /* position — 4th */
@keyframes stat-cycle {
  0%   { opacity: 1; }
  21%  { opacity: 1; }
  25%  { opacity: 0; }
  96%  { opacity: 0; }
  100% { opacity: 1; }
}
/* The running strip (dirt + rails) begins to the right of the label column. */
.lane-track {
  position: relative;
  flex: 1 1 auto;
  background: var(--lane) url('img/track-1.png') repeat-x center / auto 100%;
  image-rendering: pixelated;
  border-radius: 4px;
}
.lane-track::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 4px;
  background: #fff;
}
.lane-track::after {
  content: "";
  position: absolute;
  right: 0; top: 0; bottom: 0;
  width: 20px;
  background:
    conic-gradient(#fff 25%, #000 25% 50%, #fff 50% 75%, #000 75%) 0 0 / 10px 10px;
  background-color: #fff;
}
.horse {
  position: absolute;
  /* Sprite scales with the lane (height:80% of the lane) so lanes can be any
     height. Vertical placement is driven entirely by `top` — the body-bob
     keyframes then only nudge ±1px without re-specifying the base position.
     The drawn hooves sit ~at the box bottom (≈ top + 80%), so top:-30% lands
     the FEET on the lane's vertical centre with the body above (verified by
     outlined-box screenshot). */
  top: -30%;
  transform: translate(-50%, 0);
  transition: left 3s linear;
  height: 80%;
  aspect-ratio: 32 / 24;
  z-index: 1;
}
.horse-sprite { width: 100%; height: 100%; display: block; }

/* Soft ground shadow under each horse — body + head ovals rendered as a single
   SVG group with one opacity so overlap doesn't darken (the group composites
   into a private buffer first, then applies the group opacity). */
.horse::after {
  content: "";
  position: absolute;
  left: -5px;
  right: 5px;
  top: calc(100% - 4px);
  height: 8px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 10' preserveAspectRatio='none'><g opacity='0.45'><ellipse cx='50' cy='5' rx='30' ry='3.5' fill='black'/><ellipse cx='85' cy='5' rx='12' ry='2.5' fill='black'/></g></svg>");
  background-size: 100% 100%;
  background-repeat: no-repeat;
  z-index: -1;
  pointer-events: none;
}

/* Dust trail kicked up by the back hoof (bottom-left of sprite) */
.horse-dust {
  position: absolute;
  left: 8%;
  bottom: -1px;
  width: 7px;
  height: 5px;
  background: rgba(75, 55, 45, 0.85);
  border-radius: 50%;
  pointer-events: none;
  z-index: 0;
  opacity: 0;
}
.horse-dust::before,
.horse-dust::after {
  content: "";
  position: absolute;
  inset: 0;
  background: inherit;
  border-radius: inherit;
}
.horse.live .horse-dust          { animation: dust-puff 0.7s ease-out infinite; }
.horse.live .horse-dust::before  { animation: dust-puff 0.7s ease-out infinite; animation-delay: 0.23s; }
.horse.live .horse-dust::after   { animation: dust-puff 0.7s ease-out infinite; animation-delay: 0.46s; }
@keyframes dust-puff {
  0%   { opacity: 0;    transform: translate(0, 0)        scale(0.4); }
  20%  { opacity: 0.75;                                              }
  100% { opacity: 0;    transform: translate(-16px, -5px) scale(1.6); }
}


.horse-label {
  color: var(--text);
  font-family: "Bitcount Prop Single", var(--pixel-font);
  font-size: 0.53rem;
  font-weight: 600;
}
.horse-level {
  display: inline-block;
  margin-left: 0;
  padding: 0 4px;
  font-family: "Barlow Semi Condensed", var(--pixel-font);
  font-weight: 600;
  font-size: 0.32rem;
  text-transform: uppercase;
  color: #fff;
  background: #2563eb;
  border-radius: 999px;
  letter-spacing: 0.02em;
  line-height: 1.4;
}
.user-label {
  color: var(--text);
  opacity: 0.6;
  font-size: 0.52rem;
}
.horse-tokens {
  color: #fbbf24;              /* amber — reads as coins, distinct from the cream name/grey pace */
  font-size: 0.53rem;
  font-weight: 600;
  opacity: 1;
}
.horse-pace {
  color: var(--accent);
  font-size: 0.52rem;
  font-weight: bold;
}
.horse-position {
  font-size: 0.55rem;
  font-weight: bold;
  color: #aab0b8;            /* everything past 3rd — light grey */
}
.horse-position.pos-1 { color: #ffd700; }  /* gold   */
.horse-position.pos-2 { color: #c8ccd2; }  /* silver */
.horse-position.pos-3 { color: #cd7f32; }  /* bronze */

/* ── Pending state extras ─────────────────────────── */

.pending-banner {
  text-align: center;
  padding: 16px;
  background: var(--panel);
  border-bottom: 2px solid var(--accent);
  font-size: 1.25rem;
  color: var(--accent);
  letter-spacing: 0.1em;
}

/* ── Finished state extras ────────────────────────── */

.finished .horse { transition: left 1s ease-out, transform 1s ease-out, opacity 1s ease-out; }

.podium {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.85);
  display: flex;
  flex-direction: column;
  align-items: center;
  /* `safe center` keeps tall standings (many racers) from clipping at the top
     of the scroll container so the whole list — and the dismiss button — stay
     reachable. */
  justify-content: safe center;
  gap: 24px;
  padding: 24px 24px calc(var(--ticker-h) + 24px);
  overflow-y: auto;
  animation: fade-in 1s ease-out forwards;
  /* Sit above the achievement ticker (z-index 9999) so the dismiss button is
     never covered by it. */
  z-index: 10000;
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

.podium h2 { color: var(--accent); margin: 0; font-size: 2rem; letter-spacing: 0.1em; }
.podium ol {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  align-items: flex-end;
  gap: 16px;
}
.podium li {
  background: var(--panel);
  padding: 16px;
  border-radius: 6px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  min-width: 180px;
}
.podium li:nth-child(1) { border: 2px solid gold; transform: translateY(-16px); }
.podium li:nth-child(2) { border: 2px solid silver; }
.podium li:nth-child(3) { border: 2px solid #cd7f32; }
.podium .place { font-size: 2rem; }
.podium .name { font-weight: bold; }
.podium .podium-user { color: var(--muted); font-size: 0.7em; }
.podium .tokens { color: var(--muted); }
.podium .xp-line {
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: center;
  margin-top: 4px;
}
.podium .level-chip {
  display: inline-block;
  padding: 2px 6px;
  font-size: 0.7em;
  color: #67e8f9;
  border: 1px solid #67e8f9;
  border-radius: 3px;
  letter-spacing: 0.04em;
}
.podium .xp-gained { color: #67e8f9; font-weight: bold; font-size: 0.85em; }
.podium .xp-bar {
  width: 160px;
  height: 8px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 4px;
  overflow: hidden;
}
.podium .xp-bar-fill {
  height: 100%;
  background: #67e8f9;
  transition: width 1.5s ease-out;
}
.podium .xp-bar-text { color: var(--muted); font-size: 0.7em; }
.podium .level-up-banner {
  margin-top: 6px;
  color: gold;
  font-weight: bold;
  font-size: 1rem;
  letter-spacing: 0.18em;
  text-shadow: 0 0 12px rgba(255, 215, 0, 0.6);
  animation: level-up-pulse 0.8s ease-in-out 0.3s infinite alternate;
}
@keyframes level-up-pulse {
  from { transform: scale(1); }
  to { transform: scale(1.12); }
}

.podium .standings-table {
  border-collapse: collapse;
  color: var(--text);
  background: var(--panel);
  border-radius: 6px;
  overflow: hidden;
  max-width: 90vw;
}
.podium .standings-table th,
.podium .standings-table td {
  padding: 6px 14px;
  font-size: 0.85em;
  text-align: left;
}
.podium .standings-table th {
  font-size: 0.75em;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.podium .standings-table tbody tr:nth-child(even) { background: rgba(255, 255, 255, 0.03); }
.podium .standings-table .rank { color: var(--muted); }
.podium .standings-table .horse-name { font-weight: bold; }
.podium .standings-table .horse-name .jockey {
  color: var(--muted);
  font-weight: normal;
  font-size: 0.9em;
}
.podium .standings-table .levelled-up { color: gold; font-weight: bold; }

.podium .dismiss {
  background: var(--accent);
  color: var(--bg);
  border: none;
  padding: 8px 16px;
  font: inherit;
  cursor: pointer;
  /* Pinned to a corner so it stays reachable even when a chart face is
     covering the whole screen. */
  position: fixed;
  right: 24px;
  bottom: 24px;
  z-index: 100;
}
.podium .dismiss:hover { filter: brightness(1.1); }

/* Rotating detail panel: standings + charts share one grid cell so the
   container sizes to the tallest face and faces can crossfade in place. */
.detail-cycle { display: grid; width: min(960px, 94vw); }
.detail-cycle > .detail-face { grid-area: 1 / 1; opacity: 0; transition: opacity 0.6s ease; pointer-events: none; }
.detail-cycle > .detail-face.is-active { opacity: 1; pointer-events: auto; }
@media (prefers-reduced-motion: reduce) { .detail-cycle > .detail-face { transition: none; } }

.chart-face { display: flex; flex-direction: column; gap: 8px; }
.chart-title { color: var(--accent); letter-spacing: 0.08em; text-transform: uppercase; font-size: 0.9rem; }
.chart-svg { width: 100%; height: auto; background: #0c0c0c; border: 1px solid #222; }
.chart-grid { stroke: #222; stroke-width: 1; }
.chart-line { stroke-linejoin: round; stroke-linecap: round; }
.chart-axis { fill: #888; font-size: 10px; }
.chart-legend { display: flex; flex-wrap: wrap; gap: 4px 12px; font-size: 0.85rem; color: #ccc; }
.legend-item { display: inline-flex; align-items: center; gap: 5px; }
.legend-chip { width: 10px; height: 10px; display: inline-block; }

/* When the panel flips to a chart, take over the whole viewport (the podium and
   standings sit behind it). The standings face stays under the podium in-flow. */
.detail-cycle > .chart-face {
  position: fixed;
  inset: 0;
  z-index: 50;
  justify-content: center;
  gap: 18px;
  padding: clamp(20px, 4vw, 64px);
  background: #0a0a0a;
}
.chart-face .chart-title { font-size: 1.4rem; text-align: center; }
.chart-face .chart-svg { height: 64vh; border: none; }
.chart-face .chart-legend { justify-content: center; gap: 8px 20px; font-size: 1.05rem; }
.chart-face .legend-chip { width: 14px; height: 14px; }

/* ── Confetti ─────────────────────────────────────── */

.confetti {
  position: fixed;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 5;
}
.confetti span {
  position: absolute;
  top: -20px;
  width: 8px;
  height: 12px;
  animation: fall 3s linear forwards;
}
@keyframes fall {
  to { transform: translateY(110vh) rotate(720deg); }
}

/* ── Animations ───────────────────────────────────── */

/* Skeletal pivot points */
.leg-back              { transform-origin: 6px 16px; }   /* back hip  */
.leg-back-lower        { transform-origin: 6px 18px; }   /* back knee */
.leg-front             { transform-origin: 18px 16px; }  /* front hip */
.leg-front-lower       { transform-origin: 18px 18px; }  /* front knee */

/* Smooth sub-pixel rendering on animated legs */
.leg-back, .leg-front  { shape-rendering: auto; }

/* ── Hip swing ──────────────────────── */
@keyframes hip-back {
  0%   { transform: rotate(18deg); }   /* pushed back  */
  50%  { transform: rotate(-16deg); }  /* swung forward */
  100% { transform: rotate(18deg); }
}
@keyframes hip-front {
  0%   { transform: rotate(-16deg); }  /* reaching forward */
  50%  { transform: rotate(18deg); }   /* pushed back      */
  100% { transform: rotate(-16deg); }
}

/* ── Knee bend (nested inside hip group) ── */
@keyframes knee-back {
  0%        { transform: rotate(0deg); }     /* straight on ground */
  30%       { transform: rotate(-28deg); }   /* folds up as leg lifts */
  50%       { transform: rotate(-12deg); }   /* partially bent at full forward */
  80%       { transform: rotate(-20deg); }   /* bends on downswing */
  100%      { transform: rotate(0deg); }     /* straight on landing */
}
@keyframes knee-front {
  0%        { transform: rotate(0deg); }     /* straight at full reach */
  20%       { transform: rotate(20deg); }    /* bends as it pushes back */
  50%       { transform: rotate(0deg); }     /* straight at back */
  70%       { transform: rotate(28deg); }    /* folds as leg lifts forward */
  100%      { transform: rotate(0deg); }     /* straightens on landing */
}

/* ── Body bob ───────────────────────── */
@keyframes body-bob {
  0%, 100% { transform: translate(-50%, 0); }
  25%      { transform: translate(-50%, -1px); }
  75%      { transform: translate(-50%, 0.5px); }
}

/* ── Apply to live / pending horses ── */
.horse.live .leg-back,
.horse.pending .leg-back {
  animation: hip-back 0.4s ease-in-out infinite;
}
.horse.live .leg-back-lower,
.horse.pending .leg-back-lower {
  animation: knee-back 0.4s ease-in-out infinite;
}
.horse.live .leg-front,
.horse.pending .leg-front {
  animation: hip-front 0.4s ease-in-out infinite;
}
.horse.live .leg-front-lower,
.horse.pending .leg-front-lower {
  animation: knee-front 0.4s ease-in-out infinite;
}
.horse.live, .horse.pending {
  animation: body-bob 0.4s ease-in-out infinite;
}

/* ── Catalog view ─────────────────────────────────── */

:root {
  --rarity-common: #9ca3af;
  --rarity-rare: #60a5fa;
  --rarity-epic: #c084fc;
  --rarity-legendary: #fbbf24;
}

.catalog {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 24px;
  gap: 16px;
  max-width: 1280px;
  width: 100%;
  margin: 0 auto;
}
.catalog-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  border-bottom: 2px solid var(--panel);
  padding-bottom: 12px;
}
.catalog-header h1 {
  margin: 0;
  color: var(--accent);
  font-size: 1.75rem;
  letter-spacing: 0.08em;
  display: flex;
  align-items: center;
  gap: 0.4em;
}
.catalog-intro {
  color: var(--muted);
  margin: 0;
  max-width: 70ch;
  font-size: 0.95rem;
  line-height: 1.4;
}
.catalog-intro em { color: var(--text); font-style: normal; }

.catalog-controls {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 4px 0 8px;
}
.catalog-control-label {
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 0.75rem;
}
.palette-controls {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.palette-btn {
  background: var(--panel);
  color: var(--text);
  border: 2px solid var(--border);
  padding: 6px 14px;
  font: inherit;
  font-size: 0.95rem;
  letter-spacing: 0.04em;
  cursor: pointer;
  border-radius: 4px;
}
.palette-btn:hover { border-color: var(--accent); }
.palette-btn.active {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--bg);
}

.catalog-sections {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.rarity-heading {
  margin: 24px 0 8px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
  font-size: 1rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  display: flex;
  align-items: baseline;
  gap: 12px;
}
.rarity-heading .rarity-name { color: var(--accent); }
.rarity-heading.rarity-common .rarity-name    { color: var(--rarity-common); }
.rarity-heading.rarity-rare .rarity-name      { color: var(--rarity-rare); }
.rarity-heading.rarity-epic .rarity-name      { color: var(--rarity-epic); }
.rarity-heading.rarity-legendary .rarity-name { color: var(--rarity-legendary); }
.rarity-meta {
  color: var(--muted);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
}

.hat-row {
  display: flex;
  gap: 16px;
  padding: 12px 16px;
  background: var(--panel);
  border: 2px solid var(--border);
  border-radius: 6px;
  align-items: stretch;
}
.hat-meta {
  width: 13rem;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
}
.hat-name-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.hat-name {
  color: var(--text);
  font-size: 1.15rem;
  letter-spacing: 0.03em;
}
.hat-id {
  color: var(--muted);
  font-size: 0.7rem;
  font-family: ui-monospace, SFMono-Regular, monospace;
  letter-spacing: 0;
}
.hat-count {
  color: var(--muted);
  font-size: 0.8rem;
}
.rarity-badge {
  display: inline-block;
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  padding: 2px 8px;
  border-radius: 3px;
  color: var(--bg);
  text-transform: uppercase;
}
.rarity-badge.rarity-common    { background: var(--rarity-common); }
.rarity-badge.rarity-rare      { background: var(--rarity-rare); }
.rarity-badge.rarity-epic      { background: var(--rarity-epic); }
.rarity-badge.rarity-legendary { background: var(--rarity-legendary); }

.variants-strip {
  flex: 1;
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: flex-end;
}
.variant-card {
  width: 88px;
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 6px 6px 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}
.variant-card-dark  { background: #0a0a0a; }
.variant-card-light { background: #3a3a3a; }
.variant-card .horse-sprite {
  width: 100%;
  height: auto;
  image-rendering: pixelated;
  shape-rendering: crispEdges;
}
.variant-card .variant-name {
  font-size: 0.7rem;
  color: var(--text);
  text-align: center;
  letter-spacing: 0.02em;
}

.catalog-footer {
  color: var(--muted);
  font-size: 0.85rem;
  margin: 24px 0 8px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  line-height: 1.5;
}

.home .catalog-link {
  color: var(--muted);
  font-size: 0.85rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  border-bottom: 1px dashed var(--border);
  padding-bottom: 2px;
}
.home .catalog-link:hover { color: var(--accent); border-color: var(--accent); }

/* ── Error / fallback ─────────────────────────────── */

.error {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 32px;
  text-align: center;
}
.error h2 { color: #ff6b6b; margin: 0; }
.error a { color: var(--accent); }

/* ── TV mode (toggled via .tv on <body>; auto-applied on 21:9+, ≥1920px) ─ */

body.tv {
  --sprite-scale: 3;
  --horse-height: 66px;
  --label-col: 168px;
  --track-gap: 0px;
  font-size: 18px;
}

body.tv .race-header { padding: 8px 48px; }
body.tv .race-header h1 { font-size: 1.5rem; }
body.tv .race-header .meta { gap: 32px; font-size: 1rem; }

/* Lock the race to viewport height; track scrolls, header stays fixed */
body.tv .race { height: 100vh; min-height: 100vh; }
body.tv .track {
  padding: 12px 6px;
  overflow-y: auto;
  min-height: 0;
  scrollbar-width: none;
}
body.tv .track::-webkit-scrollbar { display: none; }

body.tv .lane-info-box { gap: 1px; padding: 3px 7px; }
body.tv .horse-label {
  font-size: 0.82rem;
  letter-spacing: 0.05em;
}
body.tv .horse-level { font-size: 0.5rem; padding: 1px 6px; }
body.tv .user-label { font-size: 0.75rem; }
body.tv .horse-tokens { font-size: 0.78rem; }
body.tv .horse-pace { font-size: 0.85rem; }
body.tv .horse-position { font-size: 0.85rem; }

body.tv .pending-banner { padding: 24px; font-size: 1.75rem; }

body.tv .home { gap: 48px; padding: 48px; }
body.tv .home p { font-size: 1.35rem; max-width: 50ch; }
body.tv .home input {
  font-size: 1.5rem;
  width: 240px;
  padding: 14px 20px;
}
body.tv .home button { font-size: 1.25rem; padding: 14px 28px; }

body.tv .btn { font-size: 1.1rem; padding: 12px 24px; }

body.tv .podium { gap: 32px; }
body.tv .podium h2 { font-size: 2.5rem; }
body.tv .podium li { padding: 24px; gap: 12px; }
body.tv .podium .place { font-size: 2.5rem; }
body.tv .podium .name { font-size: 1.25rem; }
body.tv .podium .tokens { font-size: 1.1rem; }

/* Race header action buttons sit alongside the meta items */
.race-header .meta .btn {
  padding: 3px 10px;
  font-size: 0.8rem;
}
body.tv .race-header .meta .btn {
  padding: 4px 14px;
  font-size: 0.9rem;
}
.tv-toggle[aria-pressed="true"] {
  background: #2563eb;
  color: #fff;
}

/* ── Achievement ticker ─────────────────────────────── */

.achievement-ticker {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--ticker-h);
  overflow: hidden;
  z-index: 9999;
  background: linear-gradient(180deg, rgba(12, 12, 12, 0.94), rgba(20, 20, 20, 0.98));
  border-top: 2px solid #ffd166;
  box-shadow: 0 -4px 18px rgba(0, 0, 0, 0.45);
  white-space: nowrap;
  transition: opacity 0.3s ease;
}
.achievement-ticker.is-empty { opacity: 0; pointer-events: none; }

/* The track is wider than the viewport; ticker.ts translates it leftward. */
.achievement-ticker-track {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  height: 100%;
  width: max-content;
  will-change: transform;
}

.achievement-ticker-item {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: baseline;
  gap: 0.45rem;
  height: 100%;
  padding: 0 1.5rem 0 0;
  font-size: 1.05rem;
  line-height: var(--ticker-h);
  color: #fff;
}
.achievement-ticker-xp {
  font-weight: bold;
  color: #ffd166;
}
.achievement-ticker-horse { font-weight: bold; }
.achievement-ticker-name { color: #ffd166; }
.achievement-ticker-desc { color: #aaa; }

/* Bullet between achievements within a pass. */
.achievement-ticker-sep {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  height: 100%;
  padding: 0 1.5rem;
  color: #ffd166;
  opacity: 0.55;
}

/* Loop seam — a blank break marking the end of one pass and start of the next. */
.achievement-ticker-gap {
  flex: 0 0 auto;
  height: 100%;
}

/* Reserve room so the ticker sits below the race instead of over the last lane.
   Only while it's actually showing achievements. */
.race:has(.achievement-ticker:not(.is-empty)) { padding-bottom: var(--ticker-h); }

/* ── Org manager ("/org-manager": create/join orgs, schedule, webhook) ─── */

.muted { color: var(--muted); }

/* Signed-out state (render/login.ts). */
.org-login {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
  padding: 32px;
  text-align: center;
}
.org-login h1 {
  margin: 0;
  color: var(--accent);
  font-size: clamp(2rem, 6vw, 3rem);
  letter-spacing: 0.08em;
}
.org-login p { color: var(--muted); margin: 0; max-width: 42ch; }
.org-login .cmd,
.cmd {
  display: inline-block;
  background: var(--panel);
  border: 2px solid var(--border);
  color: var(--accent);
  padding: 10px 18px;
  font-size: 1.15rem;
  letter-spacing: 0.05em;
  border-radius: 4px;
}

/* Signed-in shell (org-manager/index.ts): sidebar + tabs + tab body. */
.org-manager {
  flex: 1;
  display: flex;
  align-items: stretch;
  min-height: 0;
}
.org-side { flex: 0 0 240px; }
.org-sidebar {
  height: 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 20px 16px;
  background: var(--panel);
  border-right: 2px solid var(--border);
}
.org-side-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: 0.75rem;
}
.org-logout {
  background: none;
  border: 1px solid var(--border);
  color: var(--accent);
  font: inherit;
  font-size: 0.75rem;
  letter-spacing: 0.03em;
  padding: 3px 10px;
  border-radius: 4px;
  cursor: pointer;
}
.org-logout:hover { border-color: var(--accent); }
.org-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow-y: auto;
}
.org-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  background: var(--bg);
  border: 2px solid var(--border);
  border-radius: 4px;
  letter-spacing: 0.02em;
  cursor: pointer;
}
.org-row:hover { border-color: var(--accent); }
.org-row.selected { border-color: var(--accent); background: rgba(209, 213, 219, 0.08); color: var(--accent); }
.pill {
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 2px 8px;
  border-radius: 3px;
  background: var(--border);
  color: var(--muted);
}
.org-row.selected .pill { color: var(--bg); background: var(--accent); }

/* .org-actions is reused both as the stacked sidebar action buttons and the
   inline save/clear row inside a tab panel. */
.org-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.org-sidebar .org-actions { flex-direction: column; margin-top: auto; }
.org-create, .org-join, .org-btn {
  background: var(--accent);
  color: var(--bg);
  border: none;
  padding: 9px 16px;
  font: inherit;
  font-size: 0.85rem;
  font-weight: bold;
  letter-spacing: 0.03em;
  border-radius: 4px;
  cursor: pointer;
}
.org-create:hover, .org-join:hover, .org-btn:hover { filter: brightness(1.1); }
.org-sidebar .org-create, .org-sidebar .org-join { width: 100%; }

.org-main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  padding: 24px;
  gap: 16px;
}
.org-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  border-bottom: 2px solid var(--panel);
}
.org-tab {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -2px;
  padding: 10px 16px;
  color: var(--muted);
  font: inherit;
  font-size: 0.95rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  cursor: pointer;
}
.org-tab:hover { color: var(--text); }
.org-tab.on { color: var(--accent); border-bottom-color: var(--accent); }
.org-tabbody { flex: 1; }

.org-panel {
  display: flex;
  flex-direction: column;
  gap: 18px;
  max-width: 640px;
  padding: 20px 24px;
  background: var(--panel);
  border: 2px solid var(--border);
  border-radius: 6px;
}
.org-field { display: flex; flex-direction: column; gap: 6px; font-size: 1rem; }
.label {
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.72rem;
}
label.label {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  max-width: 260px;
}
label.label:has(input[type="checkbox"]) { flex-direction: row; align-items: center; max-width: none; }
label.label input {
  font-family: inherit;
  text-transform: none;
  letter-spacing: normal;
  font-size: 1rem;
  color: var(--text);
  background: var(--bg);
  border: 2px solid var(--border);
  border-radius: 4px;
  padding: 7px 10px;
  width: 100%;
}
label.label input[type="checkbox"] { width: auto; }
label.label input:focus { outline: none; border-color: var(--accent); }
label.label input:disabled { opacity: 0.5; }

.org-token {
  display: inline-block;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 5px 12px;
  margin-right: 8px;
  color: var(--accent);
  font-size: 1rem;
  letter-spacing: 0.04em;
}
.org-copy {
  background: none;
  border: 1px solid var(--border);
  color: var(--accent);
  padding: 4px 12px;
  font: inherit;
  font-size: 0.8rem;
  border-radius: 4px;
  cursor: pointer;
}
.org-copy:hover { border-color: var(--accent); background: rgba(209, 213, 219, 0.08); }
.warn { color: #fbbf24; font-size: 0.85rem; margin: 4px 0 0; }

.org-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--bg);
  border: 2px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
}
.org-table th {
  font-size: 0.72rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  text-align: left;
  font-weight: normal;
  padding: 9px 14px;
  border-bottom: 1px solid var(--border);
}
.org-table td { padding: 10px 14px; font-size: 0.95rem; }
.org-table tbody tr:nth-child(even) { background: rgba(255, 255, 255, 0.04); }

.org-days { display: flex; flex-wrap: wrap; gap: 10px; }
.org-day {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-size: 0.85rem;
  cursor: pointer;
}
.org-day:has(input:checked) { border-color: var(--accent); color: var(--accent); }
.org-day input[type="checkbox"] { accent-color: var(--accent); }

.org-secret {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px 14px;
  background: #0d0d0d;
  border: 1px dashed var(--accent);
  border-radius: 4px;
  color: var(--accent);
}
.org-secret code { font-size: 1rem; letter-spacing: 0.03em; word-break: break-all; }

/* Preview-only scaffolding (site/src/preview-org-manager.ts) — not emitted by
   the render modules, just labels stacking the extra tab screenshots. */
.org-preview-section { padding: 8px 24px 24px; border-top: 2px solid var(--panel); }
.org-preview-heading {
  margin: 16px 0 12px;
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: 0.9rem;
}

@media (max-width: 720px) {
  .org-manager { flex-direction: column; }
  .org-side { flex: 0 0 auto; }
  .org-sidebar { border-right: none; border-bottom: 2px solid var(--border); }
  .org-sidebar .org-actions { flex-direction: row; margin-top: 0; }
  .org-sidebar .org-create, .org-sidebar .org-join { width: auto; flex: 1; }
}
