/* Paddle Captain — a white page inside black-and-gold chrome.
   The sheet is paper; the header along the top and the rail down the left side are
   the black band around it, lettered in gold-bar gold. Tap targets stay big: this
   is read courtside, in the cold, with gloves on.

   Gold means *us* — our courts, our row in the table, our wins. It is the only
   accent, and grey carries the opponent's side, because two accents competing is
   what makes a scoreboard unreadable at a glance in bad light.

   Two token groups, deliberately separate. `--bg`/`--text` are the page; `--chrome`
   and `--chrome-text` are the black bars. Keeping them apart is what let the page
   go from black to white without touching the header, and would let it go back.
   `--on-fill` is for text over a saturated colour — on a dark theme that could be
   `--text`, on a light one `--text` is near-black and would vanish into the fill.

   Every colour past this block is a variable. It was not always: nineteen were
   hard-coded, so the first re-theme changed the top of the page and left the
   buttons and banners behind. */

:root {
  /* White page, black chrome, gold lettering on the chrome.
     The page is paper; the header and the side rail are the black-and-gold band
     around it. */
  --bg: #ffffff;
  --bg-raised: #ffffff;
  --bg-input: #ffffff;

  /* Trim on white has to be darker than trim on black was, or it disappears. */
  --line: #d8d8de;
  --line-soft: #ebebef;
  --text: #14141a;
  --text-dim: #55555f;
  /* 4.62:1 on white — AA at the 11.5px it is actually used at. */
  --text-faint: #75757f;

  /* Gold-bar gold: the metallic bullion tone, deeper than the old screen gold.
     It has to carry the header and rail lettering against black, and also read as
     "ours" in the body — a lighter gold washes out on white. */
  /* The house gold is #CEB888 — champagne, soft, and the brand colour.
     It does two jobs, and one tone cannot do both:

       as a FILL it is excellent — 10.33:1 behind the chrome lettering, and a
       near-black label on a gold button reads at 9.45:1;
       as TEXT on white it is 1.94:1, which is not a marginal call. Gold this pale
       cannot be ink on paper.

     So --court is the fill (buttons, grid shading, the washes, the chrome) and
     --court-ink is the same family darkened until it reads: 5.92:1 on white and
     5.39:1 on its own wash, so a gold-meaning link or pill works wherever it
     lands. --court-dim sits between them, for a fill that carries white text. */
  --court: #ceb888;
  --court-ink: #756230;
  --court-dim: #7d6837;
  --on-court: #1a1405; /* text over a gold fill: 9.45:1 */
  --them: #55555f; /* them — grey, so gold stays ours */
  /* Same split, milder: the plain warn colour is 3.82:1 on its own wash. */
  --warn: #c2560f;
  --warn-ink: #a8490c;
  --danger: #c0272d;
  --live: #d61f26;

  /* The black chrome, and the lettering on it. Kept apart from --text/--bg so the
     bar stays black and gold whichever way the page itself goes. */
  /* Softened. Near-pure black against a white page is a hard edge, and the two
     hairline borders holding the chrome apart from the sheet made it harder. This
     is a warm charcoal instead, the borders are gone, and the white page sits on
     it as a rounded sheet — so the join is a curve and a soft shadow rather than
     a 1px rule. */
  --chrome: #17181c;
  --chrome-soft: #202127; /* the raised state inside the rail */
  --chrome-text: #ceb888; /* the house gold, unmodified — 9.5:1 on this charcoal */
  --chrome-dim: #9fa0aa;

  /* Text over a saturated fill — a red pill, a dark-gold segment. On a dark theme
     this could be --text; on a light one --text is near-black and would vanish. */
  --on-fill: #ffffff;

  /* A lifted surface for pressed/hover states, and a tinted one behind table
     headers so a header reads as a header without needing a border. */
  --bg-alt: #f2f2f5;
  --bg-head: #f7f7f9;

  /* Gold and white washes, so tints follow the accent instead of being frozen. */
  --court-wash: color-mix(in srgb, var(--court) 16%, transparent);
  --court-wash-soft: color-mix(in srgb, var(--court) 10%, transparent);
  --them-wash: color-mix(in srgb, var(--them) 10%, transparent);
  --warn-wash: color-mix(in srgb, var(--warn) 13%, transparent);
  --danger-wash: color-mix(in srgb, var(--danger) 14%, transparent);

  --radius: 12px;
  --radius-lg: 18px;
  --pad: 16px;
  --rail: 158px; /* width of the left nav rail; collapses on narrow phones */
  --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  -webkit-text-size-adjust: 100%;
  overscroll-behavior-y: none;
}

/* The charcoal shows through behind everything; the white page is a rounded sheet
   laid on top of it, inset by the width of the rail. That curve at the top-left is
   what takes the hardness out of the corner where the rail meets the header. */
html { background: var(--chrome); }
body {
  padding-left: var(--rail);
  background: transparent;
}

a { color: var(--court-ink); }

/* ---------- layout ---------- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px var(--pad) 15px;
  background: var(--chrome);
  color: var(--chrome-text);
  /* No border. A hairline rule is what made this read as sharp; the sheet below
     rounds away from it instead, and a soft shadow does the separating. */
  box-shadow: 0 6px 18px -8px rgba(0, 0, 0, 0.55);
}

.topbar h1 {
  flex: 1;
  margin: 0;
  font-size: 17px;
  font-weight: 650;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--chrome-text);
}

.topbar .sub {
  display: block;
  font-size: 12px;
  font-weight: 450;
  color: var(--chrome-dim);
}

/* The log-out button sits on the charcoal, so it cannot inherit the page's dark
   text. Filled with the soft raised tone rather than outlined — one less hard
   line on the header. */
.topbar button {
  color: var(--chrome-text);
  border-color: transparent;
  background: var(--chrome-soft);
}

/* The white sheet. Rounded at the top-left, where it meets the corner between the
   rail and the header — the one join that looked sharpest. */
main {
  padding: var(--pad);
  background: var(--bg);
  border-top-left-radius: 20px;
  min-height: calc(100vh - 66px);
}

main > * { max-width: 900px; margin-left: auto; margin-right: auto; }

/* ---------- the left rail ---------- */
/* Was a bottom tab bar. A vertical rail gives the labels room to be words rather
   than abbreviations, and leaves the full height of the page for the season grids,
   which are the widest and tallest things here. */
.nav {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  width: var(--rail);
  z-index: 30;
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 14px 10px;
  background: var(--chrome);
  /* No border here either — the sheet's rounded edge is the boundary. */
  overflow-y: auto;
  overscroll-behavior: contain;
}

.nav a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 11px;
  border-radius: 12px;
  font-size: 13px;
  font-weight: 550;
  color: var(--chrome-dim);
  text-decoration: none;
  white-space: nowrap;
}

.nav a .ico { font-size: 17px; line-height: 1; flex: none; width: 1.3em; text-align: center; }

.nav a.on {
  color: var(--chrome-text);
  background: var(--chrome-soft);
}

.nav a:hover:not(.on) { color: var(--chrome-text); }
.nav a:active { background: var(--chrome-soft); }

/* Narrow phones: the rail collapses to icons so it never eats the content. */
@media (max-width: 560px) {
  :root { --rail: 56px; }
  .nav a { justify-content: center; padding: 12px 6px; }
  .nav a .ico { font-size: 20px; width: auto; }
  .nav a .lbl { display: none; }
}

/* ---------- cards & sections ---------- */

.card {
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--pad);
  margin-bottom: 14px;
}

.card.tight { padding: 12px 14px; }
.card.flush { padding: 0; overflow: hidden; }

h2.section {
  margin: 26px 0 10px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}

h2.section:first-child { margin-top: 4px; }
h2.section .count { color: var(--text-faint); font-weight: 500; }

h3 { margin: 0 0 10px; font-size: 15px; font-weight: 650; }

.muted { color: var(--text-dim); }
.faint { color: var(--text-faint); }
.small { font-size: 13px; }
.tiny { font-size: 11.5px; }
.mono { font-family: var(--mono); }
.right { text-align: right; }
.center { text-align: center; }
.grow { flex: 1; min-width: 0; }
.row { display: flex; align-items: center; gap: 10px; }
.row.wrap { flex-wrap: wrap; }
.row.tight { gap: 6px; }
.col { display: flex; flex-direction: column; gap: 10px; }
.spread { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.stack > * + * { margin-top: 8px; }
.truncate { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.empty {
  padding: 28px 18px;
  text-align: center;
  color: var(--text-faint);
  font-size: 14px;
  line-height: 1.5;
}

/* ---------- controls ---------- */

button, .btn {
  font: inherit;
  font-weight: 600;
  color: var(--text);
  background: var(--bg-alt);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 11px 15px;
  min-height: 44px;
  cursor: pointer;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  -webkit-tap-highlight-color: transparent;
}

button:active, .btn:active { transform: translateY(1px); }
button:disabled { opacity: 0.45; cursor: default; }

/* Bronze edge on the gold fill: on a white page a gold button with a gold border
   has no boundary, and this is the one button that commits something. */
.btn-primary { background: var(--court); border-color: var(--court-ink); color: var(--on-court); }
.btn-danger { background: transparent; border-color: color-mix(in srgb, var(--danger) 34%, transparent); color: var(--danger); }
.btn-ghost { background: transparent; }
.btn-sm { min-height: 34px; padding: 6px 11px; font-size: 13px; border-radius: 9px; }
.btn-block { width: 100%; }

input, select, textarea {
  font: inherit;
  width: 100%;
  color: var(--text);
  background: var(--bg-input);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 11px 12px;
  min-height: 44px;
}

input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--court-dim);
  box-shadow: 0 0 0 3px var(--court-wash);
}

textarea { min-height: 72px; resize: vertical; }
label.field { display: block; margin-bottom: 12px; }
label.field > span { display: block; margin-bottom: 5px; font-size: 12px; font-weight: 600; color: var(--text-dim); }
.field-row { display: flex; gap: 10px; }
.field-row > * { flex: 1; }

.check { display: flex; align-items: center; gap: 10px; min-height: 40px; }
.check input { width: 20px; height: 20px; min-height: 0; flex: none; }

/* ---------- pills & badges ---------- */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 650;
  border: 1px solid var(--line);
  color: var(--text-dim);
  white-space: nowrap;
}

.pill.in { background: var(--court-wash); border-color: transparent; color: var(--court-ink); }
.pill.out { background: var(--danger-wash); border-color: transparent; color: var(--danger); }
.pill.maybe { background: var(--warn-wash); border-color: transparent; color: var(--warn-ink); }
.pill.sub { background: color-mix(in srgb, var(--text-dim) 14%, transparent); border-color: transparent; color: var(--text-dim); }
.pill.live { background: var(--live); border-color: transparent; color: var(--on-fill); }
.pill.won { background: var(--court-wash); border-color: transparent; color: var(--court-ink); }
.pill.lost { background: var(--them-wash); border-color: transparent; color: var(--them); }

.dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-faint); flex: none; }
.dot.on { background: var(--live); animation: pulse 1.6s infinite; }
@keyframes pulse { 50% { opacity: 0.3; } }

/* ---------- lists ---------- */

.list { display: flex; flex-direction: column; }
.list > .item { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-bottom: 1px solid var(--line-soft); }
.list > .item:last-child { border-bottom: none; }
.list > .item .name { font-weight: 600; }
.list > a.item { color: inherit; text-decoration: none; }
.list > a.item:active { background: var(--bg-input); }

.seg { display: flex; gap: 0; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; flex: none; }
.seg button {
  border: none;
  border-radius: 0;
  min-height: 36px;
  padding: 6px 12px;
  font-size: 13px;
  background: transparent;
  color: var(--text-faint);
  border-left: 1px solid var(--line);
}
.seg button:first-child { border-left: none; }
.seg button.on { background: var(--bg-alt); color: var(--text); }
.seg button.on.in { background: var(--court-dim); color: var(--on-fill); }
.seg button.on.out { background: var(--danger); color: var(--on-fill); }
.seg button.on.maybe { background: var(--warn); color: var(--on-fill); }

/* ---------- scoreboard ---------- */

.board {
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  overflow: hidden;
  margin-bottom: 14px;
}

.board.is-live { border-color: color-mix(in srgb, var(--live) 45%, transparent); }
.board-head { display: flex; align-items: center; gap: 8px; padding: 10px 14px; background: var(--bg-head); border-bottom: 1px solid var(--line); font-size: 12.5px; font-weight: 650; color: var(--text-dim); }

.board-side { display: flex; align-items: center; gap: 10px; padding: 12px 14px; }
.board-side + .board-side { border-top: 1px solid var(--line-soft); }
.board-side .who { flex: 1; min-width: 0; }
.board-side .who .names { font-weight: 650; font-size: 15px; }
.board-side.serving .who .names::after { content: '•'; color: var(--court-ink); margin-left: 7px; }
.board-side .sets { display: flex; gap: 9px; font-family: var(--mono); font-size: 16px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.board-side .sets .cur { color: var(--text); font-weight: 700; }
.board-side .pts { font-family: var(--mono); font-size: 30px; font-weight: 700; min-width: 62px; text-align: right; font-variant-numeric: tabular-nums; }
.board-side.win .pts, .board-side.win .who .names { color: var(--court-ink); }

.board-foot { padding: 9px 14px; border-top: 1px solid var(--line-soft); font-size: 12px; color: var(--text-faint); display: flex; justify-content: space-between; gap: 10px; }

/* big scoring surface */
.tapzone { display: flex; gap: 10px; margin: 12px 0; }
.tapzone button { flex: 1; flex-direction: column; min-height: 84px; font-size: 13px; gap: 2px; }
.tapzone button b { font-size: 20px; }
.tapzone .us { background: var(--court-wash); border-color: var(--court-dim); color: var(--court-ink); }
.tapzone .them { background: var(--them-wash); border-color: color-mix(in srgb, var(--them) 26%, transparent); color: var(--them); }

/* ---------- voice ---------- */

.mic {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px;
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
  background: var(--bg-raised);
  margin-bottom: 14px;
}

.mic.on { border-color: var(--live); background: color-mix(in srgb, var(--live) 7%, transparent); }
.mic .orb {
  width: 54px; height: 54px; flex: none;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--bg-alt);
  display: grid; place-items: center;
  font-size: 23px;
  cursor: pointer;
}
.mic.on .orb { background: var(--live); border-color: var(--live); box-shadow: 0 0 0 0 color-mix(in srgb, var(--live) 50%, transparent); animation: ring 1.8s infinite; }
@keyframes ring { 70% { box-shadow: 0 0 0 16px color-mix(in srgb, var(--live) 0%, transparent); } }
.mic .status { font-weight: 650; font-size: 14px; }
.mic .hint { font-size: 12px; color: var(--text-faint); margin-top: 2px; line-height: 1.4; }
.mic .heard { font-family: var(--mono); font-size: 12px; color: var(--court-ink); margin-top: 4px; min-height: 15px; }

.feed { max-height: 260px; overflow-y: auto; }
.feed .line { display: flex; gap: 9px; padding: 7px 0; border-bottom: 1px solid var(--line-soft); font-size: 13px; align-items: baseline; }
.feed .line:last-child { border-bottom: none; }
.feed .line time { font-family: var(--mono); font-size: 11px; color: var(--text-faint); flex: none; }
.feed .line.kind-snap { color: var(--warn-ink); }
.feed .line.kind-ignored { color: var(--text-faint); }
.feed .line.kind-undo { color: var(--them); }

/* ---------- tables ---------- */

.scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }

table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
th, td { padding: 9px 10px; text-align: right; white-space: nowrap; border-bottom: 1px solid var(--line-soft); }
th { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-faint); font-weight: 700; }
th:first-child, td:first-child { text-align: left; position: sticky; left: 0; background: var(--bg-raised); }
tbody tr:last-child td { border-bottom: none; }
td.num { font-family: var(--mono); font-variant-numeric: tabular-nums; }

@media (max-width: 540px) {
  th, td { padding: 9px 7px; }
}

/* ---------- misc ---------- */

.banner { padding: 11px 14px; border-radius: var(--radius); font-size: 13px; margin-bottom: 14px; line-height: 1.45; }
.banner.info { background: var(--court-wash-soft); color: var(--court-dim); }
.banner.warn { background: var(--warn-wash); color: var(--warn-ink); }
.banner.error { background: var(--danger-wash); color: var(--danger); }

.toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  z-index: 60;
  background: var(--bg-alt);
  border: 1px solid var(--line);
  color: var(--text);
  padding: 11px 16px;
  border-radius: 999px;
  font-size: 13.5px;
  font-weight: 600;
  box-shadow: 0 8px 26px rgba(0, 0, 0, 0.18);
  max-width: 90vw;
  text-align: center;
}
.toast.error { background: var(--danger); border-color: var(--danger); color: var(--on-fill); }

.sheet-backdrop { position: fixed; inset: 0; z-index: 50; background: rgba(0, 0, 0, 0.6); display: flex; align-items: flex-end; justify-content: center; }
.sheet {
  width: 100%;
  max-width: 520px;
  max-height: 88vh;
  overflow-y: auto;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: 20px 20px 0 0;
  padding: 18px var(--pad) calc(24px + env(safe-area-inset-bottom));
}
.sheet h3 { display: flex; justify-content: space-between; align-items: center; font-size: 17px; margin-bottom: 14px; }

.link-box { display: flex; gap: 8px; align-items: center; }
.link-box input { font-family: var(--mono); font-size: 12px; }

/* The login screen, centred on the whole viewport.
   Fixed rather than flowed, because the body is inset by the width of the nav
   rail and the gate is the one screen that does not draw one — centring inside
   that inset box put the card half a rail's width right of true centre. */
.center-page {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  padding: var(--pad);
  background: var(--bg);
  overflow: auto;
}
.center-page .card { width: 100%; max-width: 380px; margin: 0; }

@media (min-width: 720px) {
  .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-items: start; }
  .grid-2 > .card { margin-bottom: 0; }
}

/* ---------- attendance grid ---------- */

table.matrix { font-size: 13px; }
table.matrix th, table.matrix td { padding: 6px 4px; text-align: center; }
table.matrix th:first-child, table.matrix td:first-child {
  text-align: left;
  padding-left: 12px;
  padding-right: 10px;
  min-width: 116px;
  max-width: 150px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
table.matrix th.col-date { min-width: 40px; line-height: 1.15; }
table.matrix th.col-date .d1 { display: block; font-size: 11px; color: var(--text-dim); }
table.matrix th.col-date .d2 { display: block; font-size: 9.5px; color: var(--text-faint); font-weight: 500; }
table.matrix tr.totals td {
  border-top: 1px solid var(--line);
  border-bottom: none;
  font-size: 11.5px;
  color: var(--text-faint);
  font-family: var(--mono);
}
table.matrix tr.totals td:first-child { font-family: var(--font); }

.mark {
  display: inline-grid;
  place-items: center;
  width: 30px;
  height: 30px;
  min-height: 0;
  padding: 0;
  border-radius: 8px;
  border: 1px solid transparent;
  background: var(--bg-input);
  color: var(--text-faint);
  font-size: 13px;
  font-weight: 700;
}

/* A played court: gold when we won it, white trim when we did not. Both are
   filled, because "played and lost" is still a night on court and should not read
   like an empty cell. */
.mark.yes { background: var(--court-wash); color: var(--court-ink); }
.mark.lost { background: var(--them-wash); color: var(--them); border-color: color-mix(in srgb, var(--them) 22%, transparent); }
/* A reply without a result yet: outlined rather than filled, so a promise reads
   lighter than a night actually played. Tinted by the answer. */
.mark.avail { background: transparent; border-color: var(--line); font-size: 10px; font-weight: 600; }
.mark.avail.yes { border-color: color-mix(in srgb, var(--court) 45%, transparent); color: var(--court-ink); }
.mark.avail.maybe { border-color: color-mix(in srgb, var(--warn) 45%, transparent); color: var(--warn-ink); }
.mark.avail.no { border-color: var(--line); color: var(--text-faint); }
a.mark { text-decoration: none; }

/* ---------- import preview ---------- */

.preview { max-height: 320px; overflow-y: auto; }
.preview .row-line { display: flex; gap: 8px; align-items: baseline; padding: 7px 0; border-bottom: 1px solid var(--line-soft); font-size: 13px; }
.preview .row-line:last-child { border-bottom: none; }
.preview .row-line .when { font-family: var(--mono); font-size: 12px; color: var(--text-dim); flex: none; min-width: 74px; }
.preview .row-line.bad { color: var(--warn-ink); }

/* Insight deltas: better or worse than the player's own baseline. */
.up { color: var(--court-ink); }
.down { color: var(--them); }
.warn-text { color: var(--warn-ink); }

/* ---------- PTI ---------- */

/* Four season numbers, aligned. A wrapping flex row put two per line with a gap
   the width of the card, and the second column began wherever the first ended. */
.stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.stat-value { font-size: 21px; font-weight: 700; line-height: 1.15; }
@media (max-width: 620px) {
  .stat-grid { grid-template-columns: repeat(2, 1fr); gap: 16px 12px; }
}

/* Roster columns. Fixed widths so the record and the rating form real columns down
   the list rather than drifting with the length of each name — a roster is read by
   scanning down one of them, not across a row. */
.col-rec {
  flex: none;
  width: 8.5em;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1px;
  text-align: right;
}
.col-pti { flex: none; width: 6em; display: flex; justify-content: flex-end; }

@media (max-width: 560px) {
  .col-rec { width: 5.4em; }
  .col-pti { width: 5em; }
}

.pti { display: inline-flex; align-items: baseline; gap: 5px; flex: none; font-family: var(--mono); }
.pti b { font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; }
.pti.none { color: var(--text-faint); }
.pti-move { font-size: 10.5px; font-weight: 700; }
/* Lower PTI is a stronger player, so falling is the good direction. */
.pti-move.improving { color: var(--court-ink); }
.pti-move.declining { color: var(--them); }
.pti-move.flat, .pti-move.unknown { color: var(--text-faint); }
