/* EIHL Fantasy — design tokens and components.
 *
 * Scene: a cold rink at 7pm. Dark stands, bright ice, breath visible.
 * So: a cold near-black surface, ice-bright ink, and a single cold green
 * carrying points and primary actions. Red appears only where a rink uses
 * it — the goal light — for the captain's armband and for things that are
 * wrong. Deliberately not the navy-and-ice-blue every hockey app reaches for.
 */

:root {
  /* Surfaces: cold, barely tinted, never warm. */
  --bg:          oklch(0.16 0.008 210);
  --surface:     oklch(0.21 0.010 210);
  --surface-2:   oklch(0.26 0.012 210);
  --surface-3:   oklch(0.32 0.014 210);
  --line:        oklch(0.34 0.014 210);
  --line-soft:   oklch(0.27 0.012 210);

  /* Ink */
  --ink:         oklch(0.97 0.004 210);
  --ink-muted:   oklch(0.76 0.012 210);   /* 4.5:1+ on --bg and --surface */
  --ink-faint:   oklch(0.60 0.012 210);   /* decorative only, never body */

  /* Brand: cold green. Points, selection, primary action. */
  --primary:     oklch(0.78 0.140 140);
  --primary-dim: oklch(0.62 0.110 140);
  --primary-ink: oklch(0.18 0.030 140);
  --primary-wash: oklch(0.78 0.140 140 / 0.12);

  /* The mark's lit colour. The goal horn, and the one brand colour that is
     not --primary: a skin's signature colour must not relight the logo, or
     the mark changes every time someone tries a different look. Theme.apply
     overwrites this inline, and only when a manager has actually chosen an
     accent. Everything outside the app stays horn. */
  --logo-lit:    #FF5C2B;

  /* The goal light. Captain, urgency, error. Used sparingly. */
  --alert:       oklch(0.66 0.200 28);
  --alert-wash:  oklch(0.66 0.200 28 / 0.14);

  --warn:        oklch(0.80 0.140 80);

  --radius-sm: 6px;
  --radius:    10px;
  --radius-lg: 16px;

  --pad: 16px;

  --shadow-1: 0 1px 2px oklch(0 0 0 / 0.4);
  --shadow-2: 0 6px 20px oklch(0 0 0 / 0.45);

  --ease: cubic-bezier(0.22, 1, 0.36, 1);   /* ease-out-quart */
  --fast: 160ms;
  --med:  220ms;

  /* Semantic stacking order, never arbitrary numbers. */
  --z-sticky: 100;
  --z-nav:    200;
  --z-sheet-backdrop: 300;
  --z-sheet:  310;
  --z-toast:  400;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
  font-size: 16px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior-y: none;
}

body { padding-bottom: 76px; }          /* clears the tab bar */

h1, h2, h3 { margin: 0; text-wrap: balance; letter-spacing: -0.015em; }
h1 { font-size: 1.35rem; font-weight: 650; }
h2 { font-size: 1.05rem; font-weight: 620; }
h3 { font-size: 0.9rem;  font-weight: 600; }

button { font: inherit; color: inherit; cursor: pointer; }
button:disabled { cursor: not-allowed; }

.num { font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------- shell */

.app { max-width: 620px; margin: 0 auto; }

.topbar {
  position: sticky; top: 0; z-index: var(--z-sticky);
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  padding: 12px var(--pad);
  background: oklch(0.16 0.008 210 / 0.88);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line-soft);
}
/* The mark sits before the manager's own identity, at cap height and no
   larger. It is the product's only appearance in the interface: the name
   beside it belongs to the manager, not to us. */
.brandmark {
  flex: none;
  width: auto;
  height: 22px;
  aspect-ratio: 72 / 100;
  fill: var(--logo-lit, #FF5C2B);
}

/* The full lockup, for the one screen nobody is signed in on. */
.brandlockup { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; }
.brandlockup .brandmark { height: 40px; }
.brandlockup__word { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.brandlockup__word b {
  font-size: 1.5rem; font-weight: 700; line-height: 0.95;
  letter-spacing: -0.02em; text-transform: uppercase;
}
.brandlockup__word span {
  font-size: 0.64rem; font-weight: 600; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--logo-lit, #FF5C2B);
}

.topbar__title { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.topbar__sub { font-size: 0.72rem; color: var(--ink-muted); }
.topbar__title .topbar__sub,
.topbar__title h1 { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.gw-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  font-size: 0.75rem; font-weight: 600;
  white-space: nowrap;
}
.gw-pill b { color: var(--primary); }
/* Spelled out, because 'GW2' is jargon to anyone who has not played fantasy
   sport before. It shortens to 'GW' only when there is genuinely no room. */
.gw-pill__label::after { content: " "; }
@media (max-width: 359px) {
  .gw-pill__label { font-size: 0; }
  .gw-pill__label::before { content: "GW"; font-size: 0.75rem; }
}

main { padding: var(--pad); }
.panel { display: none; }
.panel.is-active { display: block; animation: fade var(--med) var(--ease); }
@keyframes fade { from { opacity: 0; transform: translateY(4px); } }

/* ------------------------------------------------------------- tab bar */

.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-nav);
  display: grid; grid-template-columns: repeat(3, 1fr);
  background: oklch(0.18 0.009 210 / 0.94);
  backdrop-filter: blur(14px);
  border-top: 1px solid var(--line-soft);
  padding-bottom: env(safe-area-inset-bottom, 0);
}
.tabbar button {
  border: 0; background: none;
  padding: 11px 4px 13px;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  font-size: 0.68rem; font-weight: 600; letter-spacing: 0.01em;
  /* --ink-muted, not --ink-faint: these are navigation labels, not
     decoration, and faint measured 4.33:1 on the light tab bar. */
  color: var(--ink-muted);
  transition: color var(--fast) var(--ease);
}
.tabbar button svg { width: 21px; height: 21px; stroke-width: 1.7; }
.tabbar button[aria-selected="true"] { color: var(--primary); }
.tabbar button:focus-visible { outline: 2px solid var(--primary); outline-offset: -3px; }

/* ------------------------------------------------------------ the rink */

.rink {
  position: relative;
  border: 1px solid var(--line);
  border-radius: 22px;
  background:
    radial-gradient(120% 70% at 50% 0%, oklch(0.30 0.014 210) 0%, transparent 60%),
    var(--surface);
  padding: 18px 10px 14px;
  overflow: hidden;
}
/* Centre line and faceoff circle: rink furniture, not decoration for its
   own sake — they make the surface read as ice at a glance. */
.rink::before {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  border-top: 1px solid oklch(0.66 0.200 28 / 0.22);
}
.rink::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 116px; height: 116px; transform: translate(-50%, -50%);
  border: 1px solid oklch(0.60 0.10 210 / 0.20); border-radius: 50%;
}

.rink__row {
  position: relative;
  display: flex; justify-content: center; gap: 8px; flex-wrap: wrap;
  margin-bottom: 16px;
}
.rink__row:last-child { margin-bottom: 0; }

.rink__label {
  position: relative;
  text-align: center;
  font-size: 0.64rem; font-weight: 700; letter-spacing: 0.08em;
  color: var(--ink-faint);
  margin-bottom: 7px;
}

/* ------------------------------------------------------- player tokens */

.pt {
  position: relative;
  width: 82px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  padding: 6px 4px 5px;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  text-align: center;
  transition: transform var(--fast) var(--ease),
              border-color var(--fast) var(--ease),
              background var(--fast) var(--ease);
}
.pt:hover, .pt:focus-visible { border-color: var(--primary-dim); transform: translateY(-2px); }
.pt:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.pt--empty {
  border-style: dashed; background: transparent;
  color: var(--ink-faint); justify-content: center; min-height: 92px;
}
.pt--empty:hover { color: var(--primary); border-color: var(--primary-dim); }
.pt--out { opacity: 0.45; }

.pt__face {
  width: 40px; height: 40px; border-radius: 50%;
  object-fit: cover; object-position: top center;
  background: var(--surface-3);
  border: 1px solid var(--line);
}
.pt__initials {
  width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--surface-3); border: 1px solid var(--line);
  font-size: 0.78rem; font-weight: 700; color: var(--ink-muted);
  letter-spacing: 0.02em;
}
.pt__name {
  font-size: 0.7rem; font-weight: 600; line-height: 1.15;
  width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pt__meta {
  font-size: 0.62rem; color: var(--ink-muted);
  display: flex; align-items: center; gap: 4px;
}
.pt__pts {
  min-width: 34px;
  padding: 1px 6px; border-radius: 999px;
  background: var(--primary-wash); color: var(--primary);
  font-size: 0.7rem; font-weight: 700;
}
.pt__pts--zero { background: var(--surface-3); color: var(--ink-faint); }
/* A skater can finish a night below zero (penalties, minus rating).
   Only goalies are floored, so negatives must not wear the points colour. */
.pt__pts--neg { background: var(--alert-wash); color: var(--alert); }

.badge {
  position: absolute; top: -6px; right: -6px;
  width: 21px; height: 21px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 0.64rem; font-weight: 800;
  border: 2px solid var(--surface);
}
.badge--c { background: var(--alert); color: oklch(0.99 0 0); }
.badge--v { background: var(--surface-3); color: var(--ink); }

/* An inline label beside a league's name. Deliberately not .badge, which is
   absolutely positioned for the captain markers on the ice sheet. */
.ltag {
  display: inline-block; vertical-align: middle;
  margin-left: 8px; padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.66rem; font-weight: 700; letter-spacing: 0.04em;
  text-transform: uppercase;
  background: var(--primary-wash); color: var(--primary);
  border: 1px solid var(--line);
}

/* A short yes/no sheet does not need the full height a player sheet does. */
.sheet--narrow { max-height: 70vh; }

/* -------------------------------------------------------- budget meter */

.meter {
  display: grid; grid-template-columns: 1fr auto; gap: 4px 12px;
  align-items: baseline;
  margin: 0 0 14px;
}
.meter__nums { display: flex; gap: 14px; font-size: 0.78rem; color: var(--ink-muted); }
.meter__nums b { color: var(--ink); font-weight: 650; }
.meter__track {
  grid-column: 1 / -1;
  height: 5px; border-radius: 999px;
  background: var(--surface-2); overflow: hidden;
}
.meter__fill {
  height: 100%; width: 100%; border-radius: 999px;
  background: var(--primary);
  /* Scaled rather than resized: animating width would relayout the bar on
     every pick. transform-origin keeps it growing from the left. */
  transform-origin: left center;
  transform: scaleX(0);
  transition: transform var(--med) var(--ease), background var(--fast) var(--ease);
}
.meter__fill.is-over { background: var(--alert); }

/* -------------------------------------------------------------- pieces */

.stack > * + * { margin-top: 14px; }
.row { display: flex; align-items: center; gap: 8px; }
.row--between { justify-content: space-between; }
.spread { flex: 1 1 auto; }

.btn {
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--ink);
  border-radius: var(--radius-sm);
  padding: 9px 14px;
  font-size: 0.85rem; font-weight: 600;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease),
              transform var(--fast) var(--ease), opacity var(--fast) var(--ease);
}
.btn:hover:not(:disabled) { background: var(--surface-3); }
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.btn:disabled { opacity: 0.45; }
.btn--primary {
  background: var(--primary); border-color: var(--primary);
  color: var(--primary-ink); font-weight: 700;
}
.btn--primary:hover:not(:disabled) { background: oklch(0.83 0.145 140); }
.btn--ghost { background: transparent; }
.btn--sm { padding: 6px 10px; font-size: 0.78rem; }
.btn--wide { width: 100%; justify-content: center; }
.btn.is-on { border-color: var(--primary); color: var(--primary); background: var(--primary-wash); }

.card {
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 14px;
}

.note {
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  background: var(--surface);
  padding: 10px 12px;
  font-size: 0.82rem; color: var(--ink-muted);
}
.note--bad { border-color: oklch(0.66 0.200 28 / 0.5); background: var(--alert-wash); color: var(--ink); }
.note--good { border-color: oklch(0.78 0.140 140 / 0.45); background: var(--primary-wash); color: var(--ink); }
.note ul { margin: 6px 0 0; padding-left: 18px; }
.note li + li { margin-top: 3px; }

/* --------------------------------------------------------- player list */

.filters { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; }
.field {
  flex: 1 1 140px;
  display: flex; align-items: center; gap: 6px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); padding: 0 10px;
}
.field input, .field select {
  flex: 1; min-width: 0;
  border: 0; background: none; color: var(--ink);
  padding: 9px 0; font-size: 0.85rem;
}
.field input::placeholder { color: var(--ink-muted); }
.field input:focus, .field select:focus { outline: none; }
.field:focus-within { border-color: var(--primary-dim); }
.field select { cursor: pointer; }
.field select option { background: var(--surface); color: var(--ink); }

.plist { display: flex; flex-direction: column; gap: 1px;
         border: 1px solid var(--line-soft); border-radius: var(--radius); overflow: hidden; }
.prow {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) auto auto;
  align-items: center; gap: 10px;
  padding: 9px 12px;
  background: var(--surface);
  border: 0; text-align: left; width: 100%;
  transition: background var(--fast) var(--ease);
}
.prow:hover { background: var(--surface-2); }
.prow:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.prow--in { background: var(--primary-wash); }
.prow--in:hover { background: oklch(0.78 0.140 140 / 0.18); }
.prow--blocked { opacity: 0.42; }
.prow__face { width: 34px; height: 34px; border-radius: 50%; object-fit: cover;
              object-position: top center; background: var(--surface-3); }
.prow__name { font-size: 0.85rem; font-weight: 600; line-height: 1.2;
              overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* One line only: 'Nottingham Panthers · CA' wrapping made the rows
   different heights, which reads as broken rather than dense. */
.prow__meta { font-size: 0.7rem; color: var(--ink-muted);
              overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
              display: flex; align-items: center; gap: 4px; }
.prow__price { font-size: 0.85rem; font-weight: 700; }
.prow__ppg { font-size: 0.66rem; color: var(--ink-muted); text-align: right;
             white-space: nowrap; }
.prow__tick { width: 20px; text-align: center; color: var(--primary); font-weight: 800; }

.pos-chip {
  display: inline-block; min-width: 17px;
  padding: 0 4px; border-radius: 3px;
  font-size: 0.6rem; font-weight: 800; letter-spacing: 0.03em;
  text-align: center;
  background: var(--surface-3); color: var(--ink-muted);
}
.pos-chip--G { background: oklch(0.80 0.14 80 / 0.22); color: var(--warn); }
.pos-chip--D { background: oklch(0.60 0.10 210 / 0.25); color: oklch(0.80 0.08 210); }
.pos-chip--F { background: var(--primary-wash); color: var(--primary); }

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

.table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.table th {
  text-align: left; font-size: 0.68rem; font-weight: 700;
  color: var(--ink-muted); letter-spacing: 0.04em;
  padding: 8px 10px; border-bottom: 1px solid var(--line);
}
.table td { padding: 10px; border-bottom: 1px solid var(--line-soft); }
.table tr:last-child td { border-bottom: 0; }
.table tbody tr.is-me { background: var(--primary-wash); }
.table td.num, .table th.num { text-align: right; }

/* ------------------------------------------------------------- sheets */

.backdrop {
  position: fixed; inset: 0; z-index: var(--z-sheet-backdrop);
  background: oklch(0 0 0 / 0.6);
  animation: fade var(--fast) var(--ease);
}
.sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-sheet);
  max-width: 620px; margin: 0 auto;
  background: var(--surface);
  border-top-left-radius: var(--radius-lg); border-top-right-radius: var(--radius-lg);
  border: 1px solid var(--line); border-bottom: 0;
  padding: 18px var(--pad) calc(18px + env(safe-area-inset-bottom, 0));
  box-shadow: var(--shadow-2);
  animation: rise var(--med) var(--ease);
  max-height: 82vh; overflow-y: auto;
}
@keyframes rise { from { transform: translateY(100%); } }

.sheet__grip {
  width: 34px; height: 4px; border-radius: 999px;
  background: var(--surface-3); margin: -6px auto 14px;
}

/* -------------------------------------------------------------- toast */

.toast {
  position: fixed; z-index: var(--z-toast);
  left: 50%; bottom: 92px; transform: translateX(-50%);
  background: var(--surface-3); color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 999px; padding: 9px 16px;
  font-size: 0.82rem; font-weight: 600;
  box-shadow: var(--shadow-2);
  animation: rise-fade var(--med) var(--ease);
}
.toast--bad { border-color: var(--alert); }
@keyframes rise-fade { from { opacity: 0; transform: translate(-50%, 8px); } }

/* ------------------------------------------------------- empty / load */

.empty { text-align: center; padding: 34px 18px; color: var(--ink-muted); }
.empty h2 { color: var(--ink); margin-bottom: 6px; }
.empty p { margin: 0 auto 16px; max-width: 42ch; font-size: 0.88rem; }

.skeleton {
  border-radius: var(--radius-sm);
  background: linear-gradient(90deg, var(--surface) 25%, var(--surface-2) 37%, var(--surface) 63%);
  background-size: 400% 100%;
  animation: shimmer 1.3s linear infinite;
}
@keyframes shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }

/* ------------------------------------------------------------- motion */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .panel.is-active, .sheet, .toast, .backdrop { animation: none; }
}

@media (min-width: 560px) {
  .pt { width: 92px; }
  h1 { font-size: 1.5rem; }
}

/* ==========================================================================
   Desktop
   --------------------------------------------------------------------------
   Not a stretched phone. Above 900px the navigation moves into the header
   (a bottom tab bar on a desktop is the clearest tell that something was
   only ever designed for a phone), the shell widens, and each panel gets a
   layout that uses the room rather than leaving two-thirds of the screen
   empty.
   ========================================================================== */

@media (min-width: 900px) {
  body { padding-bottom: 0; }

  .app { max-width: 1180px; padding: 0 24px; }

  .topbar {
    gap: 28px;
    padding: 16px 0;
    margin-bottom: 4px;
  }
  .topbar__title h1 { font-size: 1.5rem; }

  /* Primary navigation, inline in the header. */
  .topnav { display: flex; gap: 4px; margin-left: 8px; flex: 1 1 auto; }
  .topnav button {
    border: 0; background: none;
    padding: 8px 14px; border-radius: var(--radius-sm);
    font-size: 0.86rem; font-weight: 600;
    color: var(--ink-muted);
    transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
  }
  .topnav button:hover { background: var(--surface); color: var(--ink); }
  .topnav button[aria-selected="true"] { background: var(--primary-wash); color: var(--primary); }
  .topnav button:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

  .tabbar { display: none; }

  main { padding: 8px 0 48px; }

  /* --- My Team: rink beside a squad summary, instead of one long column --- */
  .team-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.55fr) minmax(280px, 0.95fr);
    gap: 24px;
    align-items: start;
  }
  .team-grid__side { position: sticky; top: 92px; }
  .team-grid__side > * + * { margin-top: 14px; }

  .rink { padding: 26px 22px 22px; }
  .rink__row { gap: 12px; }
  .pt { width: 104px; }
  .pt__face, .pt__initials { width: 52px; height: 52px; }
  .pt__name { font-size: 0.76rem; }

  /* --- Players: three columns, as a real roster board --- */
  .plist {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1px;
    background: var(--line-soft);
  }
  .prow { border-radius: 0; }

  .filters { gap: 10px; }
  .field { flex: 0 1 190px; }
  .filters .field--search { flex: 1 1 340px; }

  /* --- Leagues: tables side by side rather than stacked --- */
  .league-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
    gap: 18px;
    align-items: start;
  }
}

@media (min-width: 1400px) {
  .app { max-width: 1320px; }
  .plist { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Below 900px the header nav is hidden and the bottom bar takes over. */
@media (max-width: 899px) {
  .topnav { display: none; }
}

/* --------------------------------------------------------------- search */

.field--search { position: relative; }
.search-hint {
  margin: 8px 0 0;
  font-size: 0.76rem;
  color: var(--ink-muted);
}
.search-hint b { color: var(--ink); font-weight: 600; }

.chips { display: flex; gap: 6px; flex-wrap: wrap; margin: 10px 0 12px; }
.chip {
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-muted);
  border-radius: 999px;
  padding: 4px 11px;
  font-size: 0.76rem; font-weight: 600;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease),
              border-color var(--fast) var(--ease);
}
.chip:hover { background: var(--surface-2); color: var(--ink); }
.chip:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.chip--clear { border-color: var(--primary-dim); color: var(--primary); }

.flag {
  font-size: 0.66rem; font-weight: 700; letter-spacing: 0.04em;
  color: var(--ink-faint);
}

/* --------------------------------------------------------- player detail */

.sheet--player { max-height: 88vh; }

.pdetail__head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  /* Keep clear of the close button, which is positioned against the sheet
     rather than laid out in it: 34px wide, 12px from the edge, so it reaches
     46px in while the content stops at --pad (16px). Without this the price a
     manager paid sits underneath the x, which is the one number on this panel
     they cannot look up anywhere else. */
  padding-right: 38px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line-soft);
}
.pdetail__face, .pdetail__initials {
  width: 56px; height: 56px; border-radius: 50%;
  object-fit: cover; object-position: top center;
  background: var(--surface-3); border: 1px solid var(--line);
}
.pdetail__initials {
  display: grid; place-items: center;
  font-size: 1rem; font-weight: 700; color: var(--ink-muted);
}
.pdetail__price { text-align: right; }
.pdetail__price > .num { font-size: 1.25rem; font-weight: 700; color: var(--primary); }
.pdetail__drift { font-size: 0.66rem; color: var(--ink-muted); margin-top: 2px; }

.pdetail { margin-top: 14px; }
.pdetail > * + * { margin-top: 12px; }

.pdetail__actions {
  margin-top: 16px; padding-top: 14px;
  border-top: 1px solid var(--line-soft);
}
.pdetail__actions > * + * { margin-top: 10px; }

/* Season numbers. A plain grid of figures, not a row of decorated tiles. */
.statgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
  gap: 1px;
  margin-top: 12px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.statgrid__cell { background: var(--surface); padding: 8px 10px; }
.statgrid__value { font-size: 0.95rem; font-weight: 650; }
.statgrid__label { font-size: 0.64rem; color: var(--ink-muted); margin-top: 1px; }

/* Recent form: the bar makes a good night legible without reading numbers. */
.form-list { margin-top: 10px; display: flex; flex-direction: column; gap: 1px; }
.form-row {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr) auto 60px 44px;
  gap: 8px; align-items: center;
  padding: 6px 0;
  font-size: 0.76rem;
}
.form-row + .form-row { border-top: 1px solid var(--line-soft); }
.form-row__date { color: var(--ink-muted); }
.form-row__opp { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.form-row__stat { color: var(--ink-muted); font-size: 0.7rem; white-space: nowrap; }
.form-row__bar {
  height: 5px; border-radius: 999px;
  background: var(--surface-2); overflow: hidden;
}
.form-row__fill {
  height: 100%; width: 100%; border-radius: 999px;
  background: var(--primary);
  transform-origin: left center;
  transition: transform var(--med) var(--ease);
}
.form-row__fill.is-neg { background: var(--alert); }
.form-row__pts { text-align: right; font-weight: 700; }

@media (max-width: 420px) {
  .form-row { grid-template-columns: 48px minmax(0, 1fr) auto 40px; }
  .form-row__bar { display: none; }
}

@media (min-width: 900px) {
  /* On a desktop a bottom sheet is wrong: centre it as a dialog. */
  .sheet--player {
    left: 50%; bottom: auto; top: 50%;
    transform: translate(-50%, -50%);
    width: min(680px, calc(100vw - 48px));
    border-radius: var(--radius-lg);
    border: 1px solid var(--line);
    animation: pop var(--med) var(--ease);
    max-height: 84vh;
  }
  .sheet--player .sheet__grip { display: none; }
  @keyframes pop {
    from { opacity: 0; transform: translate(-50%, -48%) scale(0.98); }
  }
}

/* Career table on a phone: the league name is the only wide column, so it
   truncates rather than wrapping every row to three lines. */
@media (max-width: 520px) {
  .pdetail .table { font-size: 0.78rem; }
  .pdetail .table th, .pdetail .table td { padding: 7px 6px; }
  .pdetail .table td:nth-child(2) { max-width: 128px; }
  .pdetail .table td:nth-child(2) > div,
  .pdetail .table td:nth-child(2) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* ==========================================================================
   The ice sheet
   --------------------------------------------------------------------------
   Replaces the first squad view. A rink with real markings, and players as
   jersey shapes carrying their squad number in their club's colour — which
   is how a hockey fan already reads a team sheet. Colours come from the
   clubs' own crests (see app/clubs.py).
   ========================================================================== */

.ice {
  position: relative;
  border: 1px solid var(--line);
  border-radius: 20px;
  overflow: hidden;
  /* Brighter at the top, as if lit from the stands. */
  background: linear-gradient(180deg,
    oklch(0.285 0.014 215) 0%,
    oklch(0.205 0.010 215) 100%);
  padding: 18px 10px 14px;
}
.ice__markings { position: absolute; inset: 0; pointer-events: none; }
.ice__line { position: absolute; left: 0; right: 0; height: 1px; }
.ice__line--blue { background: oklch(0.66 0.13 245 / 0.52); }
.ice__line--red  { background: oklch(0.68 0.21 28 / 0.55); }
.ice__circle {
  position: absolute; left: 50%; transform: translate(-50%, -50%);
  border: 1px solid oklch(0.66 0.13 245 / 0.28); border-radius: 50%;
}
.ice__crease {
  position: absolute; left: 50%; transform: translateX(-50%);
  width: 132px; height: 56px; border-radius: 132px 132px 0 0;
  border: 1px solid oklch(0.66 0.13 245 / 0.5);
  background: oklch(0.66 0.13 245 / 0.13);
}

.ice__unit { position: relative; margin-bottom: 18px; }
.ice__unit:last-child { margin-bottom: 0; }
.ice__tag {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  font-size: 0.6rem; font-weight: 800; letter-spacing: 0.12em;
  color: var(--ink-faint); margin-bottom: 9px;
}
.ice__tag i {
  font-style: normal; font-weight: 600; letter-spacing: 0;
  color: var(--ink-faint); opacity: 0.75;
}
.ice__row { display: flex; justify-content: center; gap: 7px; flex-wrap: wrap; }

/* ------------------------------------------------------------- a jersey */

.jsy {
  position: relative; width: 76px;
  border: 0; background: none; padding: 0;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  transition: transform var(--fast) var(--ease);
}
.jsy:hover { transform: translateY(-3px); }
.jsy:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; border-radius: 8px; }
.jsy__shirt {
  position: relative; width: 56px; height: 60px;
  /* Shoulders, sleeve notch, straight hem — a jersey, not a rounded box. */
  clip-path: polygon(23% 0, 77% 0, 100% 19%, 87% 33%, 87% 100%, 13% 100%, 13% 33%, 0 19%);
  display: grid; place-items: center;
  background: var(--club, var(--surface-3));
  transition: filter var(--fast) var(--ease);
}
.jsy:hover .jsy__shirt { filter: brightness(1.12); }
.jsy__num {
  font-size: 1.15rem; font-weight: 800; letter-spacing: -0.03em;
  color: var(--club-ink, var(--ink));
  text-shadow: 0 1px 1px oklch(0 0 0 / 0.3);
}
.jsy__name {
  font-size: 0.7rem; font-weight: 650; line-height: 1.15; text-align: center;
  max-width: 100%;
  /* Two lines, not an ellipsis. A 76px tile cannot hold "Bjorkly Nordstrom"
     on one line -- it needs 103px -- and clipping it to "Bjorkly Nord…" loses
     the half of the name that identifies him. Wrapping at the space costs
     nothing; the height is reserved whether it wraps or not so the price
     pills below stay on a line with each other. A single unbroken name too
     long for the tile breaks mid-word rather than overflowing it. */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden; overflow-wrap: anywhere;
  min-height: 2.3em;
}
.jsy__club { font-size: 0.6rem; color: var(--ink-muted); }
.jsy__pts {
  font-size: 0.7rem; font-weight: 800; line-height: 1.35;
  color: var(--primary); background: var(--primary-wash);
  border-radius: 999px; padding: 0 7px; min-width: 30px; text-align: center;
}
.jsy__pts--zero { color: var(--ink-faint); background: var(--surface-3); }
.jsy__pts--neg  { color: var(--alert);     background: var(--alert-wash); }
.jsy__pts--price { color: var(--ink-muted); background: var(--surface-3); }
.jsy__drift {
  font-size: 0.5rem; margin-left: 2px; vertical-align: 1px;
  opacity: 0.75; color: currentColor;
}

.jsy--out { opacity: 0.45; }
.jsy--empty .jsy__shirt {
  background: transparent;
  border: 1px dashed var(--line);
  clip-path: polygon(23% 0, 77% 0, 100% 19%, 87% 33%, 87% 100%, 13% 100%, 13% 33%, 0 19%);
}
.jsy--empty .jsy__num { color: var(--ink-faint); font-weight: 400; font-size: 1.4rem; text-shadow: none; }
.jsy--empty:hover .jsy__shirt { border-color: var(--primary-dim); }
.jsy--empty .jsy__name { color: var(--ink-faint); font-weight: 500; }

.jsy__badge {
  position: absolute; top: -5px; right: 6px;
  width: 20px; height: 20px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 0.62rem; font-weight: 800;
  border: 2px solid oklch(0.21 0.011 215);
}
.jsy__badge--c { background: var(--alert); color: oklch(0.99 0 0); }
.jsy__badge--v { background: var(--surface-3); color: var(--ink); }

@media (min-width: 900px) {
  .ice { padding: 26px 20px 22px; }
  .ice__row { gap: 12px; }
  .jsy { width: 92px; }
  .jsy__shirt { width: 68px; height: 72px; }
  .jsy__num { font-size: 1.4rem; }
  .jsy__name { font-size: 0.78rem; }
}

/* Four tabs now, so the bar splits four ways on a phone. */
.tabbar--4 { grid-template-columns: repeat(4, 1fr); }
.tabbar--4 button { font-size: 0.64rem; }

/* ------------------------------------------------------ segmented control */

.segmented {
  display: inline-flex; gap: 2px;
  padding: 3px; margin-bottom: 14px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 999px;
}
.segmented button {
  border: 0; background: none; color: var(--ink-muted);
  padding: 7px 16px; border-radius: 999px;
  font-size: 0.82rem; font-weight: 600;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.segmented button:hover { color: var(--ink); }
.segmented button[aria-selected="true"] { background: var(--primary); color: var(--primary-ink); }
.segmented button:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* -------------------------------------------------------------- matches */

.daygroup + .daygroup { margin-top: 18px; }
.daygroup__day {
  font-size: 0.7rem; font-weight: 800; letter-spacing: 0.06em;
  color: var(--ink-muted); margin-bottom: 8px;
}
.matchlist { display: grid; gap: 8px; }
@media (min-width: 900px) {
  .matchlist { grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); }
}

.match {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 10px; align-items: center;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 12px 14px;
}
.match__side { display: flex; align-items: center; gap: 8px; min-width: 0; }
.match__side--away { flex-direction: row-reverse; text-align: right; }
.match__dot { width: 10px; height: 10px; border-radius: 3px; background: var(--club, var(--line)); flex: 0 0 auto; }
.match__club { font-size: 0.85rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.match__score {
  font-size: 1.05rem; font-weight: 750; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.match__time { font-size: 0.82rem; font-weight: 650; color: var(--ink-muted); white-space: nowrap; }
.match__meta {
  grid-column: 1 / -1;
  display: flex; gap: 10px; flex-wrap: wrap;
  font-size: 0.68rem; color: var(--ink-muted);
  padding-top: 8px; margin-top: 2px;
  border-top: 1px solid var(--line-soft);
}
.match__stars { grid-column: 1 / -1; display: grid; gap: 3px; }
.match__star {
  display: flex; justify-content: space-between; gap: 8px;
  font-size: 0.72rem;
}
.match__star b { color: var(--primary); font-weight: 700; }
.match__winner { color: var(--ink); }
.match__loser { color: var(--ink-muted); }

/* ==========================================================================
   Light theme
   --------------------------------------------------------------------------
   Not an inverted dark theme. The scene changes: instead of a rink at night
   it is a programme read in daylight, so the surface is a cool off-white
   rather than a warm cream, and the ink is near-black rather than grey.
   Every token is redefined; nothing is left to inherit a dark value.
   ========================================================================== */

:root[data-theme="light"] {
  --bg:          oklch(0.975 0.004 215);
  --surface:     oklch(1.000 0 0);
  --surface-2:   oklch(0.958 0.005 215);
  --surface-3:   oklch(0.920 0.007 215);
  --line:        oklch(0.855 0.008 215);
  --line-soft:   oklch(0.915 0.006 215);

  --ink:         oklch(0.215 0.012 215);
  --ink-muted:   oklch(0.455 0.014 215);   /* 7.4:1 on --bg */
  --ink-faint:   oklch(0.575 0.014 215);   /* 4.6:1 on --bg */

  --primary:     oklch(0.52 0.135 150);
  --primary-dim: oklch(0.63 0.115 150);
  --primary-ink: oklch(0.995 0 0);
  --primary-wash: oklch(0.52 0.135 150 / 0.11);

  --alert:       oklch(0.52 0.200 28);
  --alert-wash:  oklch(0.52 0.200 28 / 0.10);
  --warn:        oklch(0.58 0.130 70);

  --shadow-1: 0 1px 2px oklch(0.3 0.02 215 / 0.10);
  --shadow-2: 0 8px 26px oklch(0.3 0.02 215 / 0.14);
}

:root[data-theme="light"] .topbar {
  background: oklch(0.975 0.004 215 / 0.86);
}
:root[data-theme="light"] .tabbar {
  background: oklch(1 0 0 / 0.92);
}
/* The rink keeps its dark ice even in light mode: a white sheet of white-on-
   white would lose the jerseys entirely, and a rink is a dark room anyway. */
:root[data-theme="light"] .ice {
  background: linear-gradient(180deg,
    oklch(0.30 0.014 215) 0%, oklch(0.225 0.011 215) 100%);
  border-color: oklch(0.42 0.015 215);
}
:root[data-theme="light"] .ice__tag { color: oklch(0.72 0.012 215); }
:root[data-theme="light"] .jsy__name { color: oklch(0.97 0.004 215); }
:root[data-theme="light"] .jsy__club { color: oklch(0.74 0.012 215); }
:root[data-theme="light"] .jsy__badge { border-color: oklch(0.26 0.012 215); }
:root[data-theme="light"] .jsy--empty .jsy__shirt { border-color: oklch(0.45 0.015 215); }
:root[data-theme="light"] .jsy--empty .jsy__name,
:root[data-theme="light"] .jsy--empty .jsy__num { color: oklch(0.68 0.012 215); }
:root[data-theme="light"] .jsy__pts--zero,
:root[data-theme="light"] .jsy__pts--price {
  background: oklch(0.40 0.014 215); color: oklch(0.85 0.01 215);
}
:root[data-theme="light"] .backdrop { background: oklch(0.25 0.02 215 / 0.4); }

/* ==========================================================================
   The bank — budget made prominent
   --------------------------------------------------------------------------
   The old three-number strip was easy to miss, and the budget is the whole
   game. This states what is left in large type, with the spend bar directly
   under it and a warning tone the moment it goes over.
   ========================================================================== */

.bank {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 14px 16px;
  margin-bottom: 14px;
}
.bank__top {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
}
.bank__left { display: flex; align-items: baseline; gap: 10px; }
.bank__figure {
  font-size: 2rem; font-weight: 750; line-height: 1;
  letter-spacing: -0.02em; color: var(--primary);
}
.bank__figure.is-over { color: var(--alert); }
.bank__unit { font-size: 0.8rem; font-weight: 600; color: var(--ink-muted); }
.bank__right {
  text-align: right; display: flex; gap: 16px;
  flex-wrap: wrap; justify-content: flex-end;
}
@media (max-width: 420px) { .bank__right { gap: 11px; } }
.bank__stat { display: flex; flex-direction: column; gap: 1px; }
.bank__stat b { font-size: 1rem; font-weight: 700; line-height: 1.1; }
.bank__stat span { font-size: 0.66rem; color: var(--ink-muted); }

.bank__track {
  height: 8px; border-radius: 999px; margin-top: 12px;
  background: var(--surface-2); overflow: hidden;
  border: 1px solid var(--line-soft);
}
.bank__fill {
  height: 100%; width: 100%; border-radius: 999px;
  background: var(--primary);
  transform-origin: left center; transform: scaleX(0);
  transition: transform var(--med) var(--ease), background var(--fast) var(--ease);
}
.bank__fill.is-over { background: var(--alert); }
.bank__note { font-size: 0.72rem; color: var(--ink-muted); margin-top: 8px; }
.bank__note.is-over { color: var(--alert); font-weight: 600; }
/* Why Spent and Worth now disagree. Deliberately not coloured as good or
   bad news: a price rise costs the manager nothing. */
.bank__note--drift { color: var(--ink-muted); }

@media (min-width: 900px) {
  .bank__figure { font-size: 2.4rem; }
}

/* ------------------------------------------------------------- profile */

.profile__head { display: flex; align-items: center; gap: 14px; margin-bottom: 4px; }
.avatar {
  width: 64px; height: 64px; border-radius: 50%;
  object-fit: cover; background: var(--surface-3);
  border: 2px solid var(--line);
}
.avatar--initials {
  display: grid; place-items: center;
  font-size: 1.3rem; font-weight: 750; color: var(--ink-muted);
}
.swatches { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.swatch {
  width: 38px; height: 38px; border-radius: 10px;
  border: 2px solid transparent; cursor: pointer;
  background: var(--sw); position: relative;
  transition: transform var(--fast) var(--ease);
}
.swatch:hover { transform: scale(1.08); }
.swatch:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.swatch[aria-pressed="true"] { border-color: var(--ink); }
.swatch[aria-pressed="true"]::after {
  content: "✓"; position: absolute; inset: 0;
  display: grid; place-items: center;
  font-size: 0.85rem; font-weight: 800; color: var(--sw-ink, #fff);
}
.seg-theme { display: flex; gap: 6px; margin-top: 8px; }
.seg-theme button {
  flex: 1; padding: 9px 6px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); background: var(--surface);
  font-size: 0.8rem; font-weight: 600; color: var(--ink-muted);
}
.seg-theme button[aria-pressed="true"] {
  border-color: var(--primary); color: var(--primary); background: var(--primary-wash);
}
.field--stack { flex-direction: column; align-items: stretch; padding: 0; border: 0; }
.field--stack > span { font-size: 0.72rem; color: var(--ink-muted); margin-bottom: 5px; }
.field--stack input {
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); padding: 10px 12px; color: var(--ink);
  font-size: 0.9rem;
}
.field--stack input:focus { outline: none; border-color: var(--primary-dim); }
.motto {
  font-size: 0.74rem; color: var(--ink-muted); font-style: italic;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.identity {
  display: flex; align-items: center; gap: 10px;
  border: 0; background: none; padding: 0; text-align: left; min-width: 0;
  border-radius: var(--radius-sm);
}
.identity:hover .topbar__title h1 { text-decoration: underline; text-underline-offset: 3px; }
.identity:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }
.identity .avatar { width: 38px; height: 38px; border-width: 1px; }
.identity .avatar--initials { font-size: 0.82rem; }

.pending-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  padding: 10px 0;
  border-top: 1px solid var(--line-soft);
}
.pending-row:first-of-type { border-top: 0; }

/* ----------------------------------------------------- gameweek picker ---
   A list of the whole season, one row a week. Three columns because there are
   three questions: when is it, what is on, and can I still change it. The
   middle one is the reason this screen exists. */

.gwlist { display: flex; flex-direction: column; gap: 2px; }

.gwrow {
  display: grid;
  grid-template-columns: 5.5rem minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  width: 100%;
  padding: 10px 12px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm, 8px);
  background: none;
  text-align: left;
  font: inherit;
  color: var(--ink);
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.gwrow:hover { background: var(--surface-2); border-color: var(--line-soft); }
.gwrow:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.gwrow.is-current {
  background: var(--primary-wash);
  border-color: var(--primary-dim);
}

.gwrow__when { display: flex; flex-direction: column; gap: 1px; }
.gwrow__when b { font-weight: 700; }
.gwrow__shape { display: flex; flex-direction: column; gap: 1px; font-size: 0.82rem; }
.gwrow__state { justify-self: end; }

.gwtag {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--line);
  font-size: 0.66rem;
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-muted);
  white-space: nowrap;
}
.gwtag--open {
  border-color: var(--primary-dim);
  color: var(--primary);
  background: var(--primary-wash);
}

/* At phone width the tag has nowhere to go, so it drops under the fixtures
   line rather than squeezing the two columns that carry the information. */
@media (max-width: 460px) {
  .gwrow { grid-template-columns: 4.5rem minmax(0, 1fr); }
  .gwrow__state { grid-column: 2; justify-self: start; }
}

/* ==========================================================================
   The guide
   --------------------------------------------------------------------------
   Long-form reading, so this is the one place in the app that gets prose
   measure, generous leading and a real heading hierarchy. Everything else
   is a tool; this is a document.
   ========================================================================== */

.help-btn {
  width: 30px; height: 30px; flex: 0 0 auto;
  border-radius: 50%; border: 1px solid var(--line);
  background: var(--surface); color: var(--ink-muted);
  font-size: 0.9rem; font-weight: 700; line-height: 1;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.help-btn:hover { color: var(--primary); border-color: var(--primary-dim); }
.help-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
/* On a wide screen the Guide is a tab in the nav, so the question mark is a
   second door to the same room and goes. Feedback has no second door: hiding
   it here meant that on any screen 900px or wider -- which is every desktop
   -- there was no way to send feedback at all, during a season whose whole
   point is collecting it. Only the question mark hides. */
@media (min-width: 900px) { #helpBtn { display: none; } }

.guide { padding-bottom: 40px; }
.guide__intro { margin-bottom: 22px; }
.guide__intro h1 { font-size: 1.6rem; margin-bottom: 8px; }

.guide__lead {
  font-size: 0.95rem; color: var(--ink-muted);
  max-width: 62ch; text-wrap: pretty; margin: 0 0 4px;
}

.guide__nav {
  display: flex; flex-wrap: wrap; gap: 6px;
  padding: 12px 0 18px;
  border-bottom: 1px solid var(--line-soft);
  margin-bottom: 8px;
}
.guide__navlink {
  font-size: 0.76rem; font-weight: 600;
  color: var(--ink-muted); text-decoration: none;
  border: 1px solid var(--line); border-radius: 999px;
  padding: 5px 11px;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.guide__navlink:hover { color: var(--primary); border-color: var(--primary-dim); }

.guide__section { padding: 26px 0; border-bottom: 1px solid var(--line-soft); scroll-margin-top: 84px; }
.guide__section:last-child { border-bottom: 0; }
.guide__h { font-size: 1.22rem; margin-bottom: 8px; }
.guide__h3 { font-size: 0.94rem; margin: 20px 0 8px; color: var(--ink); }

.guide__p {
  font-size: 0.9rem; line-height: 1.62;
  max-width: 68ch; text-wrap: pretty;
  margin: 12px 0;
}

/* A plain list in the guide, matching the body copy around it. */
.guide__list {
  margin: 10px 0 0; padding-left: 20px;
  /* Same measure as .guide__p: a list inside the prose, not a change of voice. */
  font-size: 0.9rem; line-height: 1.62; max-width: 68ch;
}
.guide__list b { font-weight: 650; }
.guide__list li + li { margin-top: 5px; }
.guide__p b { font-weight: 650; }

.guide__eg {
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  background: var(--surface);
  padding: 12px 14px; margin: 14px 0;
  max-width: 68ch;
}
.guide__eg-title {
  font-size: 0.66rem; font-weight: 800; letter-spacing: 0.08em;
  color: var(--primary); margin-bottom: 5px;
}
.guide__eg-body { font-size: 0.86rem; line-height: 1.55; color: var(--ink-muted); }
.guide__eg-body b { color: var(--ink); font-weight: 650; }

.guide__table { max-width: 420px; margin: 14px 0; }
.guide__chip {
  border: 1px solid var(--line-soft); border-radius: var(--radius);
  background: var(--surface); padding: 4px 16px 16px; margin: 14px 0;
  max-width: 68ch;
}
.guide__chip .guide__h3 { margin-top: 16px; }
.guide__chip-what {
  font-size: 0.84rem; color: var(--ink); margin: 0 0 4px;
  font-weight: 600;
}

@media (min-width: 900px) {
  .guide__body { max-width: 760px; }
  .guide__intro h1 { font-size: 2rem; }
}

/* ---------------------------------------------------------- avatar icons */

/* An icon avatar is drawn, not photographed, so it takes the accent the way
   the rest of the interface does. Same box as .avatar--initials. */
/* A solid accent disc with its own readable ink, rather than accent-on-wash:
   --primary-wash is translucent in most looks but solid in Terrace, where a
   wash background plus accent ink would be yellow on yellow. --primary-ink
   is always picked to be readable against --primary, here and in the accent
   the manager chooses. */
.avatar--icon {
  display: grid; place-items: center;
  background: var(--primary);
  color: var(--primary-ink);
}
.avatar--icon svg { width: 62%; height: 62%; }

.iconpick {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
  gap: 6px;
  margin-top: 8px;
}
.iconpick__btn {
  /* 44px is the smallest comfortable touch target, and eight fit a 375px
     sheet at that size. */
  aspect-ratio: 1;
  min-height: 44px;
  display: grid; place-items: center;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink-muted);
  transition: color var(--fast) var(--ease),
              border-color var(--fast) var(--ease),
              background var(--fast) var(--ease);
}
.iconpick__btn svg { width: 22px; height: 22px; }
.iconpick__btn:hover { color: var(--ink); border-color: var(--primary-dim); }
.iconpick__btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.iconpick__btn[aria-pressed="true"] {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--primary-ink);
}

/* ------------------------------------------------------------ live games */

.livebar {
  border: 1px solid oklch(0.66 0.20 28 / 0.42);
  border-radius: var(--radius);
  background: var(--alert-wash);
  padding: 12px 14px;
}
.livebar__head { display: flex; align-items: center; gap: 8px; }
.livebar__head strong {
  font-size: 0.72rem; font-weight: 800; letter-spacing: 0.1em;
  color: var(--alert);
}
.livebar__sub { font-size: 0.74rem; color: var(--ink-muted); }

.livebar__dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--alert); flex: 0 0 auto;
  animation: livepulse 2s ease-in-out infinite;
}
@keyframes livepulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}
@media (prefers-reduced-motion: reduce) {
  .livebar__dot { animation: none; }
}

.livebar__games {
  display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px;
}
.livegame {
  display: flex; align-items: center; gap: 7px;
  border: 1px solid var(--line-soft); border-radius: var(--radius-sm);
  background: var(--surface); padding: 6px 10px;
}
.livegame__code {
  font-size: 0.68rem; font-weight: 800; letter-spacing: 0.03em;
  color: var(--club, var(--ink-muted));
}
.livegame__score {
  font-size: 0.86rem; font-weight: 750; font-variant-numeric: tabular-nums;
}
.livegame__period {
  font-size: 0.64rem; font-weight: 700; text-transform: uppercase;
  color: var(--alert); margin-left: 2px;
}
.livebar__note { font-size: 0.68rem; color: var(--ink-muted); margin-top: 9px; }

.live-badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 0.66rem; font-weight: 800; letter-spacing: 0.08em;
  color: var(--alert);
  border: 1px solid oklch(0.66 0.20 28 / 0.45);
  border-radius: 999px; padding: 4px 9px;
  white-space: nowrap;
}
.live-badge[hidden] { display: none; }

/* ==========================================================================
   iOS zoom-on-focus
   --------------------------------------------------------------------------
   Safari on iOS zooms the whole page in when you focus a form control whose
   font-size is under 16px — and it does not zoom back out afterwards. The
   page then looks permanently too big and has to be pinched back by hand.
   Every control here was 13.6px, so tapping the search box broke the layout
   until the user fixed it themselves.
   16px on touch devices only; pointer devices keep the tighter sizing.
   ========================================================================== */

@media (pointer: coarse) {
  .field input,
  .field select,
  .field--stack input,
  input[type="search"],
  input[type="text"],
  select,
  textarea {
    font-size: 16px;
  }
}

/* ----------------------------------------------------------- sheet close */

.sheet__close {
  position: absolute; top: 10px; right: 12px;
  width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--line);
  background: var(--surface-2); color: var(--ink-muted);
  font-size: 1.1rem; line-height: 1;
  z-index: 1;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.sheet__close:hover { color: var(--ink); border-color: var(--primary-dim); }
.sheet__close:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

.sheet { position: fixed; }
.sheet--player, .sheet { padding-top: 22px; }

/* A grip that says "drag or tap me", plus a wide tap target above the sheet
   so flicking down or tapping the gap closes it — the two things people
   actually try on a phone. */
.sheet__grip {
  cursor: pointer;
  width: 44px; height: 5px;
  transition: background var(--fast) var(--ease);
}
.sheet__grip:hover { background: var(--ink-faint); }

/* In the flow, directly under the squad actions. A floating bar covered the
   content behind it and moved as you scrolled, which read as an overlay
   rather than the end of the sheet. */
.sheet__done { margin-top: 10px; }
.guide__h4 { font-size: 0.86rem; font-weight: 650; margin: 18px 0 6px; color: var(--ink); }

/* --------------------------------------------------------------- report */

.flaglist { display: flex; flex-direction: column; gap: 1px; margin-top: 10px; }
.rflag {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 9px 0; width: 100%; text-align: left;
  border: 0; background: none; color: inherit;
  border-top: 1px solid var(--line-soft);
}
.flaglist .rflag:first-child { border-top: 0; }
.rflag:hover .rflag__text { color: var(--ink); }
.rflag:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.rflag__dot {
  width: 7px; height: 7px; border-radius: 50%; margin-top: 6px; flex: 0 0 auto;
}
.rflag--high .rflag__dot { background: var(--alert); }
.rflag--medium .rflag__dot { background: var(--warn); }
.rflag--low .rflag__dot { background: var(--ink-faint); }
.rflag__text { font-size: 0.84rem; line-height: 1.45; color: var(--ink-muted); }

/* ------------------------------------------------------ form trendlines */

/* Points per game, week by week, one row per player in the report. Drawn
   small on purpose: it is there to be read at a glance beside the numbers,
   not studied. Colours come from the accent tokens so it follows whatever
   theme and accent the manager has chosen. */

.table--trend td { vertical-align: middle; }
.table--trend th:nth-child(2) { width: 112px; }

.spark { display: block; overflow: visible; }
.spark__line {
  fill: none; stroke: var(--primary); stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}
.spark__dot { fill: var(--primary); }
.spark__dot--last { fill: var(--primary); stroke: var(--surface); stroke-width: 1.4; }
/* A week he did not play: a faint tick on the floor, so the absence is
   visible without pretending to be a score of zero. */
.spark__gap { fill: var(--ink-muted); opacity: 0.55; }
.spark__avg { stroke: var(--ink-muted); stroke-width: 1; stroke-dasharray: 2 3; opacity: 0.5; }
.spark__zero { stroke: var(--line); stroke-width: 1; }
.spark__empty { stroke: var(--line-soft); stroke-width: 1.5; stroke-dasharray: 3 3; }

.trendmark { margin-left: 5px; font-weight: 700; }
.trendmark--up { color: var(--primary); }
.trendmark--down { color: var(--alert); }
.trendmark--flat { color: var(--ink-muted); }

/* This is a phone game, so on a narrow screen the trendline stays and the
   cost goes: what a player is returning matters more in a report than what he
   set you back, and the price is on his own page anyway. */
@media (max-width: 460px) {
  .table--trend th:nth-child(5), .table--trend td:nth-child(5) { display: none; }
  .table--trend th:nth-child(2) { width: 86px; }
  .table--trend .spark { width: 82px; }
}

/* ==========================================================================
   The deadline — which week a save lands in, and how long is left
   --------------------------------------------------------------------------
   Sits directly above the save button, because that is the moment the answer
   matters. Coloured only when the week being looked at has already shut and
   the save is going somewhere else: that is a surprise, and a surprise should
   look like one.
   ========================================================================== */
.deadline {
  margin-top: 14px; padding: 10px 12px;
  border: 1px solid var(--line-soft); border-radius: 10px;
  /* --surface, not --surface-2. Measured across all five skins, the alert
     colour on --surface-2 drops to 4.30:1 in Terrace light, under AA for
     text this size; on --surface the worst case across every skin and theme
     is 5.16:1. The border is what separates the panel, not the fill. */
  background: var(--surface);
}
.deadline__head {
  font-size: 0.72rem; font-weight: 700; color: var(--alert);
  margin-bottom: 3px;
}
.deadline__line { font-size: 0.9rem; }
.deadline__when { font-size: 0.72rem; color: var(--ink-muted); margin-top: 2px; }
.deadline__when.is-soon { color: var(--alert); font-weight: 600; }
.deadline--rolled { border-color: var(--alert); }

/* ==========================================================================
   The budget, on the screen where it is being spent
   --------------------------------------------------------------------------
   Sticky, because the whole point is that it stays in view while scrolling a
   list of three hundred players. Deliberately smaller than the bank on My
   Team: that one is the headline of its screen, this one is a reminder.
   ========================================================================== */
.poolbank {
  position: sticky; top: 0; z-index: 3;
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  margin: 0 0 8px; padding: 8px 12px;
  border: 1px solid var(--line-soft); border-radius: 10px;
  background: var(--surface);
}
.poolbank__left { display: flex; align-items: baseline; gap: 6px; }
.poolbank__figure {
  font-size: 1.3rem; font-weight: 800; line-height: 1.1; color: var(--primary);
}
.poolbank__unit { font-size: 0.72rem; color: var(--ink-muted); }
.poolbank__right { display: flex; gap: 14px; }
.poolbank__stat { display: flex; align-items: baseline; gap: 4px; }
.poolbank__stat b { font-size: 0.85rem; font-weight: 700; }
.poolbank__stat span { font-size: 0.66rem; color: var(--ink-muted); }
.poolbank.is-over { border-color: var(--alert); }
.poolbank.is-over .poolbank__figure,
.poolbank.is-over .poolbank__unit { color: var(--alert); font-weight: 700; }

/* ==========================================================================
   Your players, while the games are on
   --------------------------------------------------------------------------
   The live strip gave the game score and left you to work out whether any of
   it was yours. This is the answer, in the order it arrived.
   ========================================================================== */
#liveStrip:empty { display: none; }
#liveStrip { margin-bottom: 12px; }

.livebar__yours {
  margin-top: 10px; padding-top: 10px;
  border-top: 1px solid var(--line-soft);
}
.livebar__yourshead {
  font-size: 0.66rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--ink-muted); margin-bottom: 6px;
}
.livegain {
  display: flex; align-items: baseline; gap: 8px;
  padding: 3px 0; font-size: 0.8rem;
}
.livegain + .livegain { border-top: 1px solid var(--line-soft); }
.livegain__name {
  font-weight: 650;
  /* A club flash, so a glance tells you who it was for as well as who. */
  border-left: 3px solid var(--club, var(--line)); padding-left: 6px;
}
.livegain__mult {
  font-size: 0.62rem; font-weight: 800; color: var(--primary-ink);
  background: var(--primary); border-radius: 999px; padding: 0 5px;
}
.livegain__pts {
  margin-left: auto; font-weight: 800; color: var(--primary);
  font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   Deleting an account
   --------------------------------------------------------------------------
   Shut by default and plainly marked. Loud enough that nobody arrives here by
   accident, quiet enough that it is not shouting at someone who only came to
   change their accent colour.
   ========================================================================== */
.danger {
  margin-top: 20px; padding-top: 16px;
  border-top: 1px solid var(--line-soft);
}
.danger__summary {
  cursor: pointer; font-size: 0.82rem; font-weight: 650;
  color: var(--alert); list-style: revert;
}
.danger__summary:focus-visible { outline: 2px solid var(--alert); outline-offset: 3px; }
.danger__body {
  font-size: 0.76rem; color: var(--ink-muted); margin: 10px 0 0;
  max-width: 60ch; line-height: 1.55;
}
.danger .field { margin-top: 12px; }
.danger__go {
  margin-top: 10px;
  background: var(--alert); color: var(--bg); border-color: var(--alert);
  font-weight: 700;
}
.danger__go:disabled { opacity: 0.45; }
