/* Poker Tracker: a night-session console. Deep navy, one sky-blue accent,
   the system sans with tabular figures, a sidebar on a desk and a bottom
   bar on a phone. Results keep their own green and red; nothing else adds
   a hue. Every colour lives here as a token, charts included (stats.js,
   tournament_detail.js and the Hand Stats scripts read them back). */
:root {
  --bg: #0c1220;
  /* The shell around the page: sidebar and bottom bar. */
  --bg-sunken: #090e19;
  --bg-elevated: #121a2b;
  --bg-elevated-2: #19233a;
  --border: #222d44;
  /* A field's border under the pointer: one step up from --border. */
  --border-hover: #34405e;
  --text: #e7ecf6;
  --text-muted: #97a3bf;
  /* Placeholders: muted enough to read as a hint, still 5:1 on --bg. */
  --text-placeholder: #7f8ba8;
  --accent: #1687d9;
  /* Fill behind white text (5.2:1); the base accent only reaches 3.8:1. */
  --accent-strong: #1270b8;
  /* Ink on --accent-strong (the replayer's play control, primary buttons). */
  --on-accent: #fff;
  /* The accent as text on the dark surfaces: a lighter sky (links, badges). */
  --accent-text: #5ab3f2;
  --accent-soft: rgba(22, 135, 217, 0.16);
  --positive: #2fbf71;
  --positive-soft: rgba(47, 191, 113, 0.15);
  --negative: #e2546b;
  /* Losses as text, readable on the tinted calendar cells too. */
  --negative-text: #f07f92;
  --negative-soft: rgba(226, 84, 107, 0.15);
  /* A tournament win: rare enough to be news, so it is the one gold. */
  --gold: #f4c542;
  --on-gold: #4a3800;
  /* A warning (an incomplete history): the same gold family, never orange. */
  --warning-soft: rgba(244, 197, 66, 0.1);
  --warning-line: rgba(244, 197, 66, 0.32);
  --warning-text: #f2d48a;
  /* Extra chart series next to the accent (Hand Stats trend: in / out of
     position; a second entry on a stack curve). Separated by lightness,
     not by adding hues: a pale silver and a deep slate either side of the
     sky blue. Take them in this order. */
  --series-2: #b9c4da;
  --series-3: #5f7096;
  --chart-grid: #1c2640;
  /* The dashboard calendar's volume shades, from a day of one or two
     tournaments to one of ten or more: the accent mixed into a played
     day's own surface, one hue throughout. Volume, never a result. The
     text stays 5.5:1 on the deepest. */
  --volume-1: color-mix(in srgb, var(--accent) 12%, var(--bg-elevated-2));
  --volume-2: color-mix(in srgb, var(--accent) 24%, var(--bg-elevated-2));
  --volume-3: color-mix(in srgb, var(--accent) 40%, var(--bg-elevated-2));
  --volume-4: color-mix(in srgb, var(--accent) 60%, var(--bg-elevated-2));
  /* A four-colour deck, as the poker clients draw one: a flush draw reads
     at a glance when the diamond is not the heart's colour and the club is
     not the spade's. Ink on the card face (.pcard), all four at least 5.5:1
     against its darkest stop. */
  --suit-spade: #10131a;
  --suit-heart: #b81830;
  --suit-diamond: #1558c0;
  --suit-club: #00662a;
  --card-face: linear-gradient(#fdfefe, #e9edf6);
  --card-face-board: linear-gradient(#eef1f7, #dbe1ee);
  --card-ink: #10131a;
  /* The replayer's table: a surface tinted with the accent, never a green
     baize. The felt is a place for the cards, not a second colour. */
  --felt: color-mix(in srgb, var(--accent) 10%, var(--bg-elevated));
  --felt-line: color-mix(in srgb, var(--accent) 24%, var(--bg-elevated));
  --card-back: color-mix(in srgb, var(--accent) 28%, var(--bg-elevated-2));
  /* The lit middle of the replayer's felt, the dark rail round it, and the
     seat discs that sit on the rail. */
  --felt-lit: color-mix(in srgb, var(--accent) 38%, var(--bg-elevated));
  --felt-edge: color-mix(in srgb, var(--accent) 18%, var(--bg-elevated));
  --rail: var(--bg-sunken);
  --seat-disc: color-mix(in srgb, var(--accent) 34%, var(--bg-elevated));
  /* Floating surfaces: a tooltip, and a dialog over its dimmed page. */
  --shadow-popover: 0 8px 24px rgba(3, 6, 14, 0.45);
  --shadow-dialog: 0 24px 64px rgba(3, 6, 14, 0.6);
  --backdrop: rgba(4, 7, 14, 0.72);
  --radius: 12px;
  --radius-sm: 8px;
  --font-sans: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  /* The shell: the sidebar's width on a desk, the bottom bar's height on a
     phone (each 0 where the other is in use). */
  --shell-side: 0px;
  --tabbar-h: 0px;
  color-scheme: dark;
  font-size: 16px;
}

* {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: 16px;
}

:where(a, button, summary, input, select, textarea, label) {
  touch-action: manipulation;
}
:where(a, button, summary):focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: 2px;
}
::selection {
  background: color-mix(in srgb, var(--accent) 45%, transparent);
  color: var(--text);
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 0.95rem;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  /* Safety net: a too-wide table/chart inside a card should scroll within
     its own box (see .table-scroll), never push the whole page sideways. */
  overflow-x: hidden;
}

a {
  color: var(--accent-text);
  text-decoration: none;
  text-underline-offset: 3px;
}
a:hover {
  text-decoration: underline;
}

code,
kbd,
pre {
  font-family: var(--font-mono);
  font-size: 0.9em;
}

.skip-link {
  position: absolute;
  left: 12px;
  top: -48px;
  z-index: 50;
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  background: var(--accent-strong);
  color: var(--on-accent);
  font-weight: 600;
}
.skip-link:focus {
  top: 12px;
}
main:focus {
  outline: none;
}

/* ---------- Shell ---------- */

.brand {
  display: inline-flex;
  flex-direction: column;
  gap: 1px;
  color: var(--text);
  line-height: 1.2;
}
.brand:hover {
  text-decoration: none;
}
.brand-name {
  font-size: 1.02rem;
  font-weight: 600;
  letter-spacing: -0.015em;
}
.brand-sub {
  color: var(--text-muted);
  font-size: 0.78rem;
}

.sidebar {
  display: none;
}
.phone-head,
.public-head {
  display: flex;
  align-items: center;
  min-height: 56px;
  padding: 8px 16px;
  padding-left: max(16px, env(safe-area-inset-left));
  padding-right: max(16px, env(safe-area-inset-right));
  border-bottom: 1px solid var(--border);
  background: var(--bg-sunken);
}

.nav-group-title {
  margin: 0 0 4px;
  padding: 0 12px;
  color: var(--text-muted);
  font-size: 0.78rem;
  font-weight: 400;
  letter-spacing: 0;
}
.side-nav ul,
.tabbar ul,
.sheet-links {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Phones and tablets: a bottom bar with the five sections used most and
   "More" for the whole list. Fixed above the home indicator. */
.has-shell {
  --tabbar-h: 60px;
  padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
  scroll-padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
}
.tabbar {
  position: fixed;
  inset: auto 0 0;
  z-index: 30;
  padding: 0 max(4px, env(safe-area-inset-right)) env(safe-area-inset-bottom) max(4px, env(safe-area-inset-left));
  border-top: 1px solid var(--border);
  background: var(--bg-sunken);
}
.tabbar ul {
  display: grid;
  /* "More" is a little wider: it carries the name of a section that lives
     in the sheet ("Opponents", "Hand Stats") when that is the page. */
  grid-template-columns: repeat(5, minmax(0, 1fr)) minmax(0, 1.25fr);
  max-width: 640px;
  margin: 0 auto;
}
.tab {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  width: 100%;
  height: var(--tabbar-h);
  padding: 0 2px;
  border: 0;
  background: none;
  color: var(--text-muted);
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  cursor: pointer;
  transition: color 0.15s ease-out;
}
.tab-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tab:hover {
  color: var(--text);
  text-decoration: none;
}
.tab:active {
  color: var(--text);
  background: var(--bg-elevated);
}
/* The page you are on: lighter ink and a short bar along the top edge. */
.tab[aria-current="page"],
.tab-more.is-current {
  color: var(--accent-text);
}
.tab[aria-current="page"]::before,
.tab-more.is-current::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 22%;
  right: 22%;
  height: 2px;
  border-radius: 0 0 2px 2px;
  background: var(--accent-text);
}
.tab:focus-visible {
  outline-offset: -4px;
  border-radius: 10px;
}
/* Showing a section that lives in "More": its name, smaller, under the
   chevron, so a long one like "Opponents" still fits the cell. */
.tab-more.is-current {
  flex-direction: column;
  gap: 3px;
  font-size: 0.74rem;
}
.tab-more.is-current .tab-caret {
  order: -1;
  margin-top: 4px;
}
.tab-more.is-current .tab-label {
  max-width: 100%;
}
/* An upward chevron: "More" opens a sheet from below. */
.tab-caret {
  flex: none;
  width: 6px;
  height: 6px;
  margin-top: 3px;
  border-top: 1.5px solid currentColor;
  border-left: 1.5px solid currentColor;
  transform: rotate(45deg);
}

/* The sheet: every section, grouped by purpose, rising from the bar. */
.nav-sheet {
  width: 100%;
  max-width: 560px;
  max-height: min(88dvh, 640px);
  margin: auto auto 0;
  padding: 0;
  border: 1px solid var(--border-hover);
  border-bottom: 0;
  border-radius: 18px 18px 0 0;
  background: var(--bg-elevated);
  color: var(--text);
  box-shadow: var(--shadow-dialog);
  overscroll-behavior: contain;
}
.nav-sheet::backdrop {
  background: var(--backdrop);
}
@media (prefers-reduced-motion: no-preference) {
  .nav-sheet[open] {
    animation: sheet-up 0.22s cubic-bezier(0.2, 0.8, 0.2, 1);
  }
  .nav-sheet[open]::backdrop {
    animation: fade-in 0.22s ease-out;
  }
}
@keyframes sheet-up {
  from {
    transform: translateY(24px);
    opacity: 0;
  }
}
html:has(.nav-sheet[open]) {
  overflow: hidden;
}
.sheet-inner {
  padding: 8px 16px calc(16px + env(safe-area-inset-bottom));
}
.sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}
.sheet-head h2 {
  margin: 0;
  font-size: 1.05rem;
}
.sheet-close {
  min-width: 44px;
  min-height: 44px;
  margin-right: -8px;
  padding: 0 12px;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--accent-text);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.sheet-close:hover {
  background: var(--bg-elevated-2);
}
.sheet-group {
  padding: 12px 0 4px;
  border-top: 1px solid var(--border);
}
.sheet-group:first-of-type {
  border-top: 0;
}
.sheet-group .nav-group-title {
  padding: 0 4px;
  margin-bottom: 6px;
}
.sheet-links {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px;
}
.sheet-link {
  display: flex;
  align-items: center;
  min-height: 48px;
  padding: 0 14px;
  border-radius: 10px;
  background: var(--bg-elevated-2);
  color: var(--text);
  font-weight: 600;
  transition: background 0.15s ease-out;
}
.sheet-link:hover {
  background: color-mix(in srgb, var(--text) 8%, var(--bg-elevated-2));
  text-decoration: none;
}
.sheet-link[aria-current="page"] {
  background: var(--accent-soft);
  color: var(--accent-text);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 55%, transparent);
}
.sheet-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.sheet-foot .btn {
  min-height: 44px;
}
.side-user {
  overflow: hidden;
  color: var(--text-muted);
  font-size: 0.85rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Desks: a sidebar with every section in its group, the account at the
   foot, and the page in the remaining width. */
@media (min-width: 1024px) {
  :root {
    --shell-side: 232px;
  }
  .has-shell {
    --tabbar-h: 0px;
    padding-bottom: 0;
  }
  .tabbar,
  .nav-sheet,
  .phone-head {
    display: none;
  }
  /* The sidebar's column, painted the full height of the page with its
     hairline on the right, however long the page runs. */
  .shell {
    display: grid;
    grid-template-columns: var(--shell-side) minmax(0, 1fr);
    min-height: 100vh;
    background: linear-gradient(
      to right,
      var(--bg-sunken) calc(var(--shell-side) - 1px),
      var(--border) calc(var(--shell-side) - 1px) var(--shell-side),
      transparent var(--shell-side)
    );
  }
  .sidebar {
    position: sticky;
    top: 0;
    display: flex;
    flex-direction: column;
    gap: 28px;
    height: 100vh;
    height: 100dvh;
    padding: 22px 12px 16px;
    overflow-y: auto;
  }
  .sidebar > .brand {
    padding: 0 12px;
  }
  .side-nav {
    display: flex;
    flex-direction: column;
    gap: 20px;
  }
  .nav-link {
    display: flex;
    align-items: center;
    min-height: 36px;
    padding: 0 12px;
    border-radius: var(--radius-sm);
    color: var(--text-muted);
    font-size: 0.92rem;
    font-weight: 600;
    transition: background 0.15s ease-out, color 0.15s ease-out;
  }
  .nav-link:hover {
    background: var(--bg-elevated);
    color: var(--text);
    text-decoration: none;
  }
  .nav-link:active {
    background: var(--bg-elevated-2);
  }
  .nav-link[aria-current="page"] {
    background: var(--accent-soft);
    color: var(--accent-text);
  }
  .side-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-top: auto;
    padding: 12px 12px 0;
    border-top: 1px solid var(--border);
  }
  .side-foot form {
    margin: 0;
  }
  .side-logout {
    min-height: 36px;
    padding: 0 10px;
    margin-right: -10px;
    border: 0;
    border-radius: var(--radius-sm);
    background: none;
    color: var(--text-muted);
    font: inherit;
    font-size: 0.88rem;
    font-weight: 600;
    cursor: pointer;
  }
  .side-logout:hover {
    background: var(--bg-elevated);
    color: var(--text);
  }
}

main {
  max-width: 1120px;
  margin: 0 auto;
  padding: 32px 28px 72px;
}

h1,
h2,
h3 {
  text-wrap: balance;
}
h1 {
  font-size: 1.75rem;
  font-weight: 600;
  margin: 0 0 24px;
  line-height: 1.2;
  letter-spacing: -0.025em;
}
h2 {
  font-size: 1.1rem;
  font-weight: 600;
  margin: 36px 0 12px;
  letter-spacing: -0.012em;
}
/* The quieter second half of a page title: "Monster Stack  Hand review". */
.h1-sub,
h1 small {
  margin-left: 8px;
  color: var(--text-muted);
  font-size: 0.6em;
  font-weight: 400;
  letter-spacing: -0.005em;
}
h2 .muted {
  margin-left: 6px;
  font-weight: 400;
}
/* A heading that opens a card already has the card's padding above it. */
.card > h2:first-child {
  margin-top: 0;
}

/* Figures, set calmly: a sentence-case caption over one tabular number,
   on a quiet surface with no frame. The number is the only loud thing. */
.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px;
  margin-bottom: 8px;
}

.tile {
  background: var(--bg-elevated);
  border: 1px solid transparent;
  border-radius: var(--radius);
  padding: 16px 18px 18px;
}
.tile .label {
  color: var(--text-muted);
  font-size: 0.85rem;
  font-weight: 400;
  line-height: 1.35;
}
.tile .value {
  font-size: 1.75rem;
  font-weight: 600;
  margin-top: 6px;
  line-height: 1.15;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.tile .sub {
  color: var(--text-muted);
  font-size: 0.75rem;
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
}

/* Hand Stats: one fixed grid for every section, so tiles line up from
   one section to the next. Wide enough that "26,225/75,585 hands" never
   wraps. */
.tiles-compact {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 721px) {
  .tiles-compact {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}
.tile-feature {
  grid-column: span 2;
}
.tile .sub + .sub {
  margin-top: 0;
}

/* A card right under a row of tiles: with the tiles' own bottom margin,
   the same 14px apart as the tiles themselves. */
.follow-tiles {
  margin-top: 6px;
}

/* A global stat's flag beside its value: "High" or "Low" against its
   target window (red, like the value), or "Few spots" when too thin to
   judge. On a phone's half-width tile the flag may drop under the value,
   flush with it. */
.value-flagged {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
}
.target-flag {
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--negative-soft);
  color: var(--negative-text);
  font-size: 0.72rem;
  font-weight: 600;
  line-height: 1.5;
}
.target-flag-thin {
  background: var(--bg-elevated-2);
  color: var(--text-muted);
}
/* Hand Stats with "Show targets" off: every judged figure plain. */
.targets-off .target-judged {
  color: var(--text);
}
/* A table cell's miss, beside its figure: ↑ over the window, ↓ under. */
.target-arrow {
  margin-left: 2px;
  font-weight: 600;
}
.targets-off .target-flag,
.targets-off .target-arrow,
.targets-off .target-window {
  display: none;
}
#line-table th[scope="row"] {
  color: var(--text);
  font-size: 0.92rem;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
  white-space: nowrap;
}
#line-table td {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.rate-count {
  margin-left: 8px;
  color: var(--text-muted);
  font-size: 0.8rem;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* bb/100's 95% confidence interval: shaded range, observed value, zero. */
.ci-bar {
  position: relative;
  height: 8px;
  margin: 14px 0 8px;
  border-radius: 999px;
  background: var(--bg-elevated-2);
}
.ci-range {
  position: absolute;
  top: 0;
  bottom: 0;
  border-radius: 999px;
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.ci-zero,
.ci-point {
  position: absolute;
  transform: translateX(-50%);
  border-radius: 1px;
}
.ci-zero {
  top: -4px;
  bottom: -4px;
  width: 2px;
  background: var(--text-muted);
}
.ci-point {
  top: -3px;
  bottom: -3px;
  width: 4px;
  background: var(--text);
}
.ci-range-label {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: 0.8rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.section-gap {
  margin-top: 24px;
}

.positive {
  color: var(--positive);
}
.negative {
  color: var(--negative-text);
}

.card {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px 22px;
  margin-bottom: 16px;
}

/* The hand review's tournament card with its Luck tile at its side, the
   two the same height; on a narrow screen the tile drops under the card
   and takes the full width. */
.review-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin-bottom: 16px;
}
.review-summary > .card {
  flex: 999 1 520px;
  min-width: 0;
  margin-bottom: 0;
}
.review-summary > .tile {
  flex: 1 0 200px;
}

/* Wraps a table that may be wider than its card on a narrow phone screen —
   the table scrolls horizontally within this box instead of overflowing
   the card (or the page). */
.table-scroll {
  /* The containing block for the visually-hidden text in its cells: without
     it those absolutely placed spans escaped the scroller and widened the
     whole page on a phone (the Opponents table did). */
  position: relative;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}
th, td {
  text-align: left;
  padding: 11px 12px;
  border-bottom: 1px solid var(--border);
}
td {
  font-variant-numeric: tabular-nums;
}
th {
  color: var(--text-muted);
  font-weight: 400;
  font-size: 0.82rem;
}
tr:last-child td,
tbody tr:last-child th {
  border-bottom: none;
}
.badge {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
}
/* How a tournament finished, as one ladder rather than good and bad
   colours: busting is the ordinary end of a tournament, not a red mark
   against the evening, and the accent simply gets louder the deeper the
   run went. Gold stays for a win — rare enough to be news. */
.badge-bust { background: var(--bg-elevated-2); color: var(--text-muted); }
.badge-itm { background: var(--accent-soft); color: var(--accent-text); }
.badge-final_table { background: var(--accent-soft); color: var(--accent-text); }
.badge-top_3 { background: var(--accent-strong); color: var(--on-accent); }
.badge-runner_up { background: var(--accent-strong); color: var(--on-accent); }
.badge-win { background: var(--gold); color: var(--on-gold); }

.tournament-id {
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  font-size: 0.82rem;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.copy-btn {
  background: var(--bg-elevated-2);
  border: 1px solid var(--border);
  color: var(--text-muted);
  border-radius: 6px;
  padding: 2px 8px;
  font-size: 0.72rem;
  cursor: pointer;
}
.copy-btn:hover {
  color: var(--text);
  border-color: var(--accent);
}
.copy-btn.copied {
  color: var(--positive);
  border-color: var(--positive);
}

/* --- calendar --- */
/* A light month: an empty day is only its number, a played day is a soft
   tile with the count. No box around every day. */
.calendar {
  border-collapse: separate;
  border-spacing: 4px;
  width: 100%;
  /* Fixed layout keeps the 7 columns pinned to equal width whatever is
     inside them, so a long cell never widens the table past its card. */
  table-layout: fixed;
}
.calendar th {
  text-align: center;
  padding: 2px 0 8px;
  border-bottom: 0;
  font-size: 0.8rem;
}
.calendar td {
  border: 0;
  border-radius: 10px;
  background: transparent;
  height: 64px;
  width: 14.28%;
  vertical-align: top;
  padding: 8px 10px;
  font-size: 0.82rem;
  overflow-wrap: break-word;
}
.calendar td.empty {
  background: transparent;
}
.calendar td.has-sessions {
  background: var(--bg-elevated-2);
  cursor: pointer;
  transition: box-shadow 0.12s, background-color 0.25s ease-out;
}
.calendar td.has-sessions:hover {
  box-shadow: inset 0 0 0 1px var(--accent-text);
}
.calendar .day-num {
  color: var(--text-muted);
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
}
.calendar td.has-sessions .day-num {
  color: var(--text);
  font-weight: 600;
}
/* How much was played that day. One colour: a day is a day whether it
   went well or badly. */
.calendar .day-count {
  margin-top: 6px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.calendar .day-count span {
  font-weight: 400;
  font-size: 0.75rem;
  color: var(--text-muted);
}
/* The played day under the pointer lights up in the shade of how much was
   played (CALENDAR_VOLUME_STEPS), one day at a time; a keyboard reaching a
   day's session links lights it the same way. At rest the month stays one
   quiet surface. On a shade the muted text takes the text colour. */
.calendar td.volume-1 {
  --volume: var(--volume-1);
}
.calendar td.volume-2 {
  --volume: var(--volume-2);
}
.calendar td.volume-3 {
  --volume: var(--volume-3);
}
.calendar td.volume-4 {
  --volume: var(--volume-4);
}
.calendar td.has-sessions:is(:hover, :focus-within) {
  background-color: var(--volume, var(--bg-elevated-2));
  transition-duration: 0.12s, 0.15s;
}
.calendar .day-count span,
.calendar td a {
  transition: color 0.25s ease-out;
}
.calendar td.has-sessions:is(:hover, :focus-within) :is(.day-count span, a) {
  color: var(--text);
  transition-duration: 0.15s;
}
.calendar td.has-sessions:is(:hover, :focus-within) a {
  text-decoration: underline;
}
.calendar-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}
.calendar-nav h2 {
  margin: 0;
}
.calendar-nav a {
  display: inline-grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-muted);
  font-size: 1.05rem;
  transition: color 0.15s, background 0.15s;
}
.calendar-nav a:hover {
  color: var(--text);
  background: var(--bg-elevated-2);
  text-decoration: none;
}

/* --- filters / forms --- */
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: end;
  margin-bottom: 18px;
}
.filters label {
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-size: 0.78rem;
  font-weight: 500;
  color: var(--text-muted);
}
.filters select,
.filters input,
.filters .tfilter-summary {
  background: var(--bg-elevated-2);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 8px;
  padding: 7px 9px;
  font-size: 0.88rem;
}
/* One height for every text-like control, so a row of mixed fields lines up. */
.filters select,
.filters input:not([type="checkbox"]):not([type="radio"]),
.filters .btn,
.filters .tfilter-summary {
  min-height: 38px;
}
.filters select,
.filters .tfilter-summary {
  appearance: none;
  padding-right: 30px;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5L6 8l3.5-3.5' stroke='%2397a3bf' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 12px;
}
.filters select:hover,
.filters input:not([type="checkbox"]):not([type="radio"]):hover,
.filters .tfilter-summary:hover {
  border-color: var(--border-hover);
}
.filters select:focus,
.filters input:not([type="checkbox"]):not([type="radio"]):focus,
.filters .tfilter-summary:focus-visible,
.filters .tfilter[open] .tfilter-summary {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.filters input[type="checkbox"] {
  accent-color: var(--accent);
}
/* A buy-in is a few digits; at the browser's default width the two of
   them pushed Apply off the row. */
.filters input[type="number"] {
  width: 112px;
}
/* Room for "AKs, 77…" without clipping the hint. */
.filters .hand-class-field input {
  width: 128px;
}
.filters input::placeholder,
.coaching-form input::placeholder,
.coaching-form textarea::placeholder,
.live-form input::placeholder,
.replayer-form input::placeholder,
.coach-form textarea::placeholder,
.bounty-field input::placeholder {
  color: var(--text-placeholder);
  opacity: 1;
}
/* A caption over a row of checkboxes, set like a field's own label, with
   the row as tall as the fields beside it so everything shares a line. */
.filter-group {
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-size: 0.78rem;
  font-weight: 500;
  color: var(--text-muted);
}
.filter-group-checks {
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 38px;
}

.charts-grid {
  display: grid;
  /* min(480px, 100%) instead of a bare 480px — on a phone-width viewport a
     flat 480px minimum can't fit even one column, which used to force the
     whole grid (and the bars right at its edges) wider than the screen. */
  grid-template-columns: repeat(auto-fit, minmax(min(480px, 100%), 1fr));
  gap: 20px;
}
.chart-card canvas {
  max-height: 420px;
}
/* Three charts in a two-column grid: the one with the most bars (three per
   position) takes a whole row rather than leaving a gap beside the last. */
.chart-card-wide {
  grid-column: 1 / -1;
}

/* --- Hand Stats trend card --- */
.trend-controls {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--border);
}
.trend-field {
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}
.trend-field[hidden] {
  display: none;
}
.trend-field legend {
  padding: 0;
  margin-bottom: 8px;
  font-size: 0.78rem;
  font-weight: 500;
  color: var(--text-muted);
}
.trend-stat-groups {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 32px;
}
.trend-stat-group {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 12px;
  min-width: 0;
}
.trend-group-label {
  min-width: 72px;
  color: var(--text-muted);
  font-size: 0.82rem;
  font-weight: 400;
}
.trend-settings {
  display: flex;
  flex-wrap: wrap;
  gap: 16px 32px;
}

/* A choice between a few options, all visible: the checked one is raised
   off the track. The radio stays in the accessibility tree (see .tag-chip). */
.segmented {
  display: inline-flex;
  gap: 2px;
  max-width: 100%;
  padding: 3px;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: var(--bg);
  overflow-x: auto;
  scrollbar-width: none;
}
.segmented label {
  display: flex;
  cursor: pointer;
}
.segmented input {
  position: absolute;
  width: 0;
  height: 0;
  opacity: 0;
}
.segmented span {
  padding: 6px 14px;
  border-radius: 6px;
  color: var(--text-muted);
  font-size: 0.82rem;
  font-weight: 600;
  line-height: 1.25;
  white-space: nowrap;
  user-select: none;
  transition: background 0.15s ease-out, color 0.15s ease-out;
}
.segmented label:hover span {
  color: var(--text);
}
.segmented label:active span {
  background: var(--bg-elevated);
}
.segmented input:checked + span {
  background: var(--bg-elevated-2);
  color: var(--text);
  box-shadow: inset 0 0 0 1px var(--border-hover);
}
.segmented input:focus-visible + span {
  outline: 2px solid var(--accent-text);
  outline-offset: -2px;
}
.segmented input:disabled + span {
  opacity: 0.5;
  cursor: not-allowed;
}
.tag-chip input:active + span {
  background: var(--bg-elevated);
}

/* A short stroke in a series' color: the key for a line, in chips, the
   position key and nowhere as text color. */
.line-key {
  display: inline-block;
  width: 14px;
  margin-right: 7px;
  border-top: 2px solid var(--line-key, var(--accent));
  border-radius: 1px;
  vertical-align: middle;
  position: relative;
  top: -1px;
}
.line-key-in_position {
  --line-key: var(--series-2);
}
.line-key-out_of_position {
  --line-key: var(--series-3);
}
/* bb/100's halves in the colors poker trackers give them: showdown
   winnings green, the pots won or lost without one red. */
.line-key-showdown {
  --line-key: var(--positive);
}
.line-key-no_showdown {
  --line-key: var(--negative);
}
.line-key-ev {
  --line-key: var(--series-2);
  border-top-style: dashed;
}
.line-key-reference {
  --line-key: var(--text-muted);
  border-top-style: dashed;
}
.tag-chip input:not(:checked) + span .line-key {
  opacity: 0.4;
}

.trend-stage {
  padding-top: 20px;
  transition: opacity 0.2s ease-out;
}
.trend-card.is-loading .trend-stage {
  opacity: 0.5;
}
.trend-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 4px 16px;
  margin-bottom: 16px;
}
.trend-title {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.trend-title .muted {
  display: block;
  margin-top: 2px;
  font-size: 0.85rem;
  letter-spacing: 0;
}
.trend-key {
  display: flex;
  gap: 16px;
  margin: 0;
  color: var(--text-muted);
  font-size: 0.8rem;
}
.trend-key[hidden],
.trend-summary[hidden],
.trend-table[hidden] {
  display: none;
}
.trend-chart-box,
.result-chart-box {
  position: relative;
  height: 340px;
}
.trend-chart-box[hidden] {
  display: none;
}
.trend-multiples {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(240px, 100%), 1fr));
  gap: 12px;
}
.trend-multiples[hidden] {
  display: none;
}
.trend-panel {
  margin: 0;
  padding: 12px 12px 8px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
}
.trend-panel figcaption {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: -4px -4px 6px 2px;
  font-size: 0.88rem;
}
.trend-panel-meta {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
}
.trend-panel-name {
  font-weight: 600;
}
.trend-panel-value {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.trend-panel-value .muted {
  font-size: 0.78rem;
}
.trend-panel-box {
  position: relative;
  height: 148px;
}
.trend-tooltip {
  position: fixed;
  z-index: 30;
  top: 0;
  left: 0;
  min-width: 180px;
  padding: 10px 12px;
  border: 1px solid var(--border-hover);
  border-radius: 8px;
  background: var(--bg-elevated-2);
  box-shadow: var(--shadow-popover);
  font-size: 0.8rem;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s ease-out;
}
/* Inside the dialog, placed against the dialog rather than the viewport
   (see placeTooltip in handstats_trend.js). */
.trend-dialog .trend-tooltip {
  position: absolute;
}
.trend-tooltip:not(.is-visible) {
  visibility: hidden;
  transition: opacity 0.15s ease-out, visibility 0s 0.15s;
}
.trend-tooltip.is-visible {
  opacity: 1;
}
.trend-tooltip-title {
  margin-bottom: 6px;
  font-weight: 600;
}
.trend-tooltip-row {
  display: grid;
  grid-template-columns: auto auto auto 1fr;
  align-items: baseline;
  column-gap: 8px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.trend-tooltip-row + .trend-tooltip-row {
  margin-top: 4px;
}
.trend-tooltip-row .line-key {
  top: 0;
  align-self: center;
  margin-right: 0;
}
.trend-tooltip-row b {
  font-weight: 600;
}
.trend-tooltip-row .muted {
  text-align: right;
}

/* A square button holding only an icon; its aria-label names it. */
.icon-btn {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: color 0.15s ease-out, background 0.15s ease-out, border-color 0.15s ease-out;
}
.icon-btn:hover {
  border-color: var(--border);
  background: var(--bg-elevated-2);
  color: var(--text);
}
.icon-btn:active {
  background: var(--bg-elevated);
}
.icon-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.trend-dialog {
  width: min(960px, calc(100vw - 32px));
  max-width: none;
  max-height: calc(100dvh - 32px);
  padding: 0;
  border: 1px solid var(--border-hover);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  color: var(--text);
  box-shadow: var(--shadow-dialog);
}
.trend-dialog[open] {
  animation: dialog-in 0.2s ease-out;
}
.trend-dialog::backdrop {
  background: var(--backdrop);
}
.trend-dialog[open]::backdrop {
  animation: fade-in 0.2s ease-out;
}
@keyframes dialog-in {
  from {
    opacity: 0;
    transform: scale(0.98);
  }
}
@keyframes fade-in {
  from {
    opacity: 0;
  }
}
.trend-dialog-body {
  padding: 20px 24px 24px;
}
.trend-dialog-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 12px;
}
.trend-dialog-head h3 {
  margin: 0;
  font-size: 1.3rem;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.015em;
}
.trend-dialog-head p {
  margin: 2px 0 0;
  font-size: 0.88rem;
  font-variant-numeric: tabular-nums;
}
.trend-dialog-head .icon-btn {
  margin: -2px -6px 0 0;
}
.trend-dialog .trend-key {
  margin-bottom: 12px;
}
.trend-dialog-chart {
  position: relative;
  height: min(60vh, 460px);
}

.trend-message {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 72px 16px;
  color: var(--text-muted);
  text-align: center;
}
.trend-message[hidden] {
  display: none;
}
.trend-message p {
  margin: 0;
}
.trend-table {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
.trend-table summary {
  width: fit-content;
  border-radius: 4px;
  color: var(--text-muted);
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  transition: color 0.15s ease-out;
}
.trend-table summary:hover {
  color: var(--text);
}
.trend-table[open] summary {
  margin-bottom: 12px;
}
.trend-table .table-scroll {
  max-height: 440px;
  overflow-y: auto;
}
#trend-table th,
#trend-table td {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
#trend-table thead th {
  position: sticky;
  top: 0;
  background: var(--bg-elevated);
}
#trend-table tbody th {
  color: var(--text);
  font-size: 0.92rem;
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
}

.empty-state {
  color: var(--text-muted);
  text-align: center;
  padding: 40px 0;
}

.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin: 18px 0;
  color: var(--text-muted);
  font-size: 0.85rem;
}
.btn-page {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 34px;
  background: var(--bg-elevated-2);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 8px;
  padding: 0 12px;
  font: inherit;
  font-size: 0.85rem;
  cursor: pointer;
  transition: border-color 0.15s;
  /* 1 516 pages of global hands wrap the bar; "Prev" must not
     also wrap inside its own button. */
  white-space: nowrap;
}
.btn-page:hover:not(:disabled) {
  border-color: var(--accent);
}
.btn-page:disabled {
  color: var(--text-muted);
  cursor: default;
  opacity: 0.5;
}

/* Sign in: the form on the left, the replayer's felt as the one picture. */
.login-page {
  display: grid;
  align-items: center;
  min-height: calc(100dvh - 120px);
}
.login-wrap {
  width: 100%;
  max-width: 360px;
}
.login-wrap h1 {
  margin-bottom: 6px;
}
.login-lead {
  margin: 0 0 24px;
  color: var(--text-muted);
}
.login-wrap form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
/* Each field stacks its label over its input, so both inputs share one x. */
.login-wrap form > div {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.login-wrap label {
  font-size: 0.88rem;
  color: var(--text-muted);
}
.login-wrap input {
  width: 100%;
  min-height: 46px;
  background: var(--bg-elevated);
  border: 1px solid var(--border-hover);
  color: var(--text);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  font: inherit;
  font-size: 1rem;
  transition: border-color 0.15s ease-out, box-shadow 0.15s ease-out;
}
.login-wrap input:hover {
  border-color: color-mix(in srgb, var(--text-muted) 60%, var(--border-hover));
}
/* A ring as well as a border colour: a recoloured hairline alone was too
   faint a cue to see which field has the caret. */
.login-wrap input:focus {
  outline: 2px solid var(--accent-text);
  outline-offset: 1px;
  border-color: var(--accent);
}
.login-wrap .btn {
  margin-top: 4px;
  min-height: 46px;
}
.login-felt {
  display: none;
}
@media (min-width: 900px) {
  .login-page {
    grid-template-columns: minmax(0, 360px) minmax(0, 1fr);
    gap: 8vw;
    max-width: 1040px;
    margin: 0 auto;
    min-height: calc(100dvh - 104px);
  }
  .login-felt {
    position: relative;
    display: block;
    aspect-ratio: 16 / 10;
    border-radius: 999px;
    background: var(--felt);
    border: 1px solid var(--border);
  }
  .login-felt::before {
    content: "";
    position: absolute;
    inset: 16px;
    border-radius: inherit;
    border: 1px solid var(--felt-line);
  }
  .login-felt .pcards {
    position: absolute;
    left: 50%;
    top: 50%;
    gap: 10px;
    transform: translate(-50%, -50%);
  }
  .login-felt .pcard {
    flex-direction: column;
    width: 2.7em;
    min-width: 0;
    height: 3.65em;
    padding: 0;
    font-size: 1.5rem;
    line-height: 1;
    border-radius: 8px;
  }
  .login-felt .pcard i {
    font-size: 1.45em;
    line-height: 0.8;
  }
}
.btn {
  background: var(--accent-strong);
  color: var(--on-accent);
  border: 1px solid transparent;
  border-radius: 8px;
  padding: 10px 14px;
  font: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
  transition: filter 0.15s, border-color 0.15s, color 0.15s;
}
.btn:hover {
  filter: brightness(1.12);
}
.btn:active {
  transform: translateY(1px);
}
/* Undoing what you set is not the loudest thing on the page — the accent
   fill is for actions that do something, not for getting back to nothing. */
.btn-ghost {
  background: var(--bg-elevated-2);
  border: 1px solid var(--border);
  color: var(--text-muted);
}
.btn-ghost:hover {
  filter: none;
  border-color: var(--accent);
  color: var(--text);
}
.errorlist {
  color: var(--negative-text);
  padding-left: 18px;
  font-size: 0.85rem;
}

/* ---------- Hand review (tournament detail) ---------- */

.page-title {
  margin-bottom: 20px;
}

.notice {
  border-radius: var(--radius);
  padding: 12px 14px;
  margin: 14px 0;
  font-size: 0.9rem;
  line-height: 1.45;
}
.notice-warn {
  background: var(--warning-soft);
  border: 1px solid var(--warning-line);
  color: var(--warning-text);
}

.muted { color: var(--text-muted); font-weight: 400; }
.small { font-size: 0.82rem; }

/* Playing cards, drawn rather than imported: one span per card, suit
   glyph in an <i>. Sized in em so they scale with their context. */
/* Named .pcard, not .card: this stylesheet already has a .card for the
   app's content panels, and a second rule with that name silently
   repainted every panel on every page white. */
.pcards {
  display: inline-flex;
  gap: 3px;
  vertical-align: middle;
}
.pcard {
  display: inline-flex;
  align-items: center;
  gap: 1px;
  min-width: 2.15em;
  justify-content: center;
  padding: 3px 5px;
  border-radius: 4px;
  background: var(--card-face);
  color: var(--card-ink);
  font-weight: 600;
  font-size: 0.82rem;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
  box-shadow: 0 1px 2px rgba(3, 6, 14, 0.5);
}
.pcard i { font-style: normal; font-size: 0.95em; }
.pcard--spade { color: var(--suit-spade); }
.pcard--heart { color: var(--suit-heart); }
.pcard--diamond { color: var(--suit-diamond); }
.pcard--club { color: var(--suit-club); }

.hand {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
  margin-bottom: 10px;
}
/* A key hand (a point on the stack curve): ringed in the accent. */
.hand--key { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 55%, transparent); }
.hand--flash { animation: handflash 2s ease-out; }
@keyframes handflash {
  from { background: var(--accent-soft); }
  to { background: var(--bg-elevated); }
}

.hand-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.hand-head-left {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.hand-no { color: var(--text-muted); font-variant-numeric: tabular-nums; }
/* Hero's own two cards and the community board sit on the same line, so
   they need a divider — without one the eye reads seven cards as one hand. */
.hand-sep {
  width: 1px;
  align-self: stretch;
  min-height: 1.1em;
  background: var(--border);
  margin: 0 3px;
}
.hand-board .pcard { background: var(--card-face-board); }
.hand-net { font-weight: 600; font-variant-numeric: tabular-nums; }
.hand-net small {
  display: block;
  font-weight: 400;
  font-size: 0.75rem;
  color: var(--text-muted);
  text-align: right;
}

.hand-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 10px;
  margin-top: 8px;
  font-size: 0.8rem;
  color: var(--text-muted);
}
.badge-pos { background: var(--bg-elevated-2); color: var(--text); }
.badge-tag { background: var(--accent-soft); color: var(--accent-text); }
.badge-entry { background: var(--bg-elevated-2); color: var(--text); box-shadow: inset 0 0 0 1px var(--border-hover); }
/* On the global list every hand names the tournament it came from. It is a
   link, so it reads as one — but it sits in a row of muted metadata and
   must not shout over the hand itself. */
.hand-tournament {
  font-size: 0.78rem;
  font-weight: 600;
  max-width: 22em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hand-streets {
  margin-top: 8px;
  font-size: 0.84rem;
  display: grid;
  gap: 3px;
}
.street {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.street-name {
  text-transform: capitalize;
  font-size: 0.78rem;
  color: var(--text-muted);
  min-width: 4.2em;
}
.street-actions { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
.act b { color: var(--text-muted); font-weight: 600; }
.act--hero { color: var(--accent-text); }
.act--hero b { color: var(--accent-text); }
.act-sep { color: var(--border); }

/* Only rendered when there actually was a showdown — an almost-empty row
   just to right-align the pot size left an awkward gap on the ~60% of
   hands that never reach one. The pot moved up into .hand-meta instead. */
.hand-showdown {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--border);
  font-size: 0.82rem;
}
.showdown-label {
  text-transform: capitalize;
  font-size: 0.78rem;
  color: var(--text-muted);
  min-width: 4.2em;
}
.hand-showdown .shown { display: inline-flex; align-items: center; gap: 5px; }
.hand-showdown .shown b { color: var(--text-muted); font-weight: 600; }

/* The note row is on every hand, so it stays quiet until you engage with
   it: borderless fields that only look like inputs on hover/focus, or
   once they hold a note. */
.hand-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin-top: 9px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}
.note-form {
  /* Shared with the phone layout, which lines Save up with the fields. */
  --note-label-width: 44px;
  display: flex;
  /* Aligned to the top, not centred: once a note grows to several lines its
     label and the Save button belong beside its first line, not floating
     halfway down it. */
  align-items: flex-start;
  gap: 8px;
  flex: 1 1 320px;
  flex-wrap: nowrap;
  /* A flex item won't shrink below its content's natural width by
     default, and a textarea's is wide: at 375px that pushed Save off the
     card. This lets the textarea give way, down to its own min-width. */
  min-width: 0;
}
/* The player's note and the coach's: side by side once each can have
   240px, which a laptop-width card gives them, and stacked below that. */
.note-fields {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  flex: 1 1 auto;
  min-width: 0;
}
.note-field {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  flex: 1 1 240px;
  min-width: 0;
}
/* One width for both labels, so stacked fields start at the same x. The
   top padding sets the label on the textarea's first line (its border
   plus padding). */
.note-label {
  flex: none;
  width: var(--note-label-width);
  padding-top: 6px;
  font-size: 0.78rem;
  color: var(--text-muted);
  cursor: pointer;
}
.note-form textarea {
  flex: 1 1 auto;
  min-width: 120px;
  background: transparent;
  border: 1px solid transparent;
  color: var(--text);
  border-radius: 6px;
  padding: 5px 8px;
  font: inherit;
  font-size: 0.82rem;
  line-height: 1.45;
  /* One row when empty — nearly every hand — growing with its content up
     to this cap, after which it scrolls rather than pushing the rest of
     the list down the page. hand_list.js sets the height; resize is left
     on so a long note can still be pulled open by hand. */
  max-height: 11em;
  overflow-y: auto;
  /* No grab handle on the empty ones: it would put a corner mark on every
     row of a list that is almost entirely un-noted. Notes that exist get
     one, as an escape hatch past the max-height. */
  resize: none;
  transition: background 0.12s, border-color 0.12s;
}
.note-form textarea::placeholder { color: var(--text-placeholder); }
.note-form textarea:hover {
  border-color: var(--border);
}
.note-form textarea:focus {
  outline: none;
  background: var(--bg);
  border-color: var(--accent);
}
.note-field--filled textarea {
  background: var(--bg);
  border-color: var(--border);
  resize: vertical;
}
/* Save stays visible. It used to fade in on :focus-within to keep the
   list quiet, but clicking a <button> does not focus it on macOS, so the
   input blurred on mousedown, pointer-events:none came back, and the click
   was swallowed — the button was there and did nothing. */
.btn-small { padding: 6px 12px; font-size: 0.8rem; }
.note-status { font-size: 0.76rem; color: var(--text-muted); min-width: 3.2em; }
.note-status--error { color: var(--negative-text); font-weight: 600; }

/* The tournament's own review material, under its card: the replayer link
   and the export. One row on a laptop, where the link field takes whatever
   width is left; it wraps to stacked rows on a phone. */
.review-card {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 16px;
  padding: 12px 20px;
}
.replayer-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  flex: 1 1 360px;
}
.replayer-form label {
  font-size: 0.78rem;
  color: var(--text-muted);
}
.replayer-form input {
  flex: 1 1 200px;
  min-width: 0;
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 6px 9px;
  font-size: 0.85rem;
}
.replayer-form input:hover {
  border-color: var(--border-hover);
}
.replayer-form input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.replayer-form input[aria-invalid="true"] {
  border-color: var(--negative);
}
[data-replayer] [hidden] { display: none; }
a.btn {
  display: inline-block;
  text-decoration: none;
}
.btn:disabled {
  filter: none;
  opacity: 0.55;
  cursor: default;
  transform: none;
}

/* A hand's Winamax replayer link, in its foot: "Winamax replayer" once there is one,
   and a quiet toggle that unfolds the field to paste it into. Unfolded, it
   takes a full row at the bottom of the foot so a long link has room. */
.hand-replayer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
}
/* Unfolded: its own row, flush with the Review box above it. */
.hand-replayer:has(> .replayer-form:not([hidden])) {
  flex-basis: 100%;
  order: 1;
}
.hand-replayer .replayer-form {
  flex: 1 1 280px;
}
.hand-replayer .replayer-open,
.hand-replayer .replayer-request {
  font-size: 0.8rem;
  font-weight: 600;
}
/* A button that reads as a quiet text action rather than a filled control:
   no box of its own, so its text lines up with whatever sits above it. */
.link-btn {
  background: none;
  border: 0;
  border-radius: 4px;
  padding: 4px 0;
  font: inherit;
  font-size: 0.8rem;
  color: var(--text-muted);
  cursor: pointer;
  transition: color 0.15s;
}
.link-btn:hover {
  color: var(--text);
  text-decoration: underline;
}
.link-btn[aria-expanded="true"] {
  color: var(--text);
}
.link-btn:active {
  color: var(--accent-text);
}

/* An all-in is the one thing in an action log you must not have to infer
   from the numbers, so it gets a colour of its own rather than more grey. */
.act-allin {
  color: var(--negative-text);
  font-weight: 600;
  font-size: 0.78rem;
}
.act-equity {
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.replay-caption .act-equity::before {
  content: "\00a0· ";
}
/* In the log the odds take a line of their own under the street's cards. */
.replay-log .act-equity {
  display: block;
  margin-top: 4px;
  font-size: 0.8rem;
}

.hand-id code {
  font-size: 0.72rem;
  color: var(--text-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* --- tag chips (hand review filters) --- */

/* Its own full-width row inside the flex .filters bar: thirteen chips will
   not share a line with the selects, and the OR semantics read better as a
   labelled group than as one more field. */
.tagbar {
  flex-basis: 100%;
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}
.tagbar legend {
  padding: 0;
  font-size: 0.78rem;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.tagbar-hint {
  margin-left: 6px;
  color: var(--text-placeholder);
}
.tag-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.tag-chip {
  display: inline-flex;
  cursor: pointer;
}
/* The real checkbox is taken out of the layout rather than hidden with
   display:none, so it stays focusable and reachable by screen readers. */
.tag-chip input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.tag-chip span,
.tag-chip-clear {
  display: inline-block;
  padding: 5px 11px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--bg-elevated-2);
  color: var(--text-muted);
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1.25;
  user-select: none;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.tag-chip:hover span,
.tag-chip-clear:hover {
  border-color: var(--accent);
  color: var(--text);
}
.tag-chip input:checked + span {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-text);
}
/* Focus has to be drawn on the pill: the input it belongs to has no size. */
.tag-chip input:focus-visible + span {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.tag-chip-clear {
  cursor: pointer;
  font-family: inherit;
  border-style: dashed;
}
/* The shared pill rule above sets display, which outranks the user agent's
   [hidden] { display: none } — so the attribute has to be honoured here or
   Clear shows with nothing to clear (and a tag chip that belongs to the
   selected situation would sit in the bar alongside its own sub-filter). */
.tag-chip-clear[hidden],
.tag-chip[hidden] {
  display: none;
}

/* --- situation sub-filters --- */

/* Indented under the situation chips and hanging off a rule down the left,
   so a row of pills reads as "inside the situation above" rather than as a
   third independent group of tags. */
.subfilters {
  display: block;
  border: 0;
  border-left: 2px solid var(--border);
  margin: 8px 0 0 14px;
  padding: 2px 0 2px 12px;
  min-width: 0;
}
.subfilters[hidden] {
  display: none;
}
.subfilters-legend {
  padding: 0 0 6px;
  font-size: 0.74rem;
  color: var(--text-muted);
  opacity: 0.75;
}
.subfilter-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 6px;
}
.subfilter-row:last-child {
  margin-bottom: 0;
}
/* Fixed width so the dimension names line up when a situation has more
   than one row (only the cbet spot does today). */
.subfilter-label {
  flex: 0 0 62px;
  font-size: 0.74rem;
  color: var(--text-muted);
}

/* A checkbox beside its text, rather than under it like a field's label. */
.filters label.check {
  flex-direction: row;
  align-items: center;
  gap: 6px;
  cursor: pointer;
}
.review-link {
  margin-right: 10px;
  font-size: 0.82rem;
  font-weight: 600;
}

/* ---------- Tournament card ---------- */

.tcard-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.tcard-title {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  min-width: 0;
}
.tcard-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.badge-neutral {
  background: var(--bg-elevated-2);
  color: var(--text-muted);
}
/* Late reg is a fact about how the tournament was played, not a result, so
   it gets its own hue rather than sharing the muted neutral. */
.badge-latereg {
  background: var(--bg-elevated-2);
  color: var(--text);
}

.tcard-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 24px;
  margin: 12px 0 0;
}
.tcard-meta > div {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.tcard-meta dt {
  font-size: 0.78rem;
  color: var(--text-muted);
}
.tcard-meta dd {
  margin: 0;
  font-size: 0.92rem;
  font-variant-numeric: tabular-nums;
}
/* Net is the figure the eye should land on, so it is the only bold one and
   it is pushed to the end of the row on wide screens. */
.tcard-net {
  margin-left: auto;
  text-align: right;
}
.tcard-net dd {
  font-weight: 600;
  font-size: 1rem;
}

/* Pot carried into each postflop street, and each bet as a share of it. */
.street-pot {
  font-size: 0.72rem;
  color: var(--text-muted);
  background: var(--bg-elevated-2);
  border-radius: 4px;
  padding: 1px 6px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.act-pct { color: var(--text-muted); }

.hand-count {
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-bottom: 8px;
}
.page-links {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
}
.page-num {
  min-width: 34px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.page-num--current {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 34px;
  background: var(--accent-strong);
  color: var(--on-accent);
  border-radius: 8px;
  padding: 0 10px;
  font-size: 0.85rem;
  font-weight: 600;
}
.page-gap { color: var(--text-muted); padding: 0 2px; }

/* ---------- Tournament filter (hand review, every tournament) ---------- */

/* Shut, it reads like the selects beside it, at a fixed width so picking
   doesn't shift the rest of the row; open, the picker floats over the
   page under it. */
.tfilter {
  position: relative;
}
.filters .tfilter-summary {
  display: flex;
  align-items: center;
  width: 200px;
  list-style: none;
  transition: border-color 0.15s ease-out, box-shadow 0.15s ease-out;
}
.tfilter-summary::-webkit-details-marker {
  display: none;
}
.tfilter-value {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tfilter-panel {
  position: absolute;
  z-index: 15;
  top: calc(100% + 6px);
  left: 0;
  width: min(480px, calc(100vw - 32px));
  padding: 12px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-popover);
  /* Its own text, not the caption styling of the field it opens from. */
  font-size: 1rem;
  font-weight: 400;
  color: var(--text);
}
/* The filter bar sets its labels as captions stacked over a field; the
   picker's rows are labels too, and read as rows. */
.tfilter-panel .tpick-option {
  flex-direction: row;
  font-size: inherit;
  font-weight: 400;
  color: var(--text);
}
.tfilter-panel .tpick-list {
  max-height: 300px;
}

/* ---------- Opponents ---------- */

/* Twelve columns of numbers don't fit the 1100px column the rest of the
   app is written in. The whole page gets a wider one — title, filters and
   table together, so nothing goes out of alignment — never wider than the
   window's own gutter, so narrow screens are left exactly as they were. */
.wide-page {
  /* min(0px, …): the page only ever reaches outwards. Where the window is
     already narrower than the column, the gutter is the page's own. */
  margin-inline: min(0px, calc((100% - min(1200px, 100vw - var(--shell-side) - 56px)) / 2));
}

.opponent-count {
  margin: 0 0 12px;
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}
.opponent-table {
  font-variant-numeric: tabular-nums;
}
/* Child combinators throughout this block: an opened row's panel holds a
   table of its own, and none of the outer table's rules — sticky names,
   nowrap, the hover tint — should reach into it. */
.opponent-table > * > tr > th,
.opponent-table > * > tr > td {
  white-space: nowrap;
}
/* The row under the pointer, so a name and its numbers stay tied together
   across a table this wide. The pinned first cell has a background of its
   own and would otherwise stay behind while the rest of the row lit up. */
.opponent-table > tbody > tr {
  transition: background 0.15s ease-out;
}
.opponent-table > tbody > tr.opponent-row:not(.hero-row):hover,
.opponent-table > tbody > tr.opponent-row:not(.hero-row):hover > th[scope="row"] {
  background: var(--bg-elevated-2);
}

/* Hero's own line: the one every other row is read against, so it is
   tinted rather than hovering or sorting with them. Painted as the accent
   over the card's own colour, not as a translucent wash — the pinned first
   cell has the rest of the row scrolling under it. */
.opponent-table > tbody > .hero-row > td,
.opponent-table > tbody > .hero-row > th[scope="row"] {
  background: linear-gradient(var(--accent-soft), var(--accent-soft)),
    var(--bg-elevated);
  border-bottom-color: var(--accent);
}
.opponent-table > tbody > .hero-row > th[scope="row"],
.opponent-table > tbody > .hero-row > th[scope="row"] a {
  color: var(--accent-text);
}

/* Above or below hero's own figure for that column. The direction carries
   the meaning on its own; the colour only underlines it. */
.delta {
  display: inline-block;
  width: 0;
  height: 0;
  margin-left: 5px;
  vertical-align: 0.1em;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
}
.delta--above {
  border-bottom: 5px solid var(--positive);
}
.delta--below {
  border-top: 5px solid var(--negative-text);
}
.opponent-table > tbody > tr > th[scope="row"] {
  /* Stays put while the stats scroll past it: a row of percentages with
     no name against it is unreadable on a phone. */
  position: sticky;
  left: 0;
  background: var(--bg-elevated);
  color: var(--text);
  font-size: 0.9rem;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
  /* A nickname can run long; the table scrolls rather than the name
     pushing every stat off the screen. */
  max-width: 22ch;
  overflow: hidden;
  text-overflow: ellipsis;
}
.opponent-table > * > tr > td,
.opponent-table > thead > tr > th[scope="col"]:not(:first-child) {
  text-align: right;
}
.opponent-hands {
  font-weight: 600;
}
.opponent-seen,
.stat-sample {
  color: var(--text-muted);
}
/* The percentage reads first; the sample it rests on sits under it, so a
   60% over five spots can't pass for a 60% over two hundred. */
.stat-percent {
  display: block;
  font-weight: 600;
}
.stat-sample {
  display: block;
  font-size: 0.72rem;
}
.stat-empty {
  color: var(--text-muted);
}
.opponent-note {
  max-width: 68ch;
  margin: 20px 0 0;
  font-size: 0.85rem;
  line-height: 1.55;
}
.opponent-hint {
  margin: -6px 0 12px;
  font-size: 0.85rem;
}

/* --- One opponent, opened --- */

/* The name is the control. It keeps the cell's own look — a button here
   should read as a name, not as a button. */
.opponent-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.opponent-toggle:hover {
  color: var(--accent-text);
}
.opponent-toggle:focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: 3px;
  border-radius: 4px;
}
.opponent-caret {
  flex: none;
  width: 0;
  height: 0;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  border-left: 6px solid var(--text-muted);
  transition: transform 0.15s ease-out;
}
.opponent-row.is-open .opponent-caret {
  transform: rotate(90deg);
  border-left-color: var(--accent-text);
}
.opponent-row.is-open td,
.opponent-row.is-open th[scope="row"] {
  background: var(--bg-elevated-2);
}

.opponent-table .opponent-detail-row > td {
  padding: 0;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  /* The cell belongs to the table; everything inside it is a page. */
  text-align: left;
  white-space: normal;
}
/* Pinned to the left edge of the scroller and sized to it (opponents.js),
   so the panel stays where it can be read however far the table itself
   has been scrolled sideways. */
.opponent-panel {
  position: sticky;
  left: 0;
  padding: 20px 16px 24px;
  animation: panel-in 0.2s ease-out;
}
@keyframes panel-in {
  from {
    opacity: 0;
  }
}
.panel-head {
  margin-bottom: 16px;
}
.panel-head h3 {
  margin: 0;
  font-size: 1.15rem;
  letter-spacing: -0.01em;
}
.panel-head p {
  margin: 4px 0 0;
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}
.panel-tiles {
  margin-bottom: 20px;
}
.panel-tiles .value {
  font-size: 1.35rem;
}
/* Two tiles to a row on a phone, where several of these labels wrap: every
   label is given both lines, so the percentages read straight across. */
@media (max-width: 720px) {
  .panel-tiles .label {
    min-height: 3em;
    min-height: 2lh;
  }
}
.panel-charts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: 16px;
  margin-bottom: 4px;
}
.panel-charts h4 {
  margin: 0 0 12px;
  font-size: 0.88rem;
  font-weight: 400;
  color: var(--text-muted);
}
.panel-table {
  margin-bottom: 0;
}
.panel-table .position-table {
  font-variant-numeric: tabular-nums;
}
.panel-table th[scope="row"] {
  color: var(--text);
  font-size: 0.85rem;
}
.panel-table td,
.panel-table th[scope="col"]:not(:first-child) {
  text-align: right;
}
.panel-status {
  margin: 0;
  padding: 24px 0;
  color: var(--text-muted);
  font-size: 0.9rem;
}
.panel-status--error {
  color: var(--negative-text);
  display: flex;
  align-items: center;
  gap: 12px;
}

@media (prefers-reduced-motion: reduce) {
  .opponent-panel {
    animation: none;
  }
  .opponent-caret {
    transition: none;
  }
}

/* ---------- Bounty calculator ---------- */

.bounty-page {
  max-width: 860px;
  margin: 0 auto;
}
.bounty-card {
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding: 24px;
}

/* The formula, set like one: a rule between numerator and denominator
   rather than a slash, because that is the shape to remember. */
.formula {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 12px;
  /* Room for the caption hanging under the first fraction. */
  padding-bottom: 20px;
  font-size: 0.95rem;
  line-height: 1.3;
  text-align: center;
}
.formula--live {
  padding-bottom: 0;
}
.formula-lead {
  font-weight: 600;
}
.formula-op {
  color: var(--text-muted);
}
/* The caption sits under its fraction without making the group taller,
   so both fractions in the formula stay on the same line as each other. */
.formula-group {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.formula-brace {
  position: absolute;
  top: calc(100% + 4px);
  width: max-content;
}
.fraction {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
}
.fraction-top {
  padding: 0 10px 4px;
  border-bottom: 1px solid var(--border-hover);
}
.fraction-bottom {
  padding: 4px 10px 0;
}
/* What the first fraction actually is — the brace in the original. */
.formula-brace {
  max-width: 26ch;
  font-size: 0.76rem;
  color: var(--text-muted);
}
/* The same formula with the numbers in it, under the answer. */
.formula--live {
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}
.formula--live .fraction-top,
.formula--live .fraction-bottom {
  color: var(--text);
}

.bounty-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}
.bounty-presets {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.bounty-preset {
  padding: 5px 11px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--bg-elevated-2);
  color: var(--text-muted);
  font: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1.25;
  cursor: pointer;
  transition: background 0.15s ease-out, color 0.15s ease-out, border-color 0.15s ease-out;
}
.bounty-preset:hover {
  border-color: var(--accent);
  color: var(--text);
}
.bounty-preset:focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: 2px;
}
.bounty-preset:active {
  background: var(--bg-elevated);
}
.bounty-preset[aria-pressed="true"] {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-text);
}
.bounty-preset:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
  .bounty-preset {
    transition: none;
  }
}
.bounty-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 16px;
}
.bounty-field {
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-muted);
}
.bounty-field input {
  width: 100%;
  min-height: 42px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  padding: 8px 12px;
  font: inherit;
  font-size: 1.05rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  transition: border-color 0.15s ease-out, box-shadow 0.15s ease-out;
}
.bounty-field input:hover {
  border-color: var(--border-hover);
}
.bounty-field input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.bounty-hint {
  font-size: 0.76rem;
  font-weight: 400;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* The answer, which is what the page is for. */
.bounty-result {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}
.bounty-value {
  display: flex;
  align-items: baseline;
  gap: 8px;
  color: var(--text-muted);
}
.bounty-value strong {
  font-size: 2.6rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--accent-text);
  font-variant-numeric: tabular-nums;
}

/* Keeping one. A row of its own under the answer: the pseudo, the button
   and whatever the save had to say. */
.bounty-save {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px 16px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}
.bounty-field--pseudo {
  flex: 1 1 220px;
}
.bounty-field--pseudo input {
  font-size: 1rem;
}
.bounty-save .btn {
  min-height: 42px;
}
.bounty-save-status {
  flex: 1 1 100%;
  margin: 0;
  min-height: 1.2em;
  font-size: 0.82rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.bounty-table {
  font-variant-numeric: tabular-nums;
}
/* The saved bounties: the answer is what the eye goes to, the table it
   came from is the small print beside it. */
.bounty-history-bb {
  color: var(--accent-text);
  font-weight: 600;
}
.bounty-history-table,
.bounty-history-when {
  color: var(--text-muted);
  font-size: 0.82rem;
}
/* A chip count must not break between its thousands — the table scrolls
   inside its own box instead (.table-scroll). */
.bounty-table th,
.bounty-table td {
  white-space: nowrap;
}
.bounty-table th[scope="row"] {
  color: var(--text);
  font-size: 0.85rem;
  text-transform: none;
  letter-spacing: 0;
  white-space: nowrap;
}
.bounty-table td {
  text-align: right;
}
.bounty-table th[scope="col"] {
  text-align: right;
}
.bounty-table th[scope="col"]:first-child {
  text-align: left;
}
.bounty-page h3 {
  margin: 0 0 12px;
  font-size: 0.95rem;
  font-weight: 600;
}

/* ---------- Coaching ---------- */

/* A page title with its main action on the same line. */
.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 16px;
  margin-bottom: 20px;
}
.page-head h1 {
  margin: 0;
}

/* Undoing something that can't be undone: quiet until pointed at, and
   red rather than the accent that marks actions which make things. */
.btn-danger {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--negative-text);
}
.btn-danger:hover {
  filter: none;
  border-color: var(--negative);
  background: var(--negative-soft);
}

/* One session in the list. */
.coaching-session {
  padding: 20px 24px;
}
/* Where a save lands: a brief wash so the eye finds the card. */
.coaching-session:target {
  animation: handflash 2s ease-out;
}
.cs-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 16px;
}
.cs-heading {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 12px;
}
.cs-heading h2 {
  margin: 0;
  font-size: 1.15rem;
  font-weight: 600;
}
.cs-coach {
  color: var(--text-muted);
}
.cs-body {
  display: grid;
  gap: 24px;
}
@media (min-width: 900px) {
  .cs-body--split {
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    gap: 32px;
  }
}
.cs-main {
  display: flex;
  flex-direction: column;
  gap: 20px;
  min-width: 0;
}
.coaching-session h3 {
  margin: 0 0 8px;
  font-size: 0.88rem;
  font-weight: 400;
  color: var(--text-muted);
}
.cs-count {
  margin-left: 4px;
  font-variant-numeric: tabular-nums;
}
.cs-points {
  display: grid;
  gap: 6px;
  margin: 0;
  padding-left: 22px;
  line-height: 1.55;
}
/* A pasted replayer link is one long word: break it rather than let it
   run under the tournaments column. */
.cs-points,
.cs-notes {
  overflow-wrap: anywhere;
}
.cs-points li {
  padding-left: 4px;
}
.cs-points li::marker {
  color: var(--accent-text);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.cs-notes {
  font-size: 0.95rem;
  line-height: 1.6;
}
.cs-notes p {
  margin: 0 0 10px;
}
.cs-notes p:last-child {
  margin-bottom: 0;
}
.cs-blank {
  margin: 0;
  color: var(--text-muted);
}
.cs-aside {
  min-width: 0;
}
.cs-tournaments {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
}
.cs-tournaments li {
  display: grid;
  gap: 2px;
  padding: 10px 12px;
  border-top: 1px solid var(--border);
}
.cs-tournaments li:first-child {
  border-top: 0;
}
.cs-tournaments a {
  font-weight: 600;
  overflow-wrap: anywhere;
}
.cs-tmeta {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 0.82rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.cs-empty {
  padding: 48px 24px;
  text-align: center;
}
.cs-empty h2 {
  margin: 0 0 8px;
}
.cs-empty p {
  max-width: 46ch;
  margin: 0 auto 20px;
  color: var(--text-muted);
}

/* The form: one narrow column, centred, title included. */
.coaching-form-page {
  max-width: 760px;
  margin: 0 auto;
}
.back-link {
  display: inline-block;
  margin-bottom: 8px;
  font-size: 0.85rem;
  color: var(--text-muted);
}
.back-link::before {
  content: "\2190\00a0" / "";
}
.back-link:hover {
  color: var(--text);
  text-decoration: none;
}
.coaching-form {
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding: 24px;
}
.coaching-form .errorlist {
  list-style: none;
  margin: 0;
  padding: 0;
}
.form-row {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}
.form-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1 1 240px;
  min-width: 0;
}
.form-field--date {
  flex: 0 1 200px;
}
.form-field label {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-muted);
}
.form-section {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
  padding-top: 24px;
  border-top: 1px solid var(--border);
}
.form-section-title {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.01em;
}
.form-hint {
  margin: -4px 0 0;
  font-size: 0.85rem;
  color: var(--text-muted);
}
.coaching-form input[type="text"],
.coaching-form input[type="date"],
.coaching-form input[type="search"],
.coaching-form textarea {
  width: 100%;
  min-height: 40px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  padding: 8px 12px;
  font: inherit;
  font-size: 0.95rem;
  line-height: 1.4;
  transition: border-color 0.15s ease-out, box-shadow 0.15s ease-out;
}
.coaching-form textarea {
  min-height: 140px;
  line-height: 1.55;
  resize: vertical;
}
.coaching-form input::placeholder,
.coaching-form textarea::placeholder {
  color: var(--text-muted);
  opacity: 0.8;
}
.coaching-form input:hover,
.coaching-form textarea:hover {
  border-color: var(--border-hover);
}
.coaching-form input:focus,
.coaching-form textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.coaching-form input[aria-invalid="true"],
.coaching-form textarea[aria-invalid="true"] {
  border-color: var(--negative);
}

/* Picked tournaments, under the list: a caption beside them, or above
   them on a phone. */
.tpicked {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 12px;
  margin-top: 4px;
}
.tpicked-title {
  margin: 0;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-muted);
}
.tchips {
  display: flex;
  flex-wrap: wrap;
  flex: 1 1 0;
  min-width: 0;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.tchips[hidden] {
  display: none;
}
.tchip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  max-width: 100%;
  padding: 3px 3px 3px 12px;
  border-radius: 999px;
  background: var(--accent-soft);
  font-size: 0.85rem;
}
.tchip-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}
.tchip-date {
  white-space: nowrap;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.tchip .icon-btn {
  width: 26px;
  height: 26px;
  border-radius: 999px;
}
.tchips-empty {
  margin: 0;
  font-size: 0.85rem;
  color: var(--text-muted);
}
/* A "Select all": a rule rather than one tournament, so outlined rather
   than filled. */
.tchip--search {
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* The list to pick them from. */
.tpick {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.tpick-bar {
  display: flex;
  align-items: center;
  gap: 12px;
}
.tpick-search {
  flex: 1 1 auto;
}
.tpick-status {
  font-size: 0.82rem;
  color: var(--text-muted);
  white-space: nowrap;
}
.tpick-status:empty {
  display: none;
}
.tpick-status--error {
  color: var(--negative-text);
}
.tpick-results,
.reloadable {
  transition: opacity 0.15s ease-out;
}
.tpick-results[aria-busy="true"],
.reloadable[aria-busy="true"] {
  opacity: 0.55;
}
.tpick-list {
  max-height: 344px;
  overflow-y: auto;
  margin: 0;
  padding: 4px;
  list-style: none;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.tpick-option {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 10px;
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.15s ease-out;
}
.tpick-option:hover {
  background: var(--bg-elevated-2);
}
.tpick-option:has(input:checked) {
  background: var(--accent-soft);
}
.tpick-option input {
  flex: none;
  width: 16px;
  height: 16px;
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
}
/* Covered by a "Select all": ticked and locked until that rule goes. */
.tpick-option:has(input:disabled),
.tpick-option input:disabled {
  cursor: default;
}
.tpick-option input:focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: 2px;
}
.tpick-main {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-width: 0;
}
.tpick-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.92rem;
  font-weight: 600;
}
.tpick-meta {
  font-size: 0.8rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.tpick-net {
  white-space: nowrap;
  font-size: 0.85rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.tpick-more {
  margin: 0;
  font-size: 0.82rem;
  color: var(--text-muted);
}
/* "Select all": the one action in the line, so it reads as one. */
.tpick-more .link-btn {
  margin-left: 4px;
  padding: 0;
  font-size: inherit;
  font-weight: 600;
  color: var(--accent-text);
}
.tpick-more .link-btn:disabled {
  color: var(--text-muted);
  text-decoration: none;
  cursor: default;
}
.tpick-empty {
  margin: 0;
  padding: 24px 16px;
  border: 1px dashed var(--border);
  border-radius: 8px;
  text-align: center;
  font-size: 0.88rem;
  color: var(--text-muted);
}

/* Key points, numbered the way the list page shows them. */
.points {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: point;
}
.point-row {
  display: flex;
  align-items: center;
  gap: 8px;
  counter-increment: point;
}
.point-row::before {
  content: counter(point);
  flex: none;
  width: 20px;
  text-align: right;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--accent-text);
  font-variant-numeric: tabular-nums;
}
.points-add {
  align-self: flex-start;
  margin-left: 28px;
  font-size: 0.85rem;
}
.points-add::before {
  content: "+\00a0";
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
}
.form-actions .btn-danger {
  margin-right: auto;
}

/* ---------- Phones ---------- */

@media (max-width: 720px) {
  main {
    padding: 20px 16px 40px;
    padding-left: max(16px, env(safe-area-inset-left));
    padding-right: max(16px, env(safe-area-inset-right));
  }

  h1 {
    font-size: 1.5rem;
  }
  /* Under the title on a phone rather than wrapping beside it. */
  .h1-sub,
  h1 small {
    display: block;
    margin: 4px 0 0;
    font-size: 0.62em;
  }
  .card {
    padding: 14px;
  }
  .tile {
    padding: 13px 14px;
  }
  .tile .value {
    font-size: 1.35rem;
  }

  /* Two fields per row instead of a ragged wrap. */
  .filters {
    gap: 10px;
  }
  .filters > label,
  .filters > .filter-group {
    flex: 1 1 calc(50% - 5px);
    min-width: 0;
  }
  /* A row of its own, and the panel as wide as the bar: in half a row it
     would open off the edge of the screen. */
  .filters > .tfilter-field {
    flex-basis: 100%;
  }
  .filters .tfilter-summary {
    width: 100%;
  }
  .tfilter-panel {
    width: 100%;
  }
  .filters > label:not(.check) select,
  .filters > label:not(.check) input {
    width: 100%;
  }
  .filters > .btn {
    flex: 1 1 100%;
  }
  /* A whole row to tap, not just the box and its word. */
  .filters > label.check {
    flex: 1 1 100%;
    min-height: 44px;
  }
  .trend-chart-box {
    height: 260px;
  }
  /* Nine positions of three bars each, with the legend above them. */
  .result-chart-box {
    height: 300px;
  }
  .trend-panel-box {
    height: 128px;
  }
  /* A touch-sized target, still inside the panel's header row. */
  .icon-btn {
    width: 36px;
    height: 36px;
  }
  .trend-dialog-body {
    padding: 16px;
  }
  .trend-dialog-chart {
    height: min(55vh, 360px);
  }
  .trend-settings {
    gap: 16px;
  }
  /* Narrow enough for the trend's five intervals to fit a 375px screen. */
  .segmented span {
    padding: 8px 10px;
  }
  /* Label over its pills, three to a row: both groups line up instead of
     one pill wrapping on its own. */
  .trend-stat-groups {
    flex-direction: column;
  }
  .trend-stat-group {
    display: block;
  }
  .trend-group-label {
    display: block;
    margin-bottom: 8px;
  }
  .trend-stat-group .tag-chips {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .trend-stat-group .tag-chip span {
    width: 100%;
    padding: 8px 6px;
    text-align: center;
  }

  /* 16px keeps iOS from zooming into a field on focus. */
  .filters select,
  .filters input,
  .replayer-form input,
  .login-wrap input,
  .note-form textarea {
    font-size: 16px;
  }
  .bounty-card {
    padding: 16px;
    gap: 20px;
  }
  /* Narrow enough that the formula wraps to two lines, where a caption
     hanging out of the flow would land on top of the line below it. */
  .formula {
    font-size: 0.88rem;
    gap: 8px;
    padding-bottom: 0;
  }
  .formula-group {
    gap: 4px;
  }
  .formula-brace {
    position: static;
    width: auto;
    max-width: none;
  }
  .bounty-value strong {
    font-size: 2.1rem;
  }
  /* 16px keeps iOS from zooming into a field on focus. */
  .bounty-field input {
    font-size: 16px;
  }
  .coaching-session {
    padding: 16px;
  }
  .coaching-form {
    padding: 16px;
  }
  .coaching-form input[type="text"],
  .coaching-form input[type="date"],
  .coaching-form input[type="search"],
  .coaching-form textarea {
    font-size: 16px;
  }
  .form-field--date {
    flex-basis: 100%;
  }
  /* Under their caption rather than beside it, so a name has the width. */
  .tpicked .tchips {
    flex-basis: 100%;
  }
  /* Save first and full width, where a thumb reaches it; Delete last. */
  .form-actions {
    flex-direction: column-reverse;
    align-items: stretch;
  }
  .form-actions .btn {
    text-align: center;
  }
  .form-actions .btn-danger {
    margin-right: 0;
  }
  /* Beside a 16px first line rather than a 13px one. */
  .note-label {
    padding-top: 8px;
  }
  /* Both notes take the card's full width — a column kept free for Save
     beside them left each field ~150px wide — and Save drops to its own
     row underneath, lined up with the fields rather than their labels. */
  .note-form {
    flex-wrap: wrap;
  }
  .note-fields {
    flex-basis: 100%;
  }
  .note-form > .btn {
    margin-left: calc(var(--note-label-width) + 8px);
  }

  /* Seven columns in ~310px: tighter cells, and a count that stays on one
     line instead of breaking away from its label. */
  .calendar {
    border-spacing: 2px;
  }
  .calendar td {
    height: 52px;
    padding: 4px 2px;
    border-radius: 6px;
    overflow: hidden;
  }
  .calendar .day-num {
    font-size: 0.66rem;
    padding-left: 2px;
  }
  .calendar .day-count {
    margin-top: 4px;
    font-size: 0.7rem;
    text-align: center;
    white-space: nowrap;
    overflow-wrap: normal;
  }
  /* "played" does not fit beside the count in a 40px cell; the number
     alone reads as what it is under a day. */
  .calendar .day-count span {
    display: none;
  }

  .pagination {
    gap: 8px;
  }
  .page-links {
    gap: 2px;
  }
  .copy-btn {
    padding: 5px 9px;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition: none !important;
    animation: none !important;
  }
}

/* --- AI coach -------------------------------------------------------------- */

.coach-layout {
  display: grid;
  gap: 16px;
  align-items: start;
}
@media (min-width: 900px) {
  .coach-layout {
    grid-template-columns: 260px minmax(0, 1fr);
    gap: 24px;
  }
}

.coach-side {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
}
.coach-knowledge {
  margin: 0;
  color: var(--text-muted);
  font-size: 0.875rem;
}
.coach-knowledge strong {
  color: var(--text);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.coach-channels {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  margin-top: 4px;
  font-variant-numeric: tabular-nums;
}
.coach-side-title {
  margin: 8px 0 0;
  font-size: 0.85rem;
  font-weight: 400;
  color: var(--text-muted);
}
.coach-threads {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 60vh;
  overflow-y: auto;
}
.coach-threads a {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 10px;
  border-radius: 8px;
  color: var(--text);
  font-size: 0.9rem;
  transition: background 0.15s;
}
.coach-threads a:hover {
  background: var(--bg-elevated);
  text-decoration: none;
}
.coach-threads a[aria-current="page"] {
  background: var(--accent-soft);
}
.coach-thread-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.coach-thread-date {
  flex: none;
  color: var(--text-muted);
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
}
@media (max-width: 899px) {
  /* On a phone the conversation comes first; past threads fold under it. */
  .coach-side {
    order: 2;
  }
  .coach-threads {
    max-height: 240px;
  }
}

.coach-chat {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}
.coach-messages {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-height: 160px;
}
@media (min-width: 900px) {
  /* A desk-sized thread scrolls in its own pane, the question box always in
     view; on a phone the page itself scrolls — never a scroller in a scroller. */
  .coach-messages {
    max-height: 65vh;
    overflow-y: auto;
    padding-right: 4px;
  }
}
.coach-msg {
  max-width: 100%;
  overflow-wrap: anywhere;
}
.coach-msg--user {
  align-self: flex-end;
  max-width: min(85%, 640px);
  padding: 10px 14px;
  border-radius: var(--radius);
  background: var(--bg-elevated-2);
}
.coach-msg--user p {
  margin: 0;
}
.coach-msg--assistant {
  padding: 4px 0;
  border-top: 1px solid var(--border);
}

.coach-md {
  line-height: 1.6;
}
.coach-md > :first-child {
  margin-top: 0;
}
.coach-md > :last-child {
  margin-bottom: 0;
}
.coach-md h2 {
  margin: 20px 0 8px;
  font-size: 1.05rem;
  letter-spacing: -0.01em;
}
.coach-md h3 {
  margin: 16px 0 6px;
  font-size: 0.95rem;
}
.coach-md p,
.coach-md ul,
.coach-md ol {
  margin: 8px 0;
}
.coach-md ul,
.coach-md ol {
  padding-left: 20px;
}
.coach-md li + li {
  margin-top: 4px;
}
.coach-md strong {
  font-weight: 600;
}
.coach-md code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.85em;
  padding: 1px 4px;
  border-radius: 4px;
  background: var(--bg-elevated-2);
}
.coach-md table {
  display: block;
  overflow-x: auto;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}
.coach-md th,
.coach-md td {
  padding: 4px 10px;
  border-bottom: 1px solid var(--border);
  text-align: left;
}
.coach-md .pcards {
  margin: 0 4px;
}

.coach-sources {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin: 16px 0 0;
  padding: 12px 0 0;
  border-top: 1px solid var(--border);
  list-style: none;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.coach-sources a {
  color: var(--accent);
  margin-right: 6px;
}
.coach-sources a:hover {
  text-decoration: underline;
}
.coach-sources a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.coach-empty {
  margin: auto 0;
  color: var(--text-muted);
}
.coach-empty h2 {
  margin: 0 0 8px;
  color: var(--text);
}
.coach-empty p {
  margin: 0;
  max-width: 60ch;
}
.coach-examples {
  list-style: none;
  margin: 16px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.coach-examples .link-btn {
  padding: 6px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
}
.coach-examples .link-btn:hover {
  border-color: var(--border-hover);
}

.coach-progress {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  color: var(--text-muted);
  font-size: 0.9rem;
}
.coach-progress[hidden] {
  display: none;
}
.coach-spinner {
  flex: none;
  width: 14px;
  height: 14px;
  border: 2px solid var(--border);
  border-top-color: var(--accent-text);
  border-radius: 50%;
  animation: coach-spin 0.8s linear infinite;
}
@keyframes coach-spin {
  to {
    transform: rotate(360deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .coach-spinner {
    animation: none;
    border-color: var(--accent-text);
  }
}
.coach-error {
  margin: 0;
  color: var(--negative-text);
  font-size: 0.9rem;
}

.coach-form {
  display: flex;
  gap: 8px;
  align-items: flex-end;
}
.coach-form textarea {
  flex: 1;
  min-width: 0;
  min-height: 48px;
  max-height: 40vh;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font: inherit;
  resize: vertical;
  transition: border-color 0.15s;
}
.coach-form textarea:hover {
  border-color: var(--border-hover);
}
.coach-form textarea:focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: 1px;
}
.coach-form textarea:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}
.coach-hint {
  margin: -8px 0 0;
  color: var(--text-muted);
  font-size: 0.8rem;
}
.coach-delete {
  margin: 0;
  text-align: right;
  font-size: 0.85rem;
}
.coach-setup {
  margin-bottom: 16px;
  border-color: var(--accent);
}
.coach-setup h2 {
  margin-top: 0;
}

/* ---------- Hand replayer ---------- */

.replay-head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-end;
  gap: 12px 24px;
  margin-bottom: 20px;
}
.replay-head h1 {
  margin: 0 0 4px;
}
.replay-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 16px;
  margin: 0;
  color: var(--text-muted);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}
.replay-meta .hand-net {
  font-weight: 600;
}
.replay-hands {
  display: flex;
  gap: 8px;
}
.replay-hands .btn-page:hover {
  text-decoration: none;
}

.replayer {
  display: grid;
  gap: 16px;
  margin-bottom: 16px;
}
@media (min-width: 980px) {
  .replayer {
    grid-template-columns: minmax(0, 1fr) 300px;
    align-items: start;
  }
}
.replay-stage {
  min-width: 0;
}

/* The table. Every seat, bet and the dealer button is placed from its own
   unit vector (--cx, --cy, set by hand_replay.js) times this breakpoint's
   radii, so the same markup lays out a portrait oval on a phone and a
   wide one on a laptop. */
.replay-table {
  --seat-rx: 41%;
  --seat-ry: 38%;
  --bet-rx: 24%;
  --bet-ry: 20%;
  position: relative;
  aspect-ratio: 16 / 10;
  margin: 0 auto;
  max-width: 820px;
  font-variant-numeric: tabular-nums;
}
/* The felt, lit from the middle, inside a dark rail. The seats sit on the
   rail, so its centre line is the seats' ellipse. */
.replay-felt {
  position: absolute;
  inset: 12% 9%;
  border-radius: 999px;
  background: radial-gradient(ellipse at 50% 40%, var(--felt-lit), var(--felt-edge) 75%);
  border: 12px solid var(--rail);
  box-shadow: 0 0 0 1px var(--felt-line), inset 0 0 0 1px var(--felt-line);
}
.replay-center {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
.replay-pot {
  min-height: 1.4em;
  padding: 2px 10px;
  border-radius: 6px;
  background: var(--rail);
  color: var(--text);
  font-size: 0.9rem;
  font-weight: 600;
}
.replay-pot:empty {
  visibility: hidden;
}

/* Cards in the replayer stand upright, rank over suit, the way a table
   shows them; the app's inline pcard stays a pill everywhere else.
   The suit glyph is the larger of the two so its colour reads at a glance. */
.replay-table .pcard {
  flex-direction: column;
  justify-content: center;
  gap: 1px;
  width: 2.7em;
  min-width: 0;
  height: 3.65em;
  padding: 0;
  font-size: 1.45rem;
  line-height: 1;
  border-radius: 7px;
}
.replay-table .pcard i {
  font-size: 1.45em;
  line-height: 0.8;
}
.replay-table .pcard--spade { color: var(--suit-spade); }
.replay-table .pcard--heart { color: var(--suit-heart); }
.replay-table .pcard--diamond { color: var(--suit-diamond); }
.replay-table .pcard--club { color: var(--suit-club); }
.replay-board .pcards {
  gap: 8px;
}
/* A card still to come: a dim back, the way the table deals them face down. */
.pcard--slot {
  background: var(--card-back);
  box-shadow: none;
  border: 1px solid var(--accent-soft);
  opacity: 0.55;
}
.pcard--back {
  background: var(--card-back);
  border: 1px solid var(--accent-soft);
}

.seat,
.seat-bet,
.dealer-btn {
  position: absolute;
  transform: translate(-50%, -50%);
}
.seat {
  left: calc(50% + var(--cx) * var(--seat-rx));
  top: calc(50% + var(--cy) * var(--seat-ry));
  z-index: 2;
  width: 112px;
  display: flex;
  flex-direction: column;
  align-items: center;
}
/* The seat itself: a disc on the rail, its position at the foot and the
   cards fanned over its top half. */
.seat-disc {
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: 64px;
  height: 64px;
  padding-bottom: 12px;
  border-radius: 50%;
  background: var(--seat-disc);
  border: 4px solid var(--rail);
  box-shadow: 0 0 0 1px var(--felt-line);
  transition: border-color 0.15s ease-out, box-shadow 0.15s ease-out;
}
.seat-pos {
  font-size: 0.72rem;
  font-weight: 600;
}
.seat-cards {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -62%);
}
.replay-table .seat-cards .pcard {
  font-size: 0.82rem;
}
.replay-table .seat--hero .seat-cards .pcard {
  font-size: 1.05rem;
}
.seat-cards .pcards {
  gap: 2px;
}
.seat-pod {
  position: relative;
  max-width: 100%;
  margin-top: -10px;
  padding: 2px 8px;
  border-radius: 6px;
  background: var(--rail);
  border: 1px solid var(--felt-line);
  text-align: center;
  line-height: 1.3;
  transition: border-color 0.15s ease-out, box-shadow 0.15s ease-out;
}
.seat-name {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--accent-text);
  font-size: 0.75rem;
}
.seat-stack {
  display: block;
  font-size: 0.8rem;
  font-weight: 600;
}
/* The seat's last move this street, under it, the way a table calls it. */
.seat-act {
  min-height: 1.3em;
  margin-top: 2px;
  color: var(--gold);
  font-size: 0.75rem;
  font-weight: 600;
}
.seat-act--won {
  color: var(--positive);
}
.seat--hero .seat-pod {
  border-color: var(--border-hover);
}
.seat--acting .seat-disc {
  border-color: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-soft), 0 0 18px var(--accent);
}
.seat--winner .seat-disc {
  border-color: var(--positive);
  box-shadow: 0 0 0 4px var(--positive-soft);
}
/* A folded seat keeps its disc, empty, and only its tab dims. */
.seat--folded .seat-pod,
.seat--folded .seat-pos {
  opacity: 0.5;
}
.seat-bet {
  left: calc(50% + var(--cx) * var(--bet-rx));
  top: calc(50% + var(--cy) * var(--bet-ry));
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.8rem;
  font-weight: 600;
  white-space: nowrap;
}
.seat-bet[hidden] {
  display: none;
}
/* A bet is a little stack of chips beside its amount. */
.seat-bet::before {
  content: "";
  width: 12px;
  height: 12px;
  margin-bottom: 4px;
  border-radius: 50%;
  background: var(--accent-text);
  box-shadow: 0 2px 0 var(--accent-strong), 0 4px 0 var(--accent-text);
}
.seat-bet--won {
  color: var(--positive);
}
/* An all-in's runout: each player's chance of winning, where the bets were. */
.seat-bet--equity {
  color: var(--accent-text);
  font-variant-numeric: tabular-nums;
}
.seat-bet--won::before,
.seat-bet--equity::before {
  display: none;
}
.dealer-btn {
  left: calc(50% + var(--cx) * var(--bet-rx) * 1.25);
  top: calc(50% + var(--cy) * var(--bet-ry) * 1.25);
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--text);
  color: var(--bg);
  font-size: 0.65rem;
  font-weight: 600;
}

.replay-caption {
  min-height: 1.5em;
  margin: 12px 0;
  text-align: center;
  font-size: 0.95rem;
}
.replay-caption .pcards {
  margin-left: 4px;
}
.replay-caption .pcard,
.replay-log .pcard {
  font-size: 1rem;
  gap: 3px;
  padding: 4px 6px;
}
.replay-caption .pcard i,
.replay-log .pcard i {
  font-size: 1.15em;
}

/* One bar under the table, every control in it. */
.replay-controls {
  display: flex;
  justify-content: space-around;
  align-items: center;
  gap: 8px;
  max-width: 520px;
  margin: 12px auto 0;
  padding: 6px;
  border-radius: var(--radius-sm);
  background: var(--rail);
  /* A second tap in a hurry is the next step. Without this, the phone
     treats it as a double-tap and zooms the page. Pinch zoom still works. */
  touch-action: manipulation;
}
.replay-btn {
  display: grid;
  place-items: center;
  width: 52px;
  height: 44px;
  padding: 0;
  border-radius: var(--radius-sm);
  background: none;
  border: 1px solid transparent;
  color: var(--text);
  cursor: pointer;
  touch-action: manipulation;
  transition: border-color 0.15s ease-out, background 0.15s ease-out;
}
.replay-btn svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  touch-action: manipulation;
}
.replay-btn svg .fill {
  fill: currentColor;
}
.replay-btn:hover:not(:disabled) {
  border-color: var(--accent);
}
.replay-btn:active:not(:disabled) {
  background: var(--bg-elevated-2);
}
.replay-btn:disabled {
  color: var(--text-muted);
  opacity: 0.45;
  cursor: default;
}
.replay-btn:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 2px;
}
.replay-btn--play {
  background: var(--accent-strong);
  border-color: transparent;
  color: var(--on-accent);
}
.replay-btn--play:hover:not(:disabled) {
  border-color: transparent;
  filter: brightness(1.12);
}
.replay-btn--play .icon-pause,
.replay-btn--play.is-playing .icon-play {
  display: none;
}
.replay-btn--play.is-playing .icon-pause {
  display: block;
}
.replay-count {
  display: block;
  margin-top: 8px;
  text-align: center;
  color: var(--text-muted);
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
}

.replay-options {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 12px 16px;
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
.replay-streets,
.replay-settings {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.replay-street {
  padding: 6px 12px;
  border-radius: 8px;
  background: none;
  border: 1px solid var(--border);
  color: var(--text-muted);
  font: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.15s ease-out, color 0.15s ease-out;
}
.replay-street:hover:not(:disabled) {
  color: var(--text);
  border-color: var(--border-hover);
}
.replay-street:active:not(:disabled) {
  background: var(--bg-elevated);
}
.replay-street[aria-current] {
  color: var(--text);
  background: var(--accent-soft);
  border-color: var(--accent);
}
.replay-street:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.replay-log {
  position: relative;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 12px;
}
@media (min-width: 980px) {
  .replay-log {
    max-height: 640px;
    overflow-y: auto;
  }
}
.replay-log h2 {
  margin: 0 0 8px 8px;
  font-size: 0.9rem;
  color: var(--text-muted);
  font-weight: 400;
}
.replay-log ol {
  margin: 0;
  padding: 0;
  list-style: none;
}
.log-row button {
  display: block;
  width: 100%;
  padding: 6px 8px;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--text-muted);
  font: inherit;
  font-size: 0.85rem;
  text-align: left;
  cursor: pointer;
  font-variant-numeric: tabular-nums;
}
.log-row button:hover {
  background: var(--bg-elevated-2);
  color: var(--text);
}
.log-row button[aria-current] {
  background: var(--accent-soft);
  color: var(--text);
}
.log-row--hero button {
  color: var(--text);
}
.log-row--street,
.log-row--showdown,
.log-row--win {
  margin-top: 8px;
}
.log-row--street button,
.log-row--showdown button,
.log-row--win button {
  color: var(--text);
  font-weight: 600;
}
.log-row .pcard {
  font-size: 1rem;
}

.replay-error h2 {
  margin-top: 0;
}
.replay-error p:last-child {
  margin-bottom: 0;
}
.replay-notes p {
  display: flex;
  gap: 12px;
  margin: 8px 0 0;
}
.replay-notes .note-label {
  padding-top: 0;
  cursor: default;
}
.replay-foot {
  margin-top: 8px;
}
.replay-foot .tournament-id {
  flex-wrap: wrap;
}
.replay-foot code {
  overflow-wrap: anywhere;
}

@media (max-width: 720px) {
  /* A portrait table, the seats on its rail and the bets on a ring
     inside them. */
  .replay-table {
    --seat-rx: 38%;
    --seat-ry: 41%;
    --bet-rx: 20%;
    --bet-ry: 24%;
    aspect-ratio: 4 / 5.4;
  }
  .replay-felt {
    inset: 9% 12%;
  }
  .seat-bet,
  .dealer-btn {
    z-index: 3;
  }
  .seat {
    width: 84px;
  }
  .seat-disc {
    width: 56px;
    height: 56px;
    padding-bottom: 10px;
  }
  .seat-pos {
    font-size: 0.68rem;
  }
  .seat-name,
  .seat-stack,
  .seat-bet,
  .seat-act {
    font-size: 0.72rem;
  }
  /* Opponents' face-down cards shrink to a token over their disc; yours
     stay readable. */
  .replay-table .seat-cards .pcard {
    font-size: 0.62rem;
  }
  .replay-table .seat--shown .seat-cards .pcard {
    font-size: 0.78rem;
  }
  .replay-table .seat--hero .seat-cards .pcard {
    font-size: 0.92rem;
  }
  .replay-table .replay-board .pcard {
    font-size: 1rem;
  }
  .replay-board .pcards {
    gap: 4px;
  }
  .replay-options {
    justify-content: center;
  }

  /* Thumbs, not a cursor: every control is at least 44px tall with room
     between neighbours, so a tap in a hurry lands on the step it meant. */
  .replay-hands {
    flex: 1 1 100%;
    gap: 12px;
  }
  .replay-hands .btn-page {
    flex: 1;
    min-height: 44px;
  }
  .replay-controls {
    gap: 4px;
  }
  .replay-btn {
    flex: 1 1 0;
    max-width: 64px;
    height: 48px;
  }
  .replay-btn svg {
    width: 20px;
    height: 20px;
  }
  .replay-options {
    gap: 12px;
  }
  .replay-streets {
    flex-wrap: nowrap;
    width: 100%;
  }
  .replay-street {
    flex: 1 1 0;
    min-width: 0;
    min-height: 44px;
    padding: 0 4px;
  }
  .replay-settings {
    justify-content: center;
    gap: 12px;
  }
  .replay-settings .segmented span {
    padding: 11px 12px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .seat-disc,
  .seat-pod,
  .replay-btn,
  .replay-street {
    transition: none;
  }
}

/* ---------- Live, beside the client ---------- */

.live-dash-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px 24px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.live-dash-head .page-title {
  margin-bottom: 0;
}
.live-refresh {
  margin: 0;
  color: var(--text-muted);
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
}
.live-refresh.is-error {
  color: var(--negative-text);
}

.live-dash-section {
  margin-top: 28px;
}
.live-dash-section:first-child {
  margin-top: 12px;
}
.live-dash-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px 16px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
.live-dash-section-head h2 {
  margin: 0;
}
.live-dash-section-head p {
  margin: 0;
}

.live-status {
  display: flex;
  align-items: center;
  margin: 0;
  color: var(--text-muted);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}
.live-dot {
  width: 8px;
  height: 8px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--positive);
  flex: none;
}
.live-dot--off {
  background: var(--border-hover);
}
@media (prefers-reduced-motion: no-preference) {
  .live-dot:not(.live-dot--off) {
    animation: live-pulse 1.8s ease-out infinite;
  }
}
@keyframes live-pulse {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--positive) 50%, transparent); }
  100% { box-shadow: 0 0 0 7px transparent; }
}

.live-tiles {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}
.live-tiles + .live-tiles {
  margin-top: 12px;
}
.live-tiles .tile .value {
  font-variant-numeric: tabular-nums;
}
.tile-sm .value {
  font-size: 1.25rem;
}
@media (min-width: 721px) {
  .live-tiles {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  .live-tiles--stats {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
@media (min-width: 1100px) {
  .live-tiles--stats {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
}

.live-table h3 {
  margin: 0;
  font-size: 1.15rem;
  letter-spacing: -0.015em;
}
.live-dash-empty h3 {
  margin: 0 0 8px;
  font-size: 1.05rem;
}
.live-dash-empty p {
  max-width: 62ch;
}
.live-table-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px 24px;
}
.live-table-title {
  min-width: 0;
}
.live-table-meta,
.live-table-sub,
.live-stack-sub {
  margin: 4px 0 0;
  color: var(--text-muted);
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
}
.live-table-sub {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 0;
  margin: 12px 0;
}
.live-sep {
  margin: 0 6px;
  color: var(--text-muted);
}
.live-stack {
  text-align: right;
  flex: none;
}
.live-stack-value {
  display: block;
  font-size: 1.8rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.live-stack-value small {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--text-muted);
}
.live-table.is-quiet .live-stack-value {
  color: var(--text-muted);
}

.live-dash-seats {
  font-variant-numeric: tabular-nums;
}
.live-dash-seats > * > tr > th,
.live-dash-seats > * > tr > td {
  vertical-align: top;
}
.live-dash-seats th.num,
.live-dash-seats td.num {
  text-align: right;
  white-space: nowrap;
}
.live-dash-seats th[scope="row"] {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--bg-elevated);
  color: var(--text);
  font-size: 0.92rem;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
  min-width: 9rem;
  max-width: 22rem;
}
.live-order {
  display: block;
  margin-top: 2px;
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-muted);
}
/* Name and tags on one line. */
.seat-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 6px;
}
.live-dash-seats .badge {
  margin: 0;
}
tr.is-sitting-out > th,
tr.is-sitting-out > td {
  color: var(--text-muted);
}
/* A glance, not a legend: the same tokens as the rest of the app. */
.badge-style--nit,
.badge-style--passive {
  background: var(--bg-elevated-2);
  color: var(--text-muted);
}
.badge-style--tag {
  background: var(--accent-soft);
  color: var(--accent-text);
}
.badge-style--lag {
  background: var(--positive-soft);
  color: var(--positive);
}
.badge-style--fish,
.badge-style--maniac {
  background: var(--negative-soft);
  color: var(--negative-text);
}

@media (max-width: 640px) {
  .live-table-head {
    flex-direction: column;
    gap: 8px;
  }
  .live-stack {
    text-align: left;
  }
  .live-stack-value {
    font-size: 1.5rem;
  }
}

/* Live hands: one column for writing a hand down, not a dashboard table. */
.live-page {
  max-width: 40rem;
  margin-inline: auto;
}
.live-page ::selection {
  background: var(--accent-soft);
  color: var(--text);
}
.live-lead {
  margin: -8px 0 28px;
  color: var(--text-muted);
  max-width: 38rem;
}
.live-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 16px;
  margin-bottom: 24px;
}
.live-head h1 {
  margin: 0;
}
.live-head .btn {
  min-height: 44px;
}
.live-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.live-implicit {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  border: 0;
}
.live-section {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding-top: 28px;
  margin-top: 12px;
  border-top: 1px solid var(--border);
}
.live-section h2 {
  margin: 0;
}
.live-section h3 {
  margin: 8px 0 0;
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.live-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}
.live-field label,
.live-allin {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-muted);
}
.live-form input[type="text"],
.live-form input[type="date"],
.live-form select {
  width: 100%;
  min-height: 44px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  padding: 8px 12px;
  font: inherit;
  font-size: 1rem;
  line-height: 1.4;
  caret-color: var(--accent-text);
  transition: border-color 0.15s ease-out;
}
.live-form input::placeholder {
  color: var(--text-muted);
  opacity: 0.85;
}
.live-form input:hover,
.live-form select:hover {
  border-color: var(--border-hover);
}
.live-form input:focus,
.live-form select:focus {
  outline: none;
  border-color: var(--accent);
}
.live-form input[aria-invalid="true"],
.live-form select[aria-invalid="true"] {
  border-color: var(--negative);
}
.live-cards {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: 0.02em;
}
.live-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
.live-new {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.live-new[hidden] {
  display: none;
}
.live-seats,
.live-street {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.live-seat,
.live-action {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
}
.live-seat--bad,
.live-action--bad {
  border-color: var(--negative);
}
.live-seat-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-height: 32px;
}
.live-seat-who {
  margin: 0;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.live-seat-grid,
.live-action-grid {
  display: grid;
  gap: 12px;
}
.live-field--wide {
  grid-column: 1 / -1;
}
.live-size {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.live-action[data-kind="fold"] .live-size,
.live-action[data-kind="check"] .live-size,
.live-action[data-kind=""] .live-size {
  display: none;
}
.live-blinds-field {
  display: none;
}
.live-action[data-entry="chips"] .live-percent-field,
.live-action[data-entry="percent"] .live-chips-field,
.live-action[data-entry="blinds"] .live-chips-field,
.live-action[data-entry="blinds"] .live-percent-field {
  display: none;
}
.live-action[data-entry="blinds"] .live-blinds-field,
.live-action[data-entry="blinds"] .live-size {
  display: flex;
}
.live-action[data-default="1"] {
  padding: 10px 12px;
  gap: 8px;
}
.live-action[data-default="1"] .live-action-grid {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
  align-items: end;
  gap: 8px;
}
.live-action[data-default="1"] .live-remove {
  grid-column: auto;
}
.live-action[data-kind="call"] .live-entry,
.live-action[data-kind="call"] .live-percent-field {
  display: none;
}
.live-action[data-kind="call"] .live-chips-field {
  display: flex;
}
.live-allin {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  color: var(--text);
  font-size: 0.95rem;
  font-weight: 600;
}
.live-allin input {
  width: 18px;
  height: 18px;
  accent-color: var(--accent-strong);
}
.live-remove {
  justify-self: start;
}
.live-save {
  margin-top: 8px;
}
.live-save .btn,
.live-form .btn {
  min-height: 44px;
}
.live-alert {
  padding: 14px 16px;
  border: 1px solid var(--negative);
  border-radius: var(--radius);
  background: var(--negative-soft);
}
.live-alert p {
  margin: 0 0 8px;
  font-weight: 600;
}
.live-alert ul {
  margin: 0;
  padding-left: 18px;
}
.live-alert li + li {
  margin-top: 4px;
}
.live-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--border);
}
.live-list-item {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  padding: 14px 0;
  border-bottom: 1px solid var(--border);
}
.live-list-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  color: var(--text);
}
.live-list-main:hover {
  text-decoration: none;
  color: var(--accent-text);
}
.live-list-title {
  font-weight: 600;
  letter-spacing: -0.01em;
}
.live-list-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  color: var(--text-muted);
  font-size: 0.92rem;
  font-variant-numeric: tabular-nums;
}
.live-list-main:hover .live-list-meta {
  color: var(--text-muted);
}
.live-empty p {
  color: var(--text-muted);
  margin: 0 0 16px;
}
.live-empty .btn {
  min-height: 44px;
}
@media (min-width: 480px) {
  .live-seat-grid {
    grid-template-columns: 1fr 1fr;
  }
  .live-action-grid {
    grid-template-columns: 1fr 1fr;
  }
  .live-size,
  .live-remove {
    grid-column: 1 / -1;
  }
}
@media (prefers-reduced-motion: reduce) {
  .live-form input,
  .live-form select {
    transition: none;
  }
}

/* ---------- Dashboard ---------- */

.dash-figures {
  display: grid;
  gap: 0 24px;
}
.dash-figures h2,
.dash-grid h2 {
  margin-top: 0;
}
.dash-figures section + section h2 {
  margin-top: 28px;
}
.dash-grid {
  display: grid;
  gap: 0 24px;
  margin-top: 36px;
}
.dash-grid section + section {
  margin-top: 28px;
}
.tiles-pair {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 721px) {
  .tiles-pair {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}
@media (min-width: 1200px) {
  .dash-figures {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .dash-figures section + section h2 {
    margin-top: 0;
  }
  .tiles-pair {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .dash-grid {
    grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr);
    align-items: start;
  }
  .dash-grid section + section {
    margin-top: 0;
  }
}
.calendar-card,
.session-card {
  margin-bottom: 0;
}
.session-card {
  padding: 6px 20px;
}
.session-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
/* The whole row answers a tap, not only the date's own text. */
.session-row {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 2px 12px;
  align-items: baseline;
  margin: 0 -20px;
  padding: 12px 20px;
  border-top: 1px solid var(--border);
  transition: background 0.15s ease-out;
}
.session-row:first-child {
  border-top: 0;
}
.session-row:hover {
  background: var(--bg-elevated-2);
}
.session-date {
  color: var(--text);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.session-date::after {
  content: "";
  position: absolute;
  inset: 0;
}
.session-row:hover .session-date {
  text-decoration: underline;
}
.session-date .muted {
  margin-left: 4px;
}
.session-roi {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.session-meta {
  color: var(--text-muted);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}
.session-best {
  text-align: right;
}

/* ---------- Hand list: the foot on a phone ---------- */

.copy-btn {
  white-space: nowrap;
}
.hand-id code {
  white-space: nowrap;
}
@media (min-width: 721px) {
  .hand-quick {
    display: none;
  }
  .hand-tools {
    display: contents;
  }
}
@media (max-width: 720px) {
  .hand {
    padding: 14px;
  }
  .hand-foot {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }
  .hand-quick {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
  }
  .hand-quick .btn {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 20px;
  }
  .hand-tools-toggle {
    min-height: 44px;
    padding: 0 2px;
    font-size: 0.88rem;
  }
  .hand-tools {
    display: none;
  }
  .hand-foot.is-open .hand-tools {
    display: flex;
    flex-direction: column;
    gap: 14px;
  }
  .hand-foot.is-open .hand-tools-toggle {
    color: var(--text);
  }
  .copy-btn--replay {
    display: none;
  }
  .hand-id {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
  }
  .hand-id code {
    grid-column: 1 / -1;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .hand-id .copy-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    font-size: 0.82rem;
  }
  .note-form > .btn {
    min-height: 40px;
  }
  .hand-replayer .link-btn {
    min-height: 40px;
  }
  .coach-examples .link-btn {
    min-height: 40px;
  }
}

/* A touch keyboard has no Shift to reach for: Enter is a new line there,
   and the Send button sends (coach.js), so the key hint would mislead. */
@media (pointer: coarse) {
  .coach-hint {
    display: none;
  }
}

/* ---------- Personal bests ---------- */

/* A record names the tournament that set it: a long name wraps inside its
   tile rather than widening the grid on a phone. */
.bests-page .tile .sub {
  overflow-wrap: anywhere;
}
.bests-page section + section {
  margin-top: 8px;
}
@media (min-width: 721px) {
  .tiles-three {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
.luck-cards {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 10px 0 6px;
}
.luck-board {
  padding-left: 8px;
  border-left: 1px solid var(--border);
}
.luck-board .pcard { background: var(--card-face-board); }
/* Seven cards need the full width of a phone. */
.tiles-luck {
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 721px) {
  .tiles-luck {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.milestone-card {
  padding: 6px 20px;
}
.milestone-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.milestone-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 2px 12px;
  align-items: baseline;
  padding: 12px 0;
  border-top: 1px solid var(--border);
}
.milestone-row:first-child {
  border-top: 0;
}
.milestone-label {
  font-weight: 600;
}
.milestone-date {
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.milestone-meta {
  grid-column: 1 / -1;
  font-size: 0.85rem;
  overflow-wrap: anywhere;
}
/* Two columns on a wide screen, so eight short rows don't run the page
   long. */
@media (min-width: 1024px) {
  .milestone-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 40px;
  }
  .milestone-row:nth-child(2) {
    border-top: 0;
  }
}
.milestone-row.is-locked .milestone-label,
.milestone-row.is-locked .milestone-date {
  color: var(--text-muted);
  font-weight: 400;
}

/* The Personal bests drawings: a quiet accent line drawing in a soft disc
   beside each caption, never louder than the figure under it. */
.tile-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}
.best-badge {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  margin: -4px -6px 0 0;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent-text);
}
.best-icon {
  width: 18px;
  height: 18px;
}
.milestone-row {
  grid-template-columns: auto minmax(0, 1fr) auto;
  column-gap: 12px;
}
.milestone-badge {
  grid-row: span 2;
  align-self: center;
  margin: 0;
}
.milestone-meta {
  grid-column: 2 / -1;
}
/* A first win is gold, like the win badge; a first still to come is a
   grey outline. */
.milestone-row.is-win .milestone-badge {
  background: var(--gold);
  color: var(--on-gold);
}
.milestone-row.is-locked .milestone-badge {
  background: transparent;
  color: var(--text-muted);
  box-shadow: inset 0 0 0 1px var(--border);
}

/* The banner: the title beside one line drawing, on the panel surface. */
.bests-hero {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 8px;
  padding: 20px 22px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elevated);
}
.bests-hero h1 {
  margin: 0;
}
.bests-hero-sub {
  margin: 6px 0 0;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.bests-art {
  flex: none;
  width: 140px;
  height: auto;
}
@media (min-width: 721px) {
  .bests-art {
    width: 200px;
  }
}
.art-chips,
.art-cards,
.art-ground {
  stroke: var(--accent-text);
}
.art-chips path,
.art-cards path:not(:last-child) {
  fill: var(--accent-soft);
}
.art-cards path:last-child {
  fill: var(--accent-text);
  stroke: none;
}
.art-ground {
  stroke: var(--border);
}
.art-trophy {
  stroke: var(--gold);
}
.art-star {
  fill: var(--gold);
  stroke: none;
}
