/*
 * players.css — Players page responsive polish
 * Scoped to html[data-route="/players"] — zero bleed to other pages.
 *
 * Layout: the .app grid fills the full viewport like every other route — the
 * sidebar pins to the far-left edge and .content fills the rest. (A prior
 * max-width:1440px cap that centered the whole shell was removed 2026-07-03;
 * see the LAYOUT note lower in this file.)
 *
 * Filter bar: condensed to a single row — position dropdown, label-less
 * conf/team/sort selects, and a compact icon-led search.
 *
 * Polish bundle: motion, interaction depth, team-link style, skeleton fade.
 */

/* ─── CARD ENTRANCE ─────────────────────────────────────────────────────── */
@keyframes pl-card-fadein {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.95);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.pl-card.is-pl-visible {
  animation: pl-card-fadein 0.28s cubic-bezier(0.16, 1, 0.3, 1) both;
}

@media (prefers-reduced-motion: reduce) {
  @keyframes pl-card-fadein {
    from { opacity: 0; }
    to   { opacity: 1; }
  }
}

/* ─── MODAL ENTRANCE ────────────────────────────────────────────────────── */
@keyframes pl-modal-fadein {
  from {
    opacity: 0;
    transform: scale(0.97);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

.pl-modal[open] {
  animation: pl-modal-fadein 0.22s cubic-bezier(0.16, 1, 0.3, 1) both;
}

@media (prefers-reduced-motion: reduce) {
  @keyframes pl-modal-fadein {
    from { opacity: 0; }
    to   { opacity: 1; }
  }
}

/* ─── ACTION BUTTONS ────────────────────────────────────────────────────── */
.pl-act-btn:focus-visible {
  outline: 2px solid var(--sns-accent, var(--red-primary, #FF1A1A));
  outline-offset: 2px;
}

.pl-act-btn:active {
  transform: scale(0.96);
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3);
}

/* Icon inside action buttons (injected by player-actions.js renderButtons()) */
.pl-act-ic {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.pl-act-ic svg {
  width: 16px;
  height: 16px;
  fill: currentColor;
}

/* ─── MODAL CLOSE BUTTON ────────────────────────────────────────────────── */
.pl-modal-close {
  min-width: 44px;
  min-height: 44px;
}

.pl-modal-close:hover {
  background: rgba(255, 0, 0, 0.35); /* Q-EXP-5: match exp-card.css ✕ hover */
  border-radius: 8px;
}

.pl-modal-close:focus-visible {
  outline: 2px solid var(--sns-accent, var(--red-primary, #FF1A1A));
  outline-offset: 2px;
  border-radius: 6px;
}

/* ─── POSITION CHIPS ────────────────────────────────────────────────────── */
.pl-chip:active {
  transform: scale(0.97);
}

.pl-chip.is-active {
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.35);
}

/* ─── TEAM LINK ─────────────────────────────────────────────────────────── */
.pl-card-school.team-link,
.pl-modal-school.team-link {
  text-decoration: underline;
  text-decoration-color: var(--red-primary, #FF1A1A);
  text-underline-offset: 3px;
  /* Long school names ("Middle Tennessee") hard-cut on narrow cards (ui-audit
     TEXT_CLIP); truncate gracefully with an ellipsis instead of clipping mid-letter. */
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}

.pl-card-school.team-link:hover,
.pl-modal-school.team-link:hover {
  color: var(--red-bright, #FF4d4d);
}

/* ─── SKELETON FADE ─────────────────────────────────────────────────────── */
/* Applied by JS as a transition class before clearing the grid */
.pl-loading-banner--fading {
  transition: opacity 0.3s ease;
  opacity: 0 !important;
}

/* ─── LAYOUT — full-bleed sidebar + full-width content ──────────────────────
   The .app grid (sidebar + content) used to be capped at max-width:1440px and
   centered. On any monitor WIDER than 1440px that pushed the whole shell —
   sidebar included — into the middle of the screen, so the SNS rail no longer
   sat flush to the far-left edge and the content stopped filling the page.
   Removed: /players now matches every other route — .app fills 100vw, the
   sidebar pins to the left edge, and .content fills the remaining 1fr and
   auto-formats to the viewport. — pward 2026-07-03 */

/* ─── FILTER BAR — condensed to a single row ────────────────────────────────
   Position filter collapsed from a 7-chip strip into one dropdown; the
   CONF / TEAM / SORT text labels removed (each select's own option text
   carries the context); search collapsed to an icon-led compact field that
   widens on focus. The toolbar now flows on one line on desktop and wraps
   gracefully on smaller screens instead of the old overflow-scroll strip.
   Page-scoped — beats the shared components.css rules via html[data-route]
   specificity; components.css itself is untouched. — pward 2026-07-03 */
html[data-route="/players"] {

  /* One wrapping row at every width (overrides the components.css mobile
     column-stack + overflow-scroll fallbacks). */
  .pl-bar {
    flex-flow: row wrap;
    align-items: center;
    gap: 8px;
  }

  /* Compact, icon-led search — slim by default, widens on focus. */
  .pl-search.pl-search--compact {
    flex: 0 1 190px;
    min-width: 46px;
    max-width: 100%;
    width: auto;
    transition: flex-basis .18s ease;
  }
  .pl-search.pl-search--compact:focus-within { flex-basis: 280px; }
  .pl-search--compact .pl-search-input {
    min-height: 40px;
    padding: 8px 12px 8px 34px;
    letter-spacing: .04em;
  }

  /* Position dropdown + the conf/team/sort selects — label-less, uniform height. */
  .pl-sort { gap: 0; flex: 0 0 auto; }
  .pl-sort-select { min-height: 40px; }
  /* font-weight:700 makes this the one select whose widest option ("ALL
     POSITIONS") renders wider than the others at the same character count.
     Gecko sizes a <select>'s content box to EXACTLY that widest option, so the
     default label landed with 0.02px of slack — measured, not guessed. That
     technically fits, but any font-metric variation (a different Firefox build,
     an Inter fallback) tips it over and `text-overflow: ellipsis` then clips the
     DEFAULT label to "ALL POSITION…", which reads as the very bug D-PL-1 fixed.
     min-width buys ~12px of headroom; flex-shrink is 1 on this control, so
     without an explicit floor the flex row could also squeeze it. Stays under
     the 240px max-width, and the row wraps on mobile so it costs no overflow. */
  .pl-pos-select { font-weight: 700; min-width: 182px; }
  /* Same class of fragility on the sort select: its default label ("PROJECTION")
     has slack, but its LONGEST option ("TOTAL POINTS") measured 0.02px of it —
     so picking that option would sit one rounding error from ellipsizing. Sized
     for the longest option, not the default, since the user controls which is
     shown. Checked with tools/../select-fit-check: gutterLongest 0.02px → 12px. */
  #pl-sort-select { min-width: 175px; }

  /* FILTERS disclosure trigger — matched to the 40px control height so the
     visible row reads as one control set (search / position / sort / filters). */
  .pl-filters-toggle {
    min-height: 40px;
    display: inline-flex;
    align-items: center;
    gap: 7px;
  }

} /* end html[data-route="/players"] scope */

/* Mobile tap-target compliance (Phase C8): the filter controls are the primary
   interactive surface on /players, so on phones they must clear the 44px
   thumb-zone floor. The shared route.css sets these to 44px @≤880, but it lives
   in @layer components and is out-ranked by this unlayered file — so the 44px
   floor is re-asserted here where it actually wins. Desktop keeps the denser
   40px toolbar. (The old .pl-chip--injury selector was dropped 2026-07-27 with
   the button itself; .pl-filters-toggle and .pl-filters-reset took its place as
   the toolbar's only non-select controls.) */
@media (max-width: 880px) {
  html[data-route="/players"] .pl-search--compact .pl-search-input,
  html[data-route="/players"] .pl-sort-select,
  html[data-route="/players"] .pl-filters-toggle,
  html[data-route="/players"] .pl-filters-reset {
    min-height: 44px;
  }
}

/* ─── SCHOOL-COLOR PLAYER TILES (2026-07-01 v2, Pat) ─────────────────────────
   Tile fades school color (top) → BLACK (bottom). Position badge in the TOP-LEFT
   corner; name centered beneath the avatar. Type bright-white + uniform; school-
   name underline WHITE. THIN white ring only behind the player image (no white
   panel). Missing photo → SNS shield. .is-school-colored set in JS (--team). */
html[data-route="/players"] {
  /* tile: school color at the very top → black at the bottom */
  .pl-card.is-school-colored {
    position: relative;
    background: linear-gradient(180deg,
      var(--team) 0%,
      color-mix(in srgb, var(--team) 42%, #000000) 46%,
      #000000 100%);
    border-color: rgba(255, 255, 255, 0.14);
  }
  /* uniform bright-white type (shadow keeps it legible under the top band) */
  .pl-card.is-school-colored .pl-card-name,
  .pl-card.is-school-colored .pl-card-school,
  .pl-card.is-school-colored .pl-card-stats .stat-val,
  .pl-card.is-school-colored .pl-card-stats .stat-lbl,
  .pl-card.is-school-colored .pl-card-pos {
    color: #F5F5F5 !important;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
  }
  /* school-name underline = WHITE */
  .pl-card.is-school-colored .pl-card-school.team-link {
    text-decoration-color: #FFFFFF;
    -webkit-text-decoration-color: #FFFFFF;
    text-underline-offset: 3px;
  }
  /* position badge → top-left corner; name centers beneath the avatar */
  .pl-card.is-school-colored .pl-card-pos {
    position: absolute;
    top: 8px;
    left: 8px;
    margin: 0;
    background: rgba(0, 0, 0, 0.38);
    z-index: 2;
  }
  .pl-card.is-school-colored .pl-card-head { justify-content: center; }
  /* THIN white ring, only behind the player image */
  .pl-card.is-school-colored .pl-card-img-wrap::before {
    inset: -2px;
    background: #FFFFFF;
  }
  /* Lock the avatar to a perfect circle — the fixed height was losing to an
     intrinsic-aspect fallback on mobile (image rendered 60x44.7 → oval ring). */
  .pl-card.is-school-colored .pl-card-img,
  .pl-card.is-school-colored .pl-card-img-wrap {
    width: 60px !important;
    height: 60px !important;
    min-width: 60px;
    aspect-ratio: 1 / 1;
  }
  .pl-card.is-school-colored .pl-card-img {
    object-fit: cover;
    background: #FFFFFF;
  }
  /* contained (not cropped) for SNS-logo / school-logo fallbacks, on white */
  .pl-card.is-school-colored .pl-card-img--logo {
    object-fit: contain;
    padding: 6px;
    background: #FFFFFF;
  }
  .pl-card.is-school-colored:hover {
    border-color: #FFFFFF;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
  }
}

/* FORMAT BUCKET TABS deleted 2026-07-27 (D-PL-3). The .pl-bucket-tabs /
   .pl-bucket-tab rules that lived here styled the CAMPUS/DEVY/FRESHMEN/
   ROOKIES/CANTON row above the toolbar. That markup is gone from
   players/index.html and no other file references either class (grepped
   apps/web + tools; the only remaining hit is tools/seo/golden/html/
   players.html, a captured pre-change SEO baseline snapshot, not a live
   surface). ?bucket= itself survives as the FORMAT select in the filters
   panel. CANTON was NOT re-homed: it was a permanently `disabled`
   coming-soon chip and "canton" is not one of the API's BUCKETS
   (apps/api/src/routes/players.ts:88), so carrying it into a select would
   have advertised a scope the server cannot serve. */

/* ─── ADP BADGE — player-pool parity (A) ────────────────────────────────── */
.pl-card-adp {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: 999px;
  font-family: var(--f-mono, monospace);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--gray-light, #8A8A8A);
  border: 1px solid var(--gray-border, #2A2A2A);
  background: rgba(255, 255, 255, 0.04);
  vertical-align: middle;
  white-space: nowrap;
}
.pl-card.is-school-colored .pl-card-adp {
  color: #F5F5F5 !important;
  border-color: rgba(255, 255, 255, 0.3);
  background: rgba(0, 0, 0, 0.28);
  text-shadow: none;
}

/* ─── TIER BADGE — 2026 projection engine (positional tier) ─────────────── */
.pl-card-tier {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 999px;
  font-family: var(--f-mono, monospace);
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .04em;
  vertical-align: middle;
  white-space: nowrap;
  border: 1px solid transparent;
}
.pl-card-tier.is-elite { color: #1A1205; background: #F2C14E; border-color: #F2C14E; }  /* gold — elite */
.pl-card-tier.is-good  { color: #06231A; background: #4ADE80; border-color: #4ADE80; }  /* green — strong */
.pl-card-tier.is-mid   { color: var(--white-bright, #F5F5F5); background: rgba(255, 255, 255, 0.08); border-color: var(--gray-border, #2A2A2A); }
.pl-card-tier.is-low   { color: var(--gray-light, #8A8A8A); background: rgba(255, 255, 255, 0.03); border-color: var(--gray-border, #2A2A2A); }
/* keep the neutral/low bands legible on school-colour tiles */
.pl-card.is-school-colored .pl-card-tier.is-mid,
.pl-card.is-school-colored .pl-card-tier.is-low {
  color: #F5F5F5 !important;
  background: rgba(0, 0, 0, 0.30);
  border-color: rgba(255, 255, 255, 0.30);
}

/* ════════════════════════════════════════════════════════════════════════════
   TOOLBAR SELECTS — the Firefox caret overdraw fix (D-PL-1, 2026-07-27)
   ════════════════════════════════════════════════════════════════════════════
   THE BUG (Gecko only; Chromium and WebKit render this correctly, so a
   Chromium-only sweep finds nothing): route.css:96-107 styles .pl-sort-select
   with `letter-spacing:.12em`, no `appearance:none`, and no author
   right-padding. Firefox computes a <select>'s intrinsic content width from the
   widest <option> measured with letter-spacing IGNORED, then reserves a fixed
   ~18px gutter for the native caret — but PAINTS the selected option's text
   with letter-spacing applied, i.e. ~1.92px per character wider than the box it
   just sized. At 13 characters ("ALL POSITIONS") the text runs ~25px past the
   width Gecko reserved, so the native caret paints over the final glyphs and,
   with the neighbouring control only 8px away, reads as two filters colliding.

   THE FIX is the pattern this repo already uses twice — news/route.css:55-74
   (.nw-team-select) and scoreboard/route.css:104-113 (.filter-pill-select
   select): kill the native control with appearance:none, reserve an EXPLICIT
   author right-padding gutter, and draw the caret ourselves as an inline-SVG
   background-image. Author padding is honoured identically in all three
   engines, so the gutter stops being a Gecko implementation detail.

   letter-spacing is dropped to `normal` (not merely reduced) and that is the
   larger half of the fix, for two reasons:
     1. chrome.js:186 injects
        `input,select,textarea,button,optgroup,option{font-family:inherit!important}`
        sitewide, so route.css's `font-family:var(--f-mono)` on these selects is
        DEAD — they have always rendered in Inter. .12em was tracking tuned for
        a monospace face and was never paying for itself here; in a proportional
        face it is pure width penalty (~2px/char) on the exact axis that breaks.
     2. With letter-spacing:normal there is nothing for Gecko's intrinsic
        measurement to ignore, so the content box it computes matches the text
        it paints EXACTLY. The reserved gutter is then provably the whole
        padding-right, in every engine, instead of padding-right minus an
        accumulating per-character error.

   WHY THIS FILE: route.css lives inside `@layer components`; players.css is
   unlayered, and unlayered normal declarations outrank every layered normal
   declaration regardless of specificity. Declaring the fix here is the only way
   it wins without !important.

   NOT SET HERE: font-family (dead, see above) and font-size — core.css:963-965
   pins `select{font-size:max(16px,1rem)!important}` as an iOS focus-zoom guard.
   Both constraints are designed around, not fought. */
html[data-route="/players"] .pl-sort-select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  letter-spacing: normal;
  /* 28px right gutter with the 10px caret drawn at `right 10px` — i.e. the caret
     occupies 10-20px from the inner edge and the text box stops 8px clear of it.
     These are the exact values news/route.css:64,72 (.nw-team-select) already
     ships, so the two implementations of this pattern now agree.

     Why 28 and not the 34 this first shipped with: 34px left 12px of dead space
     between the text edge and the caret, and that slack was load-bearing in the
     wrong place. The panel selects are `width:100%` of a grid cell (with a
     deliberate min-width:0 — see below — so a min-width floor is NOT available
     as a lever there), which means their content box is cell width minus this
     padding. Measured on the deployed canary against REAL conference data, the
     longest option "AMERICAN ATHLETIC" overflowed the content box by 0.75px and
     ellipsized to "AMERICAN ATHLETI…" in the width band where the panel grid
     fits exactly 4 columns. Local fixtures never caught it because no fixture
     conference name was that long — it only showed up against live data.
     Reclaiming 6px here fixes it with ~5px still spare, costs the caret nothing,
     and leaves the two visible-row selects better off than before. */
  padding: 7px 28px 7px 12px;
  background-color: var(--black-soft, #111);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'><path d='M1 1l4 4 4-4' stroke='%238A8A8A' stroke-width='1.6'/></svg>");
  background-repeat: no-repeat;
  background-position: right 10px center;
  /* A 139-option select (#pl-team-select, intrinsically sized by "Florida
     International") must not set the width of the whole row. In the panel the
     grid track does the capping (min-width:0 + width:100% below); this is the
     backstop for the two selects that stay in the visible row. */
  max-width: 100%;
  text-overflow: ellipsis;
}
html[data-route="/players"] .pl-bar .pl-sort-select { max-width: 15rem; }
html[data-route="/players"] .pl-sort-select:hover { border-color: var(--accent, #FF2D2D); }
html[data-route="/players"] .pl-sort-select:focus-visible {
  outline: 2px solid var(--accent, #FF2D2D);
  outline-offset: 1px;
}
/* Native option lists render light-on-light on some platforms once the control
   itself is author-painted (same guard as news/route.css:78). */
html[data-route="/players"] .pl-sort-select option { color: #F5F5F5; background: #111; }

/* ─── FILTERS DISCLOSURE (D-PL-3) ─────────────────────────────────────────── */
html[data-route="/players"] .pl-filters-toggle {
  padding: 7px 12px;
  border-radius: 5px;
  border: 1px solid var(--gray-border, #2A2A2A);
  background: var(--black-soft, #111);
  color: var(--text-muted, var(--gray-light, #C2C2C2));
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .08em;
  cursor: pointer;
  transition: color .18s ease, border-color .18s ease, background .18s ease;
}
html[data-route="/players"] .pl-filters-toggle:hover {
  color: var(--white-bright, #F5F5F5);
  border-color: var(--accent, #FF2D2D);
}
html[data-route="/players"] .pl-filters-toggle:focus-visible {
  outline: 2px solid var(--accent, #FF2D2D);
  outline-offset: 1px;
}
/* Open state + "a filter is armed" state are deliberately DIFFERENT signals:
   open says where the controls are, the count says the grid is being narrowed.
   A collapsed panel with an active filter must still be self-explanatory. */
html[data-route="/players"] .pl-filters-toggle[aria-expanded="true"] {
  color: var(--white-bright, #F5F5F5);
  border-color: var(--red-primary, #FF1A1A);
}
html[data-route="/players"] .pl-filters-toggle svg { flex: 0 0 auto; }
html[data-route="/players"] .pl-filters-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--red-primary, #FF1A1A);
  color: #fff;
  font-size: 11px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0;
}

html[data-route="/players"] .pl-filters-panel {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 10px 12px;
  align-items: end;
  margin-top: 8px;
  padding: 12px;
  border: 1px solid var(--gray-border, #2A2A2A);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.02);
}
/* min-width:0 on the track item + width:100% on the control is what actually
   defeats the 139-option intrinsic width: the grid cell, not the option list,
   decides how wide the Team select gets. */
html[data-route="/players"] .pl-filter-field {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 0;
}
html[data-route="/players"] .pl-filter-field .pl-sort-select {
  width: 100%;
  min-width: 0;
  max-width: 100%;
}
html[data-route="/players"] .pl-filter-lbl {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-muted, var(--gray-light, #8A8A8A));
}
html[data-route="/players"] .pl-filters-foot {
  display: flex;
  align-items: flex-end;
  min-width: 0;
}
html[data-route="/players"] .pl-filters-reset {
  min-height: 40px;
  padding: 7px 12px;
  border-radius: 5px;
  border: 1px solid var(--gray-border, #2A2A2A);
  background: transparent;
  color: var(--text-muted, var(--gray-light, #C2C2C2));
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .08em;
  cursor: pointer;
}
html[data-route="/players"] .pl-filters-reset:hover {
  color: var(--white-bright, #F5F5F5);
  border-color: var(--accent, #FF2D2D);
}
html[data-route="/players"] .pl-filters-reset:focus-visible {
  outline: 2px solid var(--accent, #FF2D2D);
  outline-offset: 1px;
}
/* The 44px mobile floor is asserted for this control HERE and not in the
   shared @media block near the top of the file: that block uses the identical
   selector `html[data-route="/players"] .pl-filters-reset` (a media query adds
   no specificity), and it appears EARLIER in the source, so the base
   `min-height:40px` above would out-order it and win. Measured 40px in both
   Chromium and Firefox at 390px before this rule was added. */
@media (max-width: 880px) {
  html[data-route="/players"] .pl-filters-reset { min-height: 44px; }
}
/* The injured filter is CLIENT-side (the API exposes no injury param — grepped
   apps/api/src/routes/players.ts, zero matches for "injur"), so it can only
   narrow pages already fetched. Say so in the panel rather than letting the
   count badge imply a full-pool scope. */
html[data-route="/players"] .pl-filter-note {
  grid-column: 1 / -1;
  margin: 0;
  font-size: 11px;
  line-height: 1.45;
  color: var(--text-muted, var(--gray-light, #8A8A8A));
}

/* ─── SEASON NOTICE — quiet, not alarm-red (D-PL-4) ───────────────────────── */
/* An upcoming season having no stats yet is normal, expected, non-error
   information. The prior banner painted it in a red-tinted alert box
   (rgba(255,45,45,.08) + a red border) while the empty state said the same
   thing a second time and the season pill's green "live" dot said the
   opposite — three statements, one fact, one of them wrong. This is now a
   single hairline inline note; the contextual empty state is KEPT, because
   that one appears exactly when the user is staring at nothing and needs the
   explanation. */
html[data-route="/players"] .pl-season-note {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0 0 12px;
  padding: 8px 12px;
  border: 1px solid var(--gray-border, #2A2A2A);
  border-left: 2px solid var(--gray-light, #8A8A8A);
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.02);
  color: var(--text-muted, var(--gray-light, #8A8A8A));
  font-size: 13px;
  line-height: 1.45;
}
html[data-route="/players"] .pl-season-note-switch {
  min-height: 32px;
  padding: 4px 10px;
  border: 1px solid var(--gray-border, #2A2A2A);
  border-radius: 5px;
  background: transparent;
  color: var(--white-bright, #F5F5F5);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  cursor: pointer;
}
html[data-route="/players"] .pl-season-note-switch:hover { border-color: var(--accent, #FF2D2D); }
html[data-route="/players"] .pl-season-note-switch:focus-visible {
  outline: 2px solid var(--accent, #FF2D2D);
  outline-offset: 1px;
}
@media (max-width: 880px) {
  html[data-route="/players"] .pl-season-note-switch { min-height: 44px; }
}

/* ─── INJURED CARD ACCENT — follows the severity tier (D-PL-5) ─────────────── */
/* Was a single always-red inset bar, which made an OUT player and a
   QUESTIONABLE player look identical at a glance. The badge itself (.sns-inj,
   styled by /assets/injury-status.js) carries the abbreviation and hue; this
   just mirrors that hue onto the card edge so the two never disagree. Hexes
   are the same literals the helper injects, kept in sync deliberately rather
   than read from the badge. */
html[data-route="/players"] .pl-card.is-injured {
  box-shadow: inset 2px 0 0 var(--pl-inj-accent, #FF3B30);
}
html[data-route="/players"] .pl-card.is-injured--out          { --pl-inj-accent: #FF3B30; }
html[data-route="/players"] .pl-card.is-injured--doubtful     { --pl-inj-accent: #FF6A00; }
html[data-route="/players"] .pl-card.is-injured--questionable { --pl-inj-accent: #E8B21A; }
html[data-route="/players"] .pl-card.is-injured--probable     { --pl-inj-accent: #9CA0A8; }
/* On a school-colour tile the badge sits over a saturated gradient; a flat dark
   plate keeps every tier legible without changing its hue. */
html[data-route="/players"] .pl-card.is-school-colored .sns-inj {
  background: rgba(0, 0, 0, 0.42);
  text-shadow: none;
}

