/* ==========================================================================
   HezzyRecruit — design system
   --------------------------------------------------------------------------
   Ported from HezzyAnalytics/frontend: charcoal #1e1e1e base with a film-grain
   overlay, a lime radial wash, a vignette; Hezzy green for depth, lime #D4EB00
   as the single accent; Adrianna Extended everywhere, Rock Salt for the
   wordmark only.

   The brand is dark by design (brandbook "B&W gritty slide"), so this
   deliberately commits to one look rather than exposing a light theme, and
   paints its own background and colours explicitly.

   Added for a data product, in the same voice: tabular figures, percentile
   micro-bars, tier chips, sample chips, and a dense sortable table idiom that
   the mobile-first analytics app never needed.
   ========================================================================== */

/* ---------- fonts ---------- */
@font-face { font-family: Adrianna; src: url("/static/fonts/AdriannaExtended-Light.otf") format("opentype");     font-weight: 300; font-display: swap; }
@font-face { font-family: Adrianna; src: url("/static/fonts/AdriannaExtended-Regular.otf") format("opentype");   font-weight: 400; font-display: swap; }
@font-face { font-family: Adrianna; src: url("/static/fonts/AdriannaExtended-DemiBold.otf") format("opentype");  font-weight: 600; font-display: swap; }
@font-face { font-family: Adrianna; src: url("/static/fonts/AdriannaExtended-Bold.otf") format("opentype");      font-weight: 700; font-display: swap; }
@font-face { font-family: Adrianna; src: url("/static/fonts/AdriannaExtended-ExtraBold.otf") format("opentype"); font-weight: 800; font-display: swap; }
@font-face { font-family: "Rock Salt"; src: url("/static/fonts/RockSalt-Regular.ttf") format("truetype"); font-weight: 400; font-display: swap; }

/* ---------- tokens ---------- */
:root {
  --charcoal:      #1e1e1e;
  --charcoal-deep: #161616;
  --green:         #004036;
  --green-dark:    #003028;
  --green-mid:     #006837;
  --green-bright:  #009245;
  --lime:          #D4EB00;
  --lime-dim:      #a9bd00;

  --ink:        #ffffff;
  --ink-2:      rgba(255,255,255,.74);
  --ink-3:      rgba(255,255,255,.52);
  --ink-4:      rgba(255,255,255,.34);
  --line:       rgba(255,255,255,.10);
  --line-2:     rgba(255,255,255,.16);
  --surface:    rgba(255,255,255,.04);
  --surface-2:  rgba(255,255,255,.065);
  --surface-3:  rgba(255,255,255,.10);

  --good:  #6fd28a;
  --warn:  #ffc857;
  --bad:   #ff7a6b;

  --r-sm: 8px;
  --r:    12px;
  --r-lg: 16px;
  --r-xl: 22px;

  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  --sans: Adrianna, system-ui, -apple-system, "Segoe UI", sans-serif;

  --pad: clamp(14px, 2.2vw, 28px);
  --shadow: 0 10px 34px rgba(0,0,0,.42);
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  overflow-x: hidden;   /* belt and braces: nothing should scroll the page sideways */
  min-height: 100vh;
  background-color: var(--charcoal);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  font-variant-numeric: tabular-nums;
}

/* ---------- page background: the brandbook texture stack ---------- */
.hz-bg { position: fixed; inset: 0; z-index: -10; pointer-events: none; }
.hz-bg-base { position: absolute; inset: 0; background-color: #1e1e1e; }
.hz-bg-grain {
  position: absolute; inset: 0; opacity: .38;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 200px 200px;
}
.hz-bg-spray {
  position: absolute; inset: 0;
  background:
    radial-gradient(ellipse 90% 55% at 18% 0%, rgba(212,235,0,.085) 0%, transparent 55%),
    radial-gradient(ellipse 70% 50% at 92% 8%, rgba(0,146,69,.10) 0%, transparent 60%);
}
.hz-bg-vignette {
  position: absolute; inset: 0;
  background: radial-gradient(ellipse 130% 85% at 50% 38%, transparent 28%, rgba(0,0,0,.5) 100%);
}

/* ---------- typography ---------- */
h1, h2, h3, h4 { margin: 0; font-weight: 800; letter-spacing: -.01em; line-height: 1.15; }
h1 { font-size: clamp(24px, 3.2vw, 38px); }
h2 { font-size: clamp(18px, 2vw, 23px); }
h3 { font-size: 16px; font-weight: 700; }
p  { margin: 0 0 .7em; }
a  { color: inherit; text-decoration: none; }
a:hover { color: var(--lime); }

.wordmark { font-family: "Rock Salt", cursive; font-weight: 400; letter-spacing: 0; }

.label {
  font-size: 10.5px; font-weight: 700; letter-spacing: .19em;
  text-transform: uppercase; color: rgba(212,235,0,.82);
}
.label-dim { color: var(--ink-4); }
.sub { color: var(--ink-3); font-size: 13px; }
.tiny { font-size: 11.5px; color: var(--ink-3); }
.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.nowrap { white-space: nowrap; }
.dim { color: var(--ink-3); }
.lime { color: var(--lime); }

/* ---------- layout ---------- */
.shell { max-width: 1560px; margin: 0 auto; padding: 0 var(--pad) 90px; }
.shell-narrow { max-width: 1100px; }
.stack   { display: flex; flex-direction: column; gap: 18px; }
.stack-s { display: flex; flex-direction: column; gap: 10px; }
.row     { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.row-tight { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.spread  { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
.grid    { display: grid; gap: 14px; }
/* `.g2` is auto-fit, so with two children it is a genuine two-up and with four it
   becomes three-up-plus-one. `.g2x` is for the pages that mean exactly two columns —
   the quality report's tables were being squeezed into 386 px and losing their last
   two columns off the right edge. */
.g2  { grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr)); }
/* Cards of unequal height sitting in a row. Stretching the short one to match the tall
   one is what left half of the Score breakdown empty — `start` lets each card end where
   its content does, which is what a card is for. */
.g-pair { grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), 1fr));
          align-items: start; }
/* Two cards that should END level with each other. `start` is right when a short card
   has nothing to fill the difference with; here the breakdown's rows can spread to take
   up the slack, so the pair stretches and the rows distribute. Equal by construction,
   for any player, rather than by guessing at pixel heights. */
.g-even { grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), 1fr));
          align-items: stretch; }
.g-even > .card { display: flex; flex-direction: column; }
.g2x { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* Six cohort cards, three per row. */
/* Four cohort cards side by side, then 2x2, then stacked. align-items: start so a
   short cohort is a short card rather than a stretched one with a blank half. */
.g-cohorts { grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: start; }
@media (max-width: 1360px) { .g-cohorts { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 660px)  { .g-cohorts { grid-template-columns: minmax(0, 1fr); } }

/* At four across a card is ~375 px, so the meta line truncates instead of wrapping into
   a ragged second row. The full text stays in the title attribute. */
.g-cohorts .meta-1 {
  display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
@media (max-width: 980px) { .g2x { grid-template-columns: minmax(0, 1fr); } }
.g3 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); align-items: start; }
.g4 { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.g6 { grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }
/* The player page's read / breakdown / radar trio. A fixed three-column template did
   not collapse, so on a phone every card was a 110 px column of one-word lines. */
.g-profile { grid-template-columns: minmax(0,1.15fr) minmax(0,1fr) minmax(0,.85fr); }
@media (max-width: 1180px) { .g-profile { grid-template-columns: minmax(0,1fr) minmax(0,1fr); } }
@media (max-width: 780px)  { .g-profile { grid-template-columns: 1fr; } }
.grow { flex: 1 1 auto; min-width: 0; }

/* ---------- header ---------- */
.hz-header {
  position: sticky; top: 0; z-index: 60;
  background: rgba(22,22,22,.9);
  backdrop-filter: blur(14px) saturate(1.2);
  border-bottom: 1px solid var(--line);
}
.hz-header-in {
  max-width: 1560px; margin: 0 auto; padding: 9px var(--pad);
  display: flex; align-items: center; gap: 16px;
}
.hz-logo { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }
.hz-logo img { width: 34px; height: 34px; display: block; }
.hz-logo-txt { display: flex; flex-direction: column; line-height: 1; }
.hz-logo-txt b { font-size: 15px; font-weight: 800; letter-spacing: .02em; }
.hz-logo-txt span { font-size: 9px; letter-spacing: .22em; color: var(--ink-4); text-transform: uppercase; margin-top: 3px; }

.hz-nav { display: flex; gap: 2px; flex-wrap: wrap; }
.hz-nav a {
  padding: 7px 12px; border-radius: 9px; font-size: 12px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
  transition: background .14s, color .14s;
}
.hz-nav a:hover { color: var(--lime); background: var(--surface); }
.hz-nav a.on { background: var(--lime); color: var(--green); }

.hz-search { flex: 1 1 300px; min-width: 200px; max-width: 560px; position: relative; }
/* `.hz-search input` and the generic `input[type="search"]` rule below have the SAME
   specificity, and the generic one is declared later — so it was winning and the header
   box lost its 34 px left padding, putting the magnifier on top of the first letter.
   Scoped to the form element to break the tie deliberately rather than by source order. */
.hz-search input[type="search"] {
  width: 100%; padding: 9px 12px 9px 34px; font: inherit; font-size: 13px;
  color: var(--ink); background: var(--surface); border: 1px solid var(--line);
  border-radius: 10px; outline: none; transition: border-color .14s, background .14s;
  -webkit-appearance: none; appearance: none;
}
.hz-search input[type="search"]::placeholder { color: var(--ink-4); }
.hz-search input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; }
.hz-search input[type="search"]:focus {
  border-color: rgba(212,235,0,.55); background: var(--surface-2);
}
.hz-search svg { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); opacity: .4; }
.hz-search kbd {
  position: absolute; right: 9px; top: 50%; transform: translateY(-50%);
  font-family: var(--mono); font-size: 10px; color: var(--ink-4);
  border: 1px solid var(--line); border-radius: 5px; padding: 1px 5px;
}

/* ---------- page head ---------- */
.page-head { padding: 26px 0 18px; }
.page-head h1 { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.page-head .sub { max-width: 78ch; margin-top: 7px; }

/* ---------- cards ---------- */
.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 16px;
}
.card-lg { border-radius: var(--r-xl); padding: 20px; }
/* `overflow: visible`, not hidden: a help popup opening from a flush card's heading
   has to escape it. The table below keeps its own clipped corners instead. */
.card-flush { padding: 0; overflow: visible; }
.card-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap; margin-bottom: 12px;
}
.card-accent { border-color: rgba(212,235,0,.28); background: rgba(212,235,0,.045); }
.card-green  { border-color: rgba(0,146,69,.34);  background: rgba(0,146,69,.07); }

/* ---------- stat tiles ---------- */
.tile {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); padding: 12px 13px;
}
.tile .label { display: block; margin-bottom: 5px; }
.tile b { font-size: clamp(19px, 2.1vw, 26px); font-weight: 800; color: var(--lime); display: block; line-height: 1.1; }
.tile .tiny { margin-top: 3px; display: block; }
.tile.plain b { color: var(--ink); }

/* ---------- chips / badges ---------- */
.chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: 999px; font-size: 11px; font-weight: 700;
  letter-spacing: .04em; border: 1px solid var(--line-2); background: var(--surface-2);
  color: var(--ink-2); white-space: nowrap;
}
.chip-lime  { background: rgba(212,235,0,.15); border-color: rgba(212,235,0,.45); color: var(--lime); }
.chip-green { background: rgba(0,146,69,.2);  border-color: rgba(0,146,69,.5);  color: #7ee2a4; }
.chip-warn  { background: rgba(255,200,87,.14); border-color: rgba(255,200,87,.4); color: var(--warn); }
.chip-bad   { background: rgba(255,122,107,.14); border-color: rgba(255,122,107,.4); color: var(--bad); }
.chip-del {
  background: none; border: 0; padding: 0 0 0 4px; margin: 0; cursor: pointer;
  color: var(--ink-4); font: inherit; font-size: 10px; line-height: 1;
}
.chip-del:hover { color: var(--bad); }
.chip-x { cursor: pointer; }
.chip-x:hover { border-color: var(--bad); color: var(--bad); }

/* Sample chip: a rate without its sample is a lie, so it travels with the number. */
.sample {
  font-family: var(--mono); font-size: 10.5px; color: var(--ink-4);
  white-space: nowrap; letter-spacing: -.01em;
}

/* Tier chip: 1 = a country's top flight, dimming to 5. Shown next to any number
   that came from a single competition. */
.tier {
  display: inline-flex; align-items: center; justify-content: center;
  width: 19px; height: 19px; border-radius: 5px;
  font-size: 10.5px; font-weight: 800; font-family: var(--mono);
  border: 1px solid transparent; flex: 0 0 auto;
}
.tier-1 { background: var(--lime);              color: var(--green); }
.tier-2 { background: rgba(0,146,69,.85);       color: #eafff2; }
.tier-3 { background: rgba(0,64,54,.9);         color: #9fd8c3; border-color: rgba(0,146,69,.5); }
.tier-4 { background: var(--surface-3);         color: var(--ink-2); border-color: var(--line-2); }
.tier-5 { background: transparent;              color: var(--ink-4); border-color: var(--line-2); }
/* Appeared, not scored: the band keeps its colour so the level still reads at a glance,
   but the fill drops away so a three-minute cameo cannot pass for a season. */
.tier-ghost { background: transparent !important; box-shadow: inset 0 0 0 1px currentColor; }
.tier-ghost.tier-1 { color: var(--lime); }
.tier-ghost.tier-2 { color: #7ee2a4; }
.tier-ghost.tier-3 { color: #9fd8c3; }
.tier-ghost.tier-4 { color: var(--ink-2); }
.tier-ghost.tier-5 { color: var(--ink-4); }
/* No fitted level at all is its own state, and must not read as the weakest band. */
.tier-none { background: transparent; color: var(--ink-4); border-style: dashed;
             border-color: var(--line-2); }

/* ---------- percentile bar ---------- */
.bar {
  /* display:block matters: as an inline span the 7 px height was ignored, so every
     standalone bar (outside a .bar-row grid, which blockifies its items) rendered as
     an invisible zero-height element. */
  display: block;
  position: relative; height: 7px; border-radius: 99px;
  background: var(--surface-3); overflow: hidden; min-width: 26px;
}
.bar > i { position: absolute; inset: 0 auto 0 0; border-radius: 99px; display: block; }
.bar::after {                 /* the 50th-percentile hairline */
  content: ""; position: absolute; left: 50%; top: -1px; bottom: -1px; width: 1px;
  background: rgba(255,255,255,.22);
}
.bar-tall { height: 10px; }
.bar-row { display: grid; grid-template-columns: minmax(20px,1fr) 24px; align-items: center; gap: 5px; }
/* The seven score components are the densest thing on the page; their cells get a
   tighter gutter so all seven fit a 1600 px laptop without horizontal scrolling. */

table.t td.c-score .bar-row { min-width: 46px; }
.bar-row .v { font-family: var(--mono); font-size: 11px; text-align: right; }

.n-elite > i { background: linear-gradient(90deg, var(--lime), #eaff4d); }
.n-high  > i { background: linear-gradient(90deg, var(--green-bright), var(--lime-dim)); }
.n-mid   > i { background: rgba(255,255,255,.42); }
.n-low   > i { background: rgba(255,200,87,.6); }
.n-poor  > i { background: rgba(255,122,107,.62); }

.n-elite.v, .v.n-elite { color: var(--lime); }
.n-high.v,  .v.n-high  { color: #a8e05a; }
.n-mid.v,   .v.n-mid   { color: var(--ink-2); }
.n-low.v,   .v.n-low   { color: var(--warn); }
.n-poor.v,  .v.n-poor  { color: var(--bad); }

/* ---------- heat cell ----------
   Seven percentile micro-bars do not fit a 1600 px laptop next to the identity and
   sample columns, and the bars were the first thing to get clipped. A heat cell is the
   same information in a third of the width: the number stays legible, and the tint
   carries the ranking so a column can be scanned without reading any of them. Bars are
   kept on the player page, where there is room and only seven rows. */
.heat {
  display: block; min-width: 30px; padding: 2px 4px; border-radius: 5px;
  font-family: var(--mono); font-size: 11.5px; text-align: center;
  border: 1px solid transparent;
}
.heat.n-elite { background: rgba(212,235,0,.92); color: #14200a; font-weight: 700; border-color: var(--lime); }
.heat.n-high  { background: rgba(212,235,0,.34); color: #eaf7a8; font-weight: 600; }
.heat.n-mid   { background: rgba(255,255,255,.10); color: var(--ink-2); }
.heat.n-low   { background: rgba(255,200,87,.16); color: #ffd98a; }
.heat.n-poor  { background: rgba(255,122,107,.18); color: #ffb3a8; }
.heat.na      { background: transparent; color: var(--ink-4); border-color: var(--line); }
td.c-score, th.c-score { padding-left: 3px !important; padding-right: 3px !important; }

/* ---------- score dial ---------- */
.score {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-width: 96px; padding: 10px 14px; border-radius: var(--r-lg);
  background: linear-gradient(160deg, rgba(212,235,0,.16), rgba(0,146,69,.10));
  border: 1px solid rgba(212,235,0,.36);
}
.score b { font-size: 34px; font-weight: 800; color: var(--lime); line-height: 1; }
.score span { font-size: 9.5px; letter-spacing: .18em; text-transform: uppercase; color: var(--ink-3); margin-top: 5px; }

/* Every rank, under the score they all describe. */
.ranks { text-align: right; font-size: 12.5px; color: var(--ink-3); line-height: 1.4; }
.ranks b { color: var(--lime); font-size: 15px; font-weight: 800; }
.ranks .tiny { display: block; color: var(--ink-4); }

/* ---------- tables: the interface for people who scan ---------- */
.tw { overflow-x: auto; border-radius: var(--r-lg); border: 1px solid var(--line);
       background: rgba(0,0,0,.14); scrollbar-color: var(--surface-3) transparent; }
.tw::-webkit-scrollbar { height: 9px; }
.tw::-webkit-scrollbar-thumb { background: var(--surface-3); border-radius: 9px; }
.tw::-webkit-scrollbar-thumb:hover { background: rgba(212,235,0,.4); }
.tw-flush { border: 0; border-radius: 0; }
table.t { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 12.5px; }
table.t thead th {
  position: sticky; top: 0; z-index: 3;
  background: #232323; color: var(--ink-3);
  font-size: 10px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  text-align: right; padding: 9px 7px; white-space: nowrap;
  border-bottom: 1px solid var(--line-2);
}
table.t thead th:first-child,
table.t thead th.l { text-align: left; }
table.t thead th.sortable { cursor: pointer; user-select: none; }
table.t thead th.sortable:hover { color: var(--lime); }
table.t thead th .arr { opacity: .45; font-size: 9px; margin-left: 3px; }
table.t thead th.on { color: var(--lime); }
table.t tbody td {
  padding: 7px 7px; text-align: right; white-space: nowrap;
  border-bottom: 1px solid rgba(255,255,255,.055); font-family: var(--mono);
  font-size: 12px;
}
table.t tbody td.l { text-align: left; font-family: var(--sans); font-size: 12.5px; }
/* Long explanatory cells (a validity note, a weight rationale) need to wrap; a nowrap
   note is a note nobody reads. */
table.t tbody td.wrap, table.t thead th.wrap {
  white-space: normal; font-family: var(--sans); min-width: 240px;
}
table.t tbody tr:hover td { background: rgba(212,235,0,.05); }
table.t tbody tr.sel td { background: rgba(212,235,0,.10); }
table.t tbody tr:last-child td { border-bottom: 0; }
table.t tbody tr.cursor td { box-shadow: inset 0 0 0 1px rgba(212,235,0,.35); }
table.t td.best { color: var(--lime); font-weight: 700; }
table.t .g { color: var(--ink-3); }

/* frozen first columns on the board */
/* Frozen columns. The score is frozen as well as the rank and the name, because a
   coach scanning right through 20 rate columns must never lose sight of the number
   the ranking is built on — it was off-screen in the first version. */
table.t.freeze { --f1w: 40px; --f2w: 174px; }
table.t.freeze thead th.f1, table.t.freeze tbody td.f1 { position: sticky; left: 0; z-index: 2; background: #202020; }
table.t.freeze thead th.f2, table.t.freeze tbody td.f2 {
  position: sticky; left: var(--f1w); z-index: 2; background: #202020; }
table.t.freeze thead th.f3, table.t.freeze tbody td.f3 {
  position: sticky; left: calc(var(--f1w) + var(--f2w)); z-index: 2; background: #202020;
  box-shadow: 6px 0 10px -6px rgba(0,0,0,.6); }
/* Without an f3, the shadow belongs on f2 so the frozen block still reads as a unit. */
table.t.freeze:not(:has(td.f3)) tbody td.f2,
table.t.freeze:not(:has(th.f3)) thead th.f2 { box-shadow: 6px 0 10px -6px rgba(0,0,0,.6); }
/* A column pinned to the RIGHT edge. The boards table is sixteen columns wide and
   scrolls; "remove this player" was the last of them, which meant it was off-screen and
   the only way to reach it was to scroll the table sideways first. An action a scout
   needs on every row cannot live past the horizon. */
table.t thead th.fr, table.t tbody td.fr {
  position: sticky; right: 0; z-index: 2; background: #202020;
  box-shadow: -8px 0 10px -6px rgba(0,0,0,.55);
}
table.t thead th.fr { z-index: 4; background: #262626; }
table.t tbody tr:hover td.fr { background: #262421; }

#coverage.freeze { --f1w: 34px; --f2w: 232px; }
#games.freeze, table.t.freeze.career { --f1w: 84px; --f2w: 208px; }
table.t.freeze thead th.f1, table.t.freeze thead th.f2, table.t.freeze thead th.f3 { z-index: 4; background: #262626; }
table.t.freeze tbody tr:hover td.f1,
table.t.freeze tbody tr:hover td.f2,
table.t.freeze tbody tr:hover td.f3 { background: #262421; }
table.t.freeze tbody tr.sel td.f1,
table.t.freeze tbody tr.sel td.f2,
table.t.freeze tbody tr.sel td.f3 { background: #2b2a1e; }

.pname { display: flex; align-items: center; gap: 8px; }
.pname b { font-weight: 700; font-size: 13px; }
.pname .meta { color: var(--ink-4); font-size: 11px; }
.rk { font-family: var(--mono); font-size: 11.5px; color: var(--ink-4); width: 34px; }
.rk b { color: var(--ink-2); font-size: 13px; }

/* Board row expansion: the scouting card without leaving the board. */
table.t tbody tr.cardrow td {
  background: rgba(212,235,0,.045); border-bottom: 1px solid var(--line-2);
  white-space: normal; padding: 14px 16px;
}
.cardrow-in { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }
@media (max-width: 900px) { .cardrow-in { grid-template-columns: 1fr; gap: 14px; } }

/* ---------- filter rail ---------- */
/* minmax(0, 1fr), not 1fr: a bare 1fr track is min-content sized, so the 30-column
   board table widened the grid column and pushed the ENTIRE page sideways instead of
   scrolling inside its own wrapper. min-width:0 on grid children is the same fix one
   level down. */
.board-layout { display: grid; grid-template-columns: 246px minmax(0, 1fr); gap: 16px; align-items: start; }
.board-layout > *, .grid > *, .cmpgrid > * { min-width: 0; }
@media (max-width: 1080px) { .board-layout { grid-template-columns: minmax(0, 1fr); } }
.rail { position: sticky; top: 66px; max-height: calc(100vh - 84px); overflow-y: auto; }
.rail::-webkit-scrollbar { width: 7px; }
.rail::-webkit-scrollbar-thumb { background: var(--surface-3); border-radius: 9px; }
.fgroup { border-bottom: 1px solid var(--line); padding: 12px 0; }
.fgroup:first-child { padding-top: 0; }
.fgroup:last-child { border-bottom: 0; padding-bottom: 0; }
.fgroup > .label { display: block; margin-bottom: 8px; }

.opts { display: flex; flex-wrap: wrap; gap: 5px; }
/* Inputs carry width:100%, so a plain flex row wrapped them onto separate lines. */
.pair { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.pair label { display: block; min-width: 0; }
.opt {
  padding: 4px 9px; border-radius: 8px; font-size: 11.5px; font-weight: 600;
  border: 1px solid var(--line); background: var(--surface); color: var(--ink-2);
  cursor: pointer; transition: .12s;
}
.opt:hover { border-color: var(--line-2); color: var(--ink); }
.opt.on { background: var(--lime); border-color: var(--lime); color: var(--green); font-weight: 700; }
.opt .n { font-family: var(--mono); font-size: 9.5px; opacity: .6; margin-left: 4px; }

/* The one filter group that is about recruiting rather than about basketball. It is
   set apart because a scout scanning the rail should not have to read it to find it. */
.fgroup-hi {
  border: 1px solid rgba(212, 235, 0, .22); border-radius: 10px;
  background: rgba(212, 235, 0, .04); padding: 10px 11px 12px;
}
.fgroup-hi .label { color: var(--lime); }

input[type="text"], input[type="number"], input[type="search"], select, textarea {
  width: 100%; padding: 7px 9px; font: inherit; font-size: 12.5px; color: var(--ink);
  background: var(--surface); border: 1px solid var(--line); border-radius: 8px;
  outline: none;
}
input:focus, select:focus, textarea:focus { border-color: rgba(212,235,0,.5); }
select { appearance: none; background-image: none; cursor: pointer; }
select option { background: #232323; color: var(--ink); }

/* Checkboxes are the one input that must NOT stretch: the shared width:100% rule put
   the box on its own line above its label. */
input[type="checkbox"] { width: auto; flex: 0 0 auto; accent-color: var(--lime);
  margin: 0; vertical-align: middle; }
label.check { display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
  font-size: 11.5px; color: var(--ink-3); }
label.check:hover { color: var(--ink-2); }

input[type="range"] { -webkit-appearance: none; width: 100%; height: 18px; background: transparent; cursor: pointer; }
input[type="range"]::-webkit-slider-runnable-track { height: 4px; border-radius: 9px; background: var(--surface-3); }
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; width: 13px; height: 13px; margin-top: -4.5px;
  border-radius: 50%; background: var(--lime); border: 0;
}

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 14px; border-radius: 10px; font-size: 12px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; cursor: pointer;
  border: 1px solid var(--line-2); background: var(--surface); color: var(--ink);
  transition: .13s; font-family: inherit;
}
.btn:hover { border-color: rgba(212,235,0,.55); color: var(--lime); }
.btn-primary { background: var(--lime); border-color: var(--lime); color: var(--green); }
.btn-primary:hover { background: #fff; border-color: #fff; color: var(--green); }
.btn-sm { padding: 5px 10px; font-size: 10.5px; }
.btn[disabled] { opacity: .4; cursor: not-allowed; }

/* ---------- recruiting pipeline ----------
   Status is the one thing on a board the model cannot supply, so it gets a colour of
   its own — a progression from neutral to lime, with "passed" greyed rather than red
   because deciding against a player is a normal outcome, not a failure. */
select.st {
  width: auto; min-width: 104px; padding: 3px 6px; font-size: 11px; font-weight: 700;
  letter-spacing: .04em; border-radius: 7px; cursor: pointer;
}
select.st-watching  { border-color: var(--line-2);            color: var(--ink-2); }
select.st-contacted { border-color: rgba(0,146,69,.45);       color: #7ee2a4;
                      background: rgba(0,146,69,.12); }
select.st-visit     { border-color: rgba(0,146,69,.7);        color: #9dedb9;
                      background: rgba(0,146,69,.2); }
select.st-offer     { border-color: rgba(212,235,0,.6);       color: var(--lime);
                      background: rgba(212,235,0,.14); }
select.st-committed { border-color: var(--lime);              color: var(--green);
                      background: var(--lime); }
select.st-passed    { border-color: var(--line);              color: var(--ink-4);
                      background: transparent; }
select.st-committed option { color: var(--ink); }

.nudge {
  padding: 0 3px !important; font-size: 11px; line-height: 1.4;
  color: var(--ink-3); border-color: var(--line); background: var(--surface);
}
.nudge:hover { color: var(--lime); border-color: rgba(212,235,0,.55); }

/* ---------- notes / callouts ---------- */
.note {
  font-size: 12px; color: var(--ink-3); padding: 9px 12px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line);
  border-left: 2px solid rgba(212,235,0,.5);
}
.note-warn { border-left-color: var(--warn); }
.note-bad  { border-left-color: var(--bad); }
.note-ok   { border-left-color: var(--green-bright); }
.note b { color: var(--ink-2); }

/* ---------- player profile ---------- */
.phead { display: grid; grid-template-columns: 1fr auto; gap: 20px; align-items: start; }
@media (max-width: 760px) { .phead { grid-template-columns: 1fr; } }
.phead h1 { font-size: clamp(26px, 3.6vw, 42px); }
.pfacts { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 10px; }
.pfact { display: flex; flex-direction: column; gap: 1px; }
.pfact .label { font-size: 9.5px; letter-spacing: .16em; }
.pfact b { font-size: 15px; font-weight: 700; }
/* A fact's value carries its own severity. Deliberately colour on the text rather than
   a pill: a bordered pill IS a chip, and a row of chips above the name is what this
   replaced. */
.pfact b.f-good { color: #7ee2a4; }
.pfact b.f-warn { color: var(--warn); }
.pfact b.f-bad  { color: var(--bad); }
.pfact b.f-dim  { color: var(--ink-4); font-weight: 600; }
.pfact b sup { font-size: 9px; opacity: .7; margin-left: 1px; }
.pfact .tiny { display: block; margin-top: 1px; line-height: 1.3; max-width: 30ch; }
/* The note under a fact is optional and rendered unconditionally so the browser can
   fill it after a click. Empty, it must take no room. */
.pfact .tiny:empty { display: none; }

/* Fills whatever height the row settles at.

   `space-evenly`, not `space-between`: between-mode pins the first row against the
   heading and the last against the card floor, then dumps all the slack into the middle
   gaps — so the gap between two attributes was twice the gap above the first one. Evenly
   gives the same space above, between and below. */
.brk { display: flex; flex-direction: column; gap: 8px; flex: 1 1 auto;
       justify-content: space-evenly; min-height: 0; }
.brk-row { display: grid; grid-template-columns: 126px 1fr 40px; gap: 11px;
           align-items: center; }
/* Name and its dot on one line. No caption underneath: six grey sub-lines turned a
   six-row list into a wall of text with bars hiding in it. */
.brk-row .nm { font-size: 12px; font-weight: 600; color: var(--ink-2);
               display: inline-flex; align-items: center; gap: 5px; }
.brk-row .v { font-family: var(--mono); font-size: 13.5px; text-align: right; font-weight: 700; }
@media (max-width: 520px) { .brk-row { grid-template-columns: 96px 1fr 36px; } }

.findings { display: flex; flex-direction: column; gap: 7px; }
.finding { display: flex; gap: 9px; font-size: 13px; line-height: 1.45; }
.finding .mk { flex: 0 0 auto; width: 16px; text-align: center; font-weight: 800; font-size: 12px; }
.finding.s .mk { color: var(--lime); }
.finding.w .mk { color: var(--bad); }
.finding.f .mk { color: var(--warn); }
.finding.c .mk { color: var(--ink-4); }
.finding .ev {
  display: block; font-family: var(--mono); font-size: 10px; color: var(--ink-4);
  margin-top: 2px; word-break: break-word;
}

.summary { font-size: 14.5px; line-height: 1.6; color: var(--ink-2); }

/* The Read runs full width now, so it splits internally: the prose in one column, the
   findings in the other. Edge-to-edge sentences at 1500 px are unreadable, and the
   card was the reason the three-column row above never lined up. */
.read-cols { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
             gap: 10px 28px; margin-top: 9px; align-items: start; }
@media (max-width: 900px) { .read-cols { grid-template-columns: minmax(0, 1fr); } }
.read-prose .summary { margin-top: 0; }
.read-findings { display: flex; flex-direction: column; gap: 2px; }
.summary b { color: var(--ink); }

/* ---------- charts ---------- */
.chart { width: 100%; display: block; overflow: visible; }
/* A viewBox SVG stretches to its container: a one-player compare turned a 250 px radar
   into a 1,300 px one with 60 px axis labels. Radars get a hard cap and centre; wide
   charts (age curves) still fill their card. */
.chart-radar { max-width: 208px; margin: -10px auto 0; }
.chart text { font-family: var(--sans); fill: var(--ink-3); font-size: 10px; }
.chart .ax { stroke: var(--line); stroke-width: 1; }
.chart .grid-l { stroke: rgba(255,255,255,.06); stroke-width: 1; }
.chart .curve { fill: none; stroke: rgba(255,255,255,.3); stroke-width: 1.6; }
.chart .curve-hi { fill: none; stroke: var(--lime); stroke-width: 2.2; }
.chart .dot { fill: var(--lime); stroke: var(--charcoal); stroke-width: 1.5; }
.chart .dot-2 { fill: var(--green-bright); }
.chart .area { fill: rgba(212,235,0,.12); stroke: none; }
.chart .radar-grid { fill: none; stroke: rgba(255,255,255,.09); stroke-width: 1; }
.chart .radar-shape { fill: rgba(212,235,0,.17); stroke: var(--lime); stroke-width: 1.8; }
.chart .radar-shape-2 { fill: rgba(0,146,69,.15); stroke: var(--green-bright); stroke-width: 1.8; }
/* Series 3 and 4 must NOT reuse --warn and --bad: an amber and a red radar read as
   "this player is a warning" and "this player is bad", which is a meaning the compare
   view does not have. Two neutral hues instead, both distinguishable from the lime. */
.chart .radar-shape-3 { fill: rgba(124,199,245,.13); stroke: #7cc7f5; stroke-width: 1.8; }
.chart .radar-shape-4 { fill: rgba(199,155,240,.13); stroke: #c79bf0; stroke-width: 1.8; }
.series-1 { border-color: var(--lime) !important;         color: var(--lime) !important; }
.series-2 { border-color: var(--green-bright) !important; color: #7ee2a4 !important; }
.series-3 { border-color: #7cc7f5 !important;             color: #7cc7f5 !important; }
.series-4 { border-color: #c79bf0 !important;             color: #c79bf0 !important; }
.chart .lbl { fill: var(--ink-3); font-size: 9.5px; letter-spacing: .06em; }
/* The sparkline shares the chart's line vocabulary but not its class, and an
   unstyled <polyline> defaults to fill:black — which renders a trend line as a solid
   blob. Every stroke-only shape in this file has to say so explicitly. */
.spark { display: block; overflow: visible; }
.spark .curve-hi { fill: none; stroke: var(--lime); stroke-width: 2; }
.spark .curve    { fill: none; stroke: rgba(255,255,255,.3); stroke-width: 1.4; }
.spark .dot      { fill: var(--lime); stroke: var(--charcoal); stroke-width: 1.2; }

.ladder { display: flex; flex-direction: column; gap: 3px; }
.ladder-step {
  display: grid; grid-template-columns: 26px 1fr auto; gap: 8px; align-items: center;
  font-size: 11.5px; padding: 3px 0;
}
.ladder-bar { height: 15px; border-radius: 4px; background: var(--surface-3); position: relative; }
.ladder-bar > i { position: absolute; inset: 0 auto 0 0; border-radius: 4px; background: linear-gradient(90deg, var(--green-mid), var(--lime)); }
.ladder-bar > span { position: absolute; left: 7px; top: 0; line-height: 15px; font-size: 10px; font-weight: 700; color: rgba(0,0,0,.72); }

/* ---------- misc ---------- */
.divider { height: 1px; background: var(--line); margin: 6px 0; }
.pill-list { display: flex; flex-wrap: wrap; gap: 6px; }
.cmpgrid { display: grid; gap: 14px; justify-content: start;
  grid-template-columns: repeat(var(--n, 4), minmax(240px, 340px)); }
@media (max-width: 900px) { .cmpgrid { grid-template-columns: 1fr; } }

.empty { padding: 40px 20px; text-align: center; color: var(--ink-3); font-size: 14px; }
.empty b { display: block; color: var(--ink); font-size: 17px; margin-bottom: 6px; }
.scroll-x { overflow-x: auto; }
.hide-sm { }
@media (max-width: 720px) { .hide-sm { display: none !important; } }

.footer {
  border-top: 1px solid var(--line); margin-top: 40px; padding: 18px 0 60px;
  font-size: 11.5px; color: var(--ink-3); display: flex; gap: 18px; flex-wrap: wrap;
}
.footer a { color: var(--ink-3); }
.footer a:hover { color: var(--lime); }

.toast {
  position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%) translateY(20px);
  background: var(--lime); color: var(--green); padding: 10px 18px; border-radius: 11px;
  font-size: 12.5px; font-weight: 700; box-shadow: var(--shadow); z-index: 200;
  opacity: 0; pointer-events: none; transition: opacity .18s, transform .18s;
}
.toast.on { opacity: 1; transform: translateX(-50%) translateY(0); }

.cmpbar {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 90;
  background: rgba(22,22,22,.96); backdrop-filter: blur(12px);
  border-top: 1px solid rgba(212,235,0,.3); padding: 10px var(--pad);
  display: none; align-items: center; gap: 12px; flex-wrap: wrap;
}
.cmpbar.on { display: flex; }

details.acc > summary {
  cursor: pointer; list-style: none; padding: 9px 0;
  font-size: 12px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3);
}
details.acc > summary::-webkit-details-marker { display: none; }
details.acc > summary:hover { color: var(--lime); }
details.acc > summary::before { content: "▸ "; color: var(--ink-4); }
details.acc[open] > summary::before { content: "▾ "; }

#hz-help, .hz-modal {
  position: fixed; inset: 0; z-index: 300; display: grid; place-items: center;
  background: rgba(10,10,10,.7); backdrop-filter: blur(3px);
}
/* The board picker: the same card, holding menu rows instead of a key table. */
.hz-pick-list {
  display: flex; flex-direction: column; gap: 1px; margin-top: 10px; min-width: 260px;
  max-height: 50vh; overflow-y: auto;
}
.hz-help-card {
  background: #232323; border: 1px solid var(--line-2); border-radius: var(--r-lg);
  padding: 20px 24px; box-shadow: var(--shadow); max-width: 420px;
}
.hz-help-t { border-collapse: collapse; margin-top: 10px; font-size: 13px; }
.hz-help-t td { padding: 4px 12px 4px 0; color: var(--ink-2); }
.hz-help-t td:first-child { white-space: nowrap; text-align: right; }

.kbd-help { display: flex; gap: 12px; flex-wrap: wrap; font-size: 11px; color: var(--ink-3); }
.kbd-help kbd {
  font-family: var(--mono); font-size: 10px; border: 1px solid var(--line-2);
  border-radius: 4px; padding: 1px 5px; color: var(--ink-3);
}

/* ==========================================================================
   Responsive. The Big Board is a dense 30-column table and is honestly a
   desktop surface — it degrades to a horizontally scrolled table rather than
   pretending otherwise. Everything else (Desk, player, team, competition,
   boards) has to work on a phone, because the person reading it is at a gym.
   ========================================================================== */
@media (max-width: 860px) {
  .hz-header-in { flex-wrap: wrap; gap: 8px 12px; padding: 8px var(--pad); }
  .hz-search { order: 3; flex: 1 1 100%; max-width: none; }
  .hz-search kbd { display: none; }
  .hz-nav { order: 2; margin-left: auto; }
  .hz-nav a { padding: 6px 8px; font-size: 11px; letter-spacing: .04em; }
  .hz-logo-txt span { display: none; }

  .page-head { padding: 18px 0 14px; }
  .phead { grid-template-columns: 1fr; }
  .phead .stack-s { align-items: flex-start !important; }

  .board-layout { grid-template-columns: minmax(0, 1fr); }
  .rail { position: static; max-height: none; }

  /* Sticky columns cost width that a 390 px screen does not have, and a frozen
     174 px name column left 200 px for 28 others. Scroll the whole table instead. */
  table.t.freeze thead th.f1, table.t.freeze tbody td.f1,
  table.t.freeze thead th.f2, table.t.freeze tbody td.f2,
  table.t.freeze thead th.f3, table.t.freeze tbody td.f3 {
    position: static; box-shadow: none; background: transparent;
  }
  table.t thead th { position: static; }

  .brk-row { grid-template-columns: 92px 1fr 32px; }
  .tile b { font-size: 20px; }
  .footer { gap: 8px 16px; padding-bottom: 40px; }
  .cmpbar { padding: 8px 12px; }
}

@media (max-width: 520px) {
  .g6, .g4 { grid-template-columns: 1fr 1fr; }
  h1 { font-size: 26px; }
  .pfacts { gap: 8px 14px; }
  .hz-nav a { padding: 5px 7px; font-size: 10.5px; }
  .score { min-width: 78px; padding: 8px 12px; }
  .score b { font-size: 27px; }
}

/* ==========================================================================
   The scout's own layer
   --------------------------------------------------------------------------
   Availability, eligibility, freshness, film, notes, the pipeline board and
   roster needs. Colour discipline: lime is still the only accent, so these
   states borrow the same ramp the percentile bars use rather than inventing
   a second palette. Two rules worth keeping:

     * "Not checked" must never look like "fine". An unchecked eligibility or
       an unknown signing status renders dim and outlined, because a scout who
       reads a blank as a clearance will find out in August.
     * Anything not yet confirmed carries a visible mark — the `?` on a
       computed eligibility read is the whole difference between a heuristic
       and a compliance answer.
   ========================================================================== */

/* ---------- availability ---------- */
.sig, .elig, .rec, .vstate, .nkind {
  display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
  padding: 2px 9px; border-radius: 999px; font-size: 10.5px; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase;
  border: 1px solid var(--line-2); background: var(--surface); color: var(--ink-3);
}
.sig b, .elig b { font-weight: 800; text-transform: none; letter-spacing: 0; }
.sig-unknown  { border-style: dashed; color: var(--ink-4); }
.sig-open     { border-color: rgba(212,235,0,.55); color: var(--lime);
                background: rgba(212,235,0,.12); }
.sig-in_talks { border-color: rgba(255,200,87,.5); color: var(--warn);
                background: rgba(255,200,87,.12); }
.sig-verbal   { border-color: rgba(255,122,107,.5); color: var(--bad);
                background: rgba(255,122,107,.12); }
.sig-signed   { border-color: var(--bad); color: #2a0f0b; background: var(--bad); }

/* ---------- eligibility ---------- */
.elig sup { font-size: 8.5px; margin-left: 1px; opacity: .8; }
.elig-unset      { border-style: dashed; color: var(--ink-4); }
.elig-clear      { border-color: rgba(0,146,69,.55); color: #7ee2a4;
                   background: rgba(0,146,69,.16); }
.elig-review     { border-color: rgba(255,200,87,.5); color: var(--warn);
                   background: rgba(255,200,87,.12); }
.elig-at_risk    { border-color: rgba(255,122,107,.5); color: var(--bad);
                   background: rgba(255,122,107,.14); }
.elig-ineligible { border-color: var(--bad); color: #2a0f0b; background: var(--bad); }

/* ---------- recency ---------- */
.rec i { width: 6px; height: 6px; border-radius: 50%; background: currentColor;
         display: inline-block; }
.rec-live   { border-color: rgba(212,235,0,.5);  color: var(--lime); }
.rec-recent { border-color: rgba(0,146,69,.5);   color: #7ee2a4; }
.rec-stale  { border-color: rgba(255,200,87,.42); color: var(--warn); }
.rec-old    { border-color: rgba(255,122,107,.4); color: var(--bad); }
.rec-none   { border-style: dashed; color: var(--ink-4); }
.rec-depth i { display: none; }
.rec-d-deep { color: var(--ink-2); }
.rec-d-fair { color: var(--ink-3); }
.rec-d-thin { border-color: rgba(255,200,87,.42); color: var(--warn); }
.rec-d-none { border-style: dashed; color: var(--ink-4); }

/* A three-up facts block: last game, sample, record freshness. */
.rgrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.rgrid .label { display: block; font-size: 9px; letter-spacing: .14em; margin-bottom: 3px; }
.rgrid b { display: block; font-size: 13px; font-weight: 700; }
.rgrid .tiny { display: block; }
@media (max-width: 520px) { .rgrid { grid-template-columns: 1fr; } }

/* ---------- film ---------- */
.btn-video.on      { border-color: var(--lime); background: rgba(212,235,0,.16);
                     color: var(--lime); }
.btn-video.pending { border-style: dashed; color: var(--ink-3); cursor: default; }
.btn-video.pending:hover { border-color: var(--line-2); color: var(--ink-3); }
.vrow { padding: 7px 0; border-bottom: 1px solid var(--line); }
.vrow:last-child { border-bottom: 0; }
/* The queue's own state picker borrows the pipeline select's shape — same idiom, same
   progression from neutral to lime. */
select.vsel { width: auto; min-width: 112px; }
select.vsel-requested   { border-color: var(--line-2);          color: var(--ink-2); }
select.vsel-in_progress { border-color: rgba(255,200,87,.5);    color: var(--warn);
                          background: rgba(255,200,87,.12); }
select.vsel-ready       { border-color: rgba(212,235,0,.6);     color: var(--lime);
                          background: rgba(212,235,0,.14); }
select.vsel-declined    { border-color: var(--line);            color: var(--ink-4); }
.vstate-requested   { color: var(--ink-3); }
.vstate-in_progress { border-color: rgba(255,200,87,.42); color: var(--warn); }
.vstate-ready       { border-color: rgba(212,235,0,.55); color: var(--lime);
                      background: rgba(212,235,0,.12); }
.vstate-declined    { border-style: dashed; color: var(--ink-4); }

/* ---------- action menu ----------
   One button that opens a list. Five equal-weight buttons beside the score competed
   with it for the eye and left nowhere for a sixth action to go. */
.menu { position: relative; }
.menu-pop {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 70;
  min-width: 232px; padding: 5px; border-radius: var(--r);
  border: 1px solid var(--line-2); background: #242424; box-shadow: var(--shadow);
  display: flex; flex-direction: column; gap: 1px; text-align: left;
}
.menu-pop[hidden] { display: none; }
.menu-item {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 8px 10px; border-radius: var(--r-sm); border: 0; background: transparent;
  color: var(--ink-2); font: inherit; font-size: 13px; text-align: left;
  cursor: pointer; white-space: nowrap;
}
.menu-item:hover, .menu-item:focus-visible {
  background: var(--surface-2); color: var(--ink); outline: none;
}
.menu-item .mi { width: 15px; text-align: center; color: var(--ink-4); flex: 0 0 auto; }
.menu-item:hover .mi { color: var(--lime); }
.menu-item.is-off { color: var(--ink-4); cursor: default; }
.menu-item.is-off:hover { background: transparent; color: var(--ink-4); }
.menu-item.on .mi { color: var(--lime); }

/* ---------- the help dot ----------
   A section's explanation, folded away until asked for. The dot has to be small enough
   to ignore and big enough to hit: 15px with a 4px invisible margin of error. */
.sechead { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
           justify-content: space-between; width: 100%; }
.sechead .label { flex: 0 0 auto; }
.sechead-note { flex: 1 1 auto; text-align: right; }

.help {
  position: relative; flex: 0 0 auto; display: inline-flex;
  align-items: center; justify-content: center;
  width: 15px; height: 15px; border-radius: 50%; cursor: help;
  border: 1px solid var(--line-2); background: var(--surface);
  color: var(--ink-4); font-size: 9.5px; font-weight: 800; line-height: 1;
  font-family: var(--sans); user-select: none; transition: .13s;
  align-self: center;
}
.help:hover, .help:focus-visible {
  border-color: rgba(212,235,0,.6); color: var(--lime);
  background: rgba(212,235,0,.12); outline: none;
}
.help-pop {
  display: none; position: absolute; top: calc(100% + 7px); right: -4px; z-index: 60;
  width: 330px; max-width: min(330px, 74vw); padding: 11px 13px;
  border-radius: var(--r); border: 1px solid var(--line-2);
  background: #242424; box-shadow: var(--shadow);
  font-size: 12px; line-height: 1.55; font-weight: 400; letter-spacing: 0;
  text-transform: none; color: var(--ink-2); text-align: left; cursor: auto;
  white-space: normal;
}
.help-wide .help-pop { width: 420px; max-width: min(420px, 82vw); }
/* Flipped by app.js when right-anchoring would run off the left edge of the page. */
.help-left .help-pop { right: auto; left: -4px; }
.help:hover .help-pop, .help:focus .help-pop, .help:focus-within .help-pop { display: block; }
.help-pop b { color: var(--ink); }
.help-pop .help-title {
  display: block; margin-bottom: 5px; font-size: 10px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; color: rgba(212,235,0,.82);
}
.help-pop p { margin: 0 0 .6em; }
.help-pop p:last-child { margin-bottom: 0; }
.help-pop a { color: var(--lime); text-decoration: underline; }
.card-flush > .tw:last-child, .card-flush > .tw-flush { border-bottom-left-radius: var(--r-lg);
  border-bottom-right-radius: var(--r-lg); overflow: hidden; }
@media (max-width: 620px) {
  .help-pop, .help-wide .help-pop { right: auto; left: -8px; width: min(320px, 86vw); }
}

/* ---------- name-match tier ----------
   The label that says WHY a row is in the list. "exact" has to read as the answer and
   "similar" has to read as a guess, or the split between the two blocks means nothing. */
.mt { display: inline-block; padding: 1px 7px; border-radius: 999px; font-size: 9.5px;
      font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
      border: 1px solid var(--line-2); color: var(--ink-3); white-space: nowrap; }
.mt-exact       { border-color: var(--lime); background: rgba(212,235,0,.16);
                  color: var(--lime); }
.mt-all-terms   { border-color: rgba(0,146,69,.55); background: rgba(0,146,69,.16);
                  color: #7ee2a4; }
.mt-starts-with { border-color: var(--line-2); color: var(--ink-2); }
.mt-close       { border-color: rgba(255,200,87,.55); background: rgba(255,200,87,.14);
                  color: var(--warn); }
.mt-similar     { border-style: dashed; color: var(--ink-4); }

/* ---------- internal notes ---------- */
.notebox textarea { resize: vertical; min-height: 62px; line-height: 1.45; }
.notes { display: flex; flex-direction: column; gap: 9px; margin-top: 14px;
         max-height: 420px; overflow-y: auto; }
.noteitem {
  padding: 9px 11px; border-radius: var(--r); background: var(--surface);
  border: 1px solid var(--line); border-left: 2px solid rgba(212,235,0,.45);
}
.noteitem p { margin: 6px 0 0; font-size: 13px; line-height: 1.5; color: var(--ink-2);
              white-space: pre-wrap; }
.nkind-note { color: var(--ink-3); }
.nkind-call { border-color: rgba(0,146,69,.5); color: #7ee2a4; }
.nkind-game { border-color: rgba(212,235,0,.5); color: var(--lime); }

/* ---------- pipeline board ----------
   The same board_player rows as the list, laid out by stage. A staff that
   cannot see six players stuck at "contacted" for a month will not chase
   them, which is the entire argument for this view existing. */
/* Six stages, always in one row, scrolling sideways when they do not fit.
   Wrapping to three columns at 1280px was fine while this was a read-only view of a
   pipeline. It is not fine now that a player is moved by dragging him: the column you
   are dragging to ends up on a different ROW, above or below the one you started on,
   and a drag across a wrap is a drag nobody completes. A stage board also stops
   reading as a sequence the moment it folds.
   The floor is 200px, which is what a card with a grade row and a note field needs. */
.kanban { display: grid; grid-template-columns: repeat(6, minmax(200px, 1fr));
          gap: 10px; align-items: start; overflow-x: auto; padding-bottom: 6px; }
/* On a phone there is no sideways drag worth having, so stack them and use the
   select on each card. */
@media (max-width: 640px) {
  .kanban { grid-template-columns: minmax(0, 1fr); overflow-x: visible; }
}
.kcol { background: var(--surface); border: 1px solid var(--line);
        border-radius: var(--r); padding: 10px; min-height: 90px; }
.kcol > .khead { display: flex; align-items: center; justify-content: space-between;
                 gap: 6px; margin-bottom: 9px; }
.kcol .khead b { font-size: 10.5px; font-weight: 700; letter-spacing: .13em;
                 text-transform: uppercase; color: var(--ink-2); }
.kcol .khead .n { font-family: var(--mono); font-size: 11px; color: var(--ink-4); }
.kcol-committed { border-color: rgba(212,235,0,.4); background: rgba(212,235,0,.05); }
.kcol-passed    { opacity: .62; }
.kcard { display: block; padding: 8px 9px; border-radius: var(--r-sm);
         background: var(--surface-2); border: 1px solid var(--line);
         margin-bottom: 7px; }
.kcard:last-child { margin-bottom: 0; }
.kcard:hover { border-color: rgba(212,235,0,.45); }
.kcard b { font-size: 12.5px; display: block; }
.kcard .kmeta { font-size: 10.5px; color: var(--ink-4); margin-top: 2px; }
.kcard .krow { display: flex; align-items: center; gap: 5px; margin-top: 6px;
               flex-wrap: wrap; }
.kcard .due { font-family: var(--mono); font-size: 10px; color: var(--ink-3); }
.kcard .due.over { color: var(--bad); font-weight: 700; }
.kcard .due.soon { color: var(--warn); }

/* ---------- dragging a player to the next stage ----------
   The card has to look picked up and the column has to look like a target, or a drag
   is a guess. `grab`/`grabbing` on the cursor is the only affordance saying the card
   moves at all -- there is no handle, the whole card is one. */
.kcard { cursor: grab; }
.kcard:active { cursor: grabbing; }
/* The inputs on the card are not drag handles: a click into the note field or the
   grade buttons must not start one. */
.kcard input, .kcard select, .kcard button, .kcard a { cursor: auto; }
.kcard input { cursor: text; }
.kcard select, .kcard button, .kcard a { cursor: pointer; }
.kcard.dragging { opacity: .45; border-color: var(--lime); }
.kcol.over { border-color: var(--lime); background: rgba(212,235,0,.07); }
.kcol.over > .khead b { color: var(--lime); }
/* A column with nothing in it is still a target, and a 90px one is a hard one to hit. */
.kcol { transition: background .12s, border-color .12s; }
.kanban .kcol { min-height: 140px; }

/* ---------- roster needs ---------- */
.needs { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 330px), 1fr));
         gap: 12px; align-items: start; }
.need { padding: 13px 15px; }
.need .needhead { display: flex; align-items: flex-start; justify-content: space-between;
                  gap: 10px; }
.need h3 { font-size: 14px; }
.slots { display: inline-flex; gap: 3px; align-items: center; }
.slots i { width: 16px; height: 6px; border-radius: 3px; background: var(--surface-3);
           display: block; }
.slots i.filled { background: linear-gradient(90deg, var(--green-mid), var(--lime)); }
.needmatch { display: flex; align-items: center; justify-content: space-between;
             gap: 8px; padding: 5px 0; border-bottom: 1px solid var(--line); }
.needmatch:last-child { border-bottom: 0; }
.needmatch .nm-name { font-size: 12.5px; font-weight: 700; }
.needmatch .nm-meta { font-size: 10.5px; color: var(--ink-4); }

/* A near miss is deliberately quieter than a match: it is a prompt to reconsider the
   need, not a candidate the need actually asked for. */
.needmatch-near { opacity: .78; }
.needmatch-near:hover { opacity: 1; }
.needmatch-near .nm-meta b { color: var(--ink-2); }

/* An urgent need keeps its left edge marked, so the order of the grid is legible
   without reading every card's chips. */
.need-p1 { border-left: 2px solid var(--bad); }
.need-p3 { opacity: .9; }

/* The gap strip: the whole roster in one line, before any individual hole. */
.gapstat { display: inline-flex; align-items: baseline; gap: 6px; }
.gapstat b { font-family: var(--mono); font-size: 19px; line-height: 1; }
.gapstat span { font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-4); }
.needform { display: grid; gap: 10px; }
/* The field name needs room to read, the comparator needs room for "at least", and
   neither should stretch across a 900 px card because the value box is 90 px. */
.needform .cond-row { display: grid; gap: 6px; margin-bottom: 6px;
                      grid-template-columns: minmax(0, 260px) 104px 92px 32px;
                      justify-content: start; }
@media (max-width: 620px) {
  .needform .cond-row { grid-template-columns: minmax(0, 1fr) 88px 72px 30px; }
}
.tagpick { display: flex; flex-wrap: wrap; gap: 4px; max-height: 104px; overflow-y: auto;
           padding: 2px; }

/* ---------- the note drawer ----------
   A note history is a page of its own on a row that is fourteen columns wide, so it
   gets an overlay rather than an expanding cell. */
.drawer { position: fixed; inset: 0; z-index: 80; background: rgba(0,0,0,.62);
          display: flex; justify-content: flex-end; }
.drawer[hidden] { display: none; }
.drawer-in {
  width: min(480px, 100%); height: 100%; overflow-y: auto; padding: 20px;
  background: #202020; border-left: 1px solid var(--line-2);
  box-shadow: var(--shadow);
}
@media (max-width: 560px) { .drawer-in { width: 100%; } }

/* ---------- the printed report ---------- */
.report { max-width: 900px; margin: 0 auto; }
.rep-head { display: grid; grid-template-columns: 1fr auto; gap: 18px;
            align-items: start; border-bottom: 2px solid var(--lime);
            padding-bottom: 14px; margin-bottom: 18px; }
.rep-sec { margin-bottom: 18px; break-inside: avoid; }
.rep-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 10px; }
.rep-foot { border-top: 1px solid var(--line); margin-top: 20px; padding-top: 10px;
            font-size: 10.5px; color: var(--ink-4); display: flex;
            justify-content: space-between; gap: 12px; flex-wrap: wrap; }

@media print {
  /* The report is the one page built to leave the building, so it prints on white
     with its ink intact — the dark ground is a screen idiom and a scout printing a
     profile for a head coach should not empty a toner cartridge on it.

     The tokens are redefined rather than the rules overridden one by one. Every piece
     of text in this file gets its colour from --ink-*, and the first version of this
     block listed selectors instead: the score breakdown then printed its bars with no
     component names at all, because `.brk-row .nm` was white-on-white and nobody had
     remembered to add it to the list. Redefining the token fixes every such case at
     once, including the ones written after this. */
  :root {
    --ink:   #111;
    --ink-2: #222;
    --ink-3: #444;
    --ink-4: #666;
    --line:   #d4d4d4;
    --line-2: #9a9a9a;
    --surface:   transparent;
    --surface-2: transparent;
    --surface-3: #e8e8e8;
  }
  .no-print, .notebox, [data-signing], [data-elig], [data-video], .hz-help { display: none !important; }
  .report { max-width: none; }
  .rep-head { border-bottom-color: #111; }

  /* State chips keep their shape but lose their fill. The two that mean "stop" keep a
     solid one, because a printed page has no tooltip and no hover: if he is signed or
     ineligible, that has to survive a photocopier. */
  .sig, .elig, .rec, .vstate, .nkind, .chip, .tier, .heat {
    border-color: #999 !important; background: #fff !important; color: #111 !important;
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }
  .sig-signed, .elig-ineligible, .elig-at_risk {
    background: #111 !important; border-color: #111 !important; color: #fff !important;
  }
  .sig-in_talks, .sig-verbal, .elig-review, .elig-at_risk, .rec-old, .rec-d-thin {
    border-color: #111 !important; border-width: 1.5px !important;
  }
  .sig-unknown, .elig-unset, .rec-none { border-style: dashed !important; }

  .card, .kcol, .kcard, .noteitem { border-color: #ccc !important;
    background: #fff !important; box-shadow: none !important; }
  .label { color: #555 !important; }

  /* Lime is the single accent and it is invisible on paper. Text goes to ink; the
     micro-bars keep their length, which is the information, in grey. */
  .lime, .score b, .v, .g, .ranks b { color: #111 !important; }
  /* A fact's severity is carried by colour on screen; on paper it becomes weight, or
     a signed player reads the same as an open one. */
  .pfact b.f-good, .pfact b.f-dim { color: #333 !important; }
  .pfact b.f-warn, .pfact b.f-bad { color: #111 !important; font-weight: 800 !important;
                                    text-decoration: underline; }
  /* The +/− markers carry the sign of each finding and are the one thing on this page
     that must not fade: a pale-yellow plus on white is an unmarked bullet. */
  .finding .mk, .nkind, .due { color: #111 !important; }
  .score { background: #fff !important; border-color: #999 !important; }
  .bar { background: #e8e8e8 !important; }
  .bar > i, .ladder-bar > i, .slots i.filled {
    background: #555 !important;
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }
  .chart .curve-hi, .spark .curve-hi { stroke: #111 !important; }
  .chart .curve, .spark .curve { stroke: #999 !important; }
  .chart .dot, .spark .dot { fill: #111 !important; }
  .chart .dot-2 { fill: #888 !important; }
  .chart text, .chart .lbl { fill: #444 !important; }
  .chart .radar-shape { fill: rgba(0,0,0,.10) !important; stroke: #111 !important; }
  .chart .grid-l, .chart .ax, .chart .radar-grid { stroke: #ccc !important; }
  a { color: #111 !important; }
  .rep-sec { page-break-inside: avoid; }
}

@media print {
  .hz-header, .rail, .cmpbar, .footer, .btn { display: none !important; }
  body { background: #fff; color: #000; }
  .hz-bg { display: none; }
  .card { border-color: #ccc; background: #fff; }
  table.t tbody td, table.t thead th { color: #000; background: #fff; }
}

/* ---------- third-party scouting reports (db/010) ----------------------------
   A scout's opinion and a mart measurement must never be the same colour. Everything
   here is deliberately off-palette from --lime/--bad, which are reserved for findings
   the rule engine derived and cited. If you can't tell at a glance whether a sentence
   was measured or written, the card has failed. */
.pill.scout {
  display: inline-block; font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 999px; background: rgba(122,162,227,.14);
  color: #9dbcf0; border: 1px solid rgba(122,162,227,.3); vertical-align: middle;
}
.pill.warn {
  display: inline-block; font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 999px; background: rgba(255,200,87,.12);
  color: var(--warn); border: 1px solid rgba(255,200,87,.28);
}
.finding.scout .mk.sc { color: #9dbcf0; font-weight: 700; }
.finding.scout > span:last-child {
  border-left: 2px solid rgba(122,162,227,.32); padding-left: 8px;
}
.finding .ev.dis { color: var(--warn); }
.summary .prov { margin-top: 8px; color: var(--ink-4); font-style: italic; font-size: 11.5px; }

.reports { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; }
details.acc.rep > summary { display: flex; gap: 9px; align-items: baseline; flex-wrap: wrap; }
.rep-src  { font-weight: 600; }
.rep-ev   { color: var(--ink-3); font-size: 12.5px; }
.rep-date { color: var(--ink-4); font-size: 11.5px; margin-left: auto; font-family: var(--mono); }
.rep-body { padding: 8px 0 12px 14px; max-width: 74ch; }
.rep-body p { margin: 0 0 8px; font-size: 13.5px; line-height: 1.58; color: var(--ink-2); }


/* ======================================================================================
   Sign-in
   ====================================================================================== */

.shell-narrow { max-width: 480px; }

.signin { padding: 48px 0 60px; }
.signin-brand { display: flex; align-items: center; gap: 11px; margin-bottom: 26px; }
.signin-brand img { width: 34px; height: 34px; }
.signin-brand b { display: block; font-family: var(--display); font-size: 17px;
  letter-spacing: .02em; }
.signin-brand span { display: block; font-size: 10px; text-transform: uppercase;
  letter-spacing: .14em; color: var(--ink-4); }

/* Clerk renders its own card in here. The mount only has to reserve the space and not
   fight the widget's own styling. */
.signin-mount { min-height: 380px; display: flex; justify-content: center; }
.signin-foot { margin-top: 20px; color: var(--ink-4); text-align: center; }

/* Who is signed in, in the header. Pushed to its own end of the nav so it reads as
   account state rather than as one more place to go. */
.hz-user { display: inline-flex; align-items: center; gap: 8px; margin-left: 10px;
  padding-left: 12px; border-left: 1px solid var(--line); }
.hz-user > span { font-size: 11px; color: var(--ink-4); max-width: 150px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hz-user a { font-size: 11px; }
