@import url('https://fonts.googleapis.com/css2?family=Oswald:wght@400;500;600;700&family=Inter:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&family=Arvo:ital,wght@0,700;1,700&display=swap');

:root{
  --bg: #12151b;
  --bg-raised: #1a1e26;
  --line: #2a2f3a;
  --ink: #edeef0;
  --ink-dim: #8b93a1;
  --flag: #5B87C9;
  --flag-dim: #233A5C;
  --flag-hover: #2A52BE;
  --turf: #A6192E;
  --turf-dim: #3d0a12;
  --pen: #E4362B;
  --pen-dim: #5c1710;
}

*{ box-sizing:border-box; margin:0; padding:0; }

body{
  background: var(--bg);
  color: var(--ink);
  font-family: 'Inter', sans-serif;
  min-height: 100vh;
}

/* Matches welcome.css's/browse_boards.html's own .wrap width (added
   2026-09-09) — those two pages sit at 1180px, this one was still capped at
   the old 720px, which is why the logged-in header (now up to 5 items:
   Browse/My Boards/Create/name/Log out) needed more room to fit on one line
   than this page actually had, and why the whole site read as narrower here
   than on /welcome or /browse-boards. Every card on the logged-in views
   (boards list, sport grid, board page) stretches to use the extra width
   naturally — see #viewAuth below for the one deliberate exception. */
.wrap{ max-width: 1180px; margin: 0 auto; padding: 28px 20px 80px; }

/* The login/register/forgot-password/reset-password card is just one or
   two bare text fields — at the full 1180px width those stretched into a
   single ~1100px-wide input sitting alone in a mostly-empty card, which
   reads as broken rather than spacious (checked visually before deciding
   this, not assumed). Capped to a normal auth-card width and centered,
   same as the rest of the internet's login forms; every other view keeps
   the full-width stretch from the .wrap change above. */
#viewAuth .card{ max-width: 460px; margin: 0 auto; }

/* flex-wrap is on unconditionally (harmless on desktop — the row always
   fits on one line there); see .header-right below for why. */
header{ margin-bottom: 24px; display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; row-gap:12px; gap:12px; }
.eyebrow{
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px; letter-spacing: 0.18em; color: var(--flag);
  text-transform: uppercase; display:flex; align-items:center; gap:10px; margin-bottom: 8px;
}
.eyebrow::before{ content:''; width:18px; height:2px; background:var(--flag); display:inline-block; }
.site-logo{
  height: clamp(28px, 6vw, 42px);
  width: auto;
  display: block;
}
.logo-link{
  display: inline-block;
  line-height: 0; /* no extra baseline gap under the image */
  flex-shrink: 0;
}
.logo-link:hover{ opacity: 0.85; }
/* On a narrow phone, "Browse Boards" + the account chip no longer both
   fit beside the logo without cramming (found 2026-09-06, from real phone
   screenshots after the Browse Boards link shipped) — flex-shrink:0 here
   plus white-space:nowrap on .nav-link means the browser's only remaining
   option, once they don't fit on the logo's line, is to drop this whole
   group to its own line below (header's flex-wrap, above) rather than
   shrinking "Browse Boards" until the words themselves wrap. margin-left:
   auto keeps it flush right whichever line it ends up on.
   flex-wrap here too (added 2026-09-09, once My Boards/Create joined
   Browse/the account chip as a 5-item logged-in row) — even on its own
   line below the logo, five items can outgrow a narrow phone's width;
   this lets them fold onto a second line instead of overflowing past the
   screen edge the way a single non-wrapping row would. */
.header-right{ display:flex; flex-wrap:wrap; align-items:center; gap:20px; row-gap:10px; flex-shrink:0; margin-left:auto; max-width:100%; }
.nav-link{
  font-family:'Oswald',sans-serif; font-weight:600; font-size:13px; text-transform:uppercase;
  letter-spacing:0.03em; color:var(--ink-dim); text-decoration:none; padding:8px 2px;
  border-bottom:2px solid transparent; white-space:nowrap;
}
.nav-link:hover{ color:var(--ink); }
.nav-link.is-current{ color:var(--flag); border-bottom-color:var(--flag); }

/* Matches welcome.css's/browse_boards.html's own "Create a board" — the one
   nav item that's an action, not a place, so it gets the bordered-button
   treatment instead of the plain underline the other two nav links use. */
.nav-cta{
  font-family:'Oswald',sans-serif; font-weight:600; font-size:13px; text-transform:uppercase;
  letter-spacing:0.03em; color:var(--ink); text-decoration:none; border:1px solid var(--line);
  border-radius:7px; padding:8px 16px; white-space:nowrap;
}
.nav-cta:hover{ border-color:var(--flag-hover); color:var(--flag-hover); }
.nav-cta.is-current{ border-color:var(--flag); color:var(--flag); }

.account-chip{
  font-family:'IBM Plex Mono', monospace; font-size:11px; color:var(--ink-dim);
  display:flex; align-items:center; gap:8px; flex-shrink:0;
}
.account-chip button{
  background:none; border:1px solid var(--line); color:var(--ink-dim);
  border-radius:6px; padding:6px 10px; font-family:'IBM Plex Mono',monospace;
  font-size:11px; cursor:pointer;
}
.account-chip button:hover{ color:var(--pen); border-color:var(--pen-dim); }

@media (max-width: 480px){
  .header-right{ gap:14px; }
}

/* Same narrow-phone trim as welcome.css's nav — see its comment. */
@media (max-width: 360px){
  .header-right{ gap:10px; }
  .nav-link{ font-size:12px; }
  .nav-cta{ font-size:12px; padding:7px 12px; }
  .account-chip{ font-size:10px; gap:6px; }
  .account-chip button{ padding:5px 8px; font-size:10px; }
}

.card{
  background: var(--bg-raised); border:1px solid var(--line); border-radius:10px;
  padding:20px; margin-bottom:18px;
}

/* Admin-only board deletion — see delete_board() in boards.py. A quiet red
   border is enough to mark it as the odd one out among the other cards;
   the destructive weight lives in the button/copy, not a loud container. */
#dangerZoneCard{ border-color:var(--pen-dim); }

.field{ margin-bottom:12px; }
.field label{
  display:block; font-family:'IBM Plex Mono',monospace; font-size:11px;
  color:var(--ink-dim); margin-bottom:6px; letter-spacing:0.03em;
}
/* Section headings on the /create page ("Join a board", "Choose a sport",
   "Create a board", "Who can join?", "How many teams can be ranked?") —
   promoted 2026-09-09 from the small dim mono treatment every .field label
   shares to the SAME 19px white Oswald the board page's card titles
   already use (.card-title below, and .board-name above it), so the two
   pages read as one app rather than two. Deliberately opt-in per label
   rather than restyling `.field label` wholesale: subordinate labels like
   "Description (optional)", and every field on the login/register/reset
   forms, should stay the quiet mono treatment. */
.field label.field-heading{
  font-family:'Oswald',sans-serif; font-weight:600; font-size:19px;
  color:var(--ink); letter-spacing:0.01em; margin-bottom:8px;
}
input[type=text], input[type=email], input[type=password]{
  width:100%; background:var(--bg); border:1px solid var(--line); border-radius:7px;
  color:var(--ink); font-family:'Inter',sans-serif; font-size:14px; padding:11px 13px; outline:none;
}
input[type=text]:focus, input[type=email]:focus, input[type=password]:focus{ border-color:var(--flag); }

/* "Keep me logged in" on the login form — deliberately lighter-weight than
   .radio-option's boxed treatment below (a single, low-stakes checkbox
   doesn't need its own bordered card). */
.checkbox-field label{
  display:flex; align-items:center; gap:8px; cursor:pointer;
  font-family:'Inter',sans-serif; font-size:13px; color:var(--ink-dim);
  text-transform:none; letter-spacing:normal;
}
.checkbox-field input{ accent-color:var(--flag); flex-shrink:0; }

button.primary{
  font-family:'Oswald',sans-serif; font-weight:600; font-size:15px; text-transform:uppercase;
  letter-spacing:0.04em; background:var(--flag); color:#f5f7ff; border:none; border-radius:7px;
  padding:13px 26px; cursor:pointer;
}
button.primary:hover{ background:var(--flag-hover); }
button.primary:disabled{ background:var(--line); color:var(--ink-dim); cursor:default; }

.link-btn{
  background:none; border:none; color:var(--flag); font-family:'IBM Plex Mono',monospace;
  font-size:12px; cursor:pointer; text-decoration:underline; padding:0;
}
.link-btn:hover{ color:var(--flag-hover); }
.link-btn.danger-link{ color:var(--pen); }
.link-btn.danger-link:hover{ color:var(--pen-dim); }

button.danger-btn{
  font-family:'Oswald',sans-serif; font-weight:600; font-size:15px; text-transform:uppercase;
  letter-spacing:0.04em; background:var(--pen); color:#f5f7ff; border:none; border-radius:7px;
  padding:13px 26px; cursor:pointer;
}
button.danger-btn:hover:not(:disabled){ background:var(--pen-dim); }
button.danger-btn:disabled{ background:var(--line); color:var(--ink-dim); cursor:default; }

.status-msg{ font-family:'IBM Plex Mono',monospace; font-size:12.5px; color:var(--flag); margin-top:10px; }
.status-msg.err{ color:var(--pen); }

/* --- Boards list --- */
.board-row{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding:12px 14px; border:1px solid var(--line); border-radius:8px; margin-bottom:8px;
  background:var(--bg); cursor:pointer;
}
.board-row:hover{ border-color:var(--flag-dim); }
.board-code{ font-family:'Oswald',sans-serif; font-weight:600; font-size:15px; text-transform:uppercase; }
.board-meta{ font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--ink-dim); }
.badge-submitted{ color:var(--flag); }
.badge-pending{ color:var(--ink-dim); }

.join-row{ display:flex; gap:10px; margin-top:14px; }
.join-row input{ flex:1; }

.visibility-choice{ display:flex; flex-direction:column; gap:8px; }
.radio-option{
  display:flex; align-items:flex-start; gap:10px; cursor:pointer;
  font-family:'Inter',sans-serif; font-size:13px; color:var(--ink-dim);
  border:1px solid var(--line); border-radius:8px; padding:10px 12px;
}
.radio-option:hover{ border-color:var(--flag-dim); }
.radio-option input{ margin-top:3px; accent-color:var(--flag); flex-shrink:0; }
.radio-option strong{ color:var(--ink); }

/* --- Sport selector (create-board form only, added 2026-09-08, shortlist
   item 5) — promoted from the standalone Board Sport Selector mockup
   artifact, same markup/classes. NFL and NHL are real, selectable
   (.enabled); NBA/MLB/WNBA render greyed-out with a "Coming soon" chip
   (.disabled) until their real team data exists (teams.py has no
   NBA_TEAMS/MLB_TEAMS/WNBA_TEAMS yet — see boards.py's VALID_SPORTS). A
   board's sport is fixed at creation, so this field only ever appears on
   the create-board form, never as an edit control elsewhere. */
.sport-grid{
  display:grid; grid-template-columns:repeat(auto-fit, minmax(96px, 1fr)); gap:8px;
}
.sport-card{
  display:flex; flex-direction:column; align-items:center; gap:7px;
  border:1px solid var(--line); border-radius:9px; padding:14px 8px 11px; background:var(--bg);
}
.sport-card.enabled{ cursor:pointer; }
.sport-card.enabled:hover{ border-color:var(--flag-dim); }
.sport-card.selected{ border-color:var(--flag); background:rgba(91,135,201,0.1); }
.sport-card.disabled{ cursor:not-allowed; }
.sport-card.disabled .sport-badge{ opacity:0.55; }
/* Fixed-height wrapper, so all five badges sit on the same baseline
   despite their different viewBox aspect ratios (the football is 100x64
   and the puck 100x74, against the basketball/baseball's square 100x100)
   — the same fix the mockup needed once it was screenshotted. */
.sport-badge{ height:36px; display:flex; align-items:center; justify-content:center; }
.sport-badge svg{ width:46px; height:auto; display:block; }
/* CFB's upright football (cfbBadgeSVG, 64x100) is taller than wide, so it
   sizes by height instead -- by width it would render 72px tall. */
.sport-badge svg.football-badge-vertical{ width:auto; height:36px; }
.sport-name{
  font-family:'Oswald',sans-serif; font-weight:600; font-size:12.5px; text-transform:uppercase;
  letter-spacing:0.03em; color:var(--ink);
}
.sport-card.disabled .sport-name{ color:var(--ink-dim); }
.sport-status{
  font-family:'IBM Plex Mono',monospace; font-size:9px; letter-spacing:0.06em; text-transform:uppercase;
  border-radius:4px; padding:2px 7px; white-space:nowrap;
}
.sport-status.selected{ color:var(--flag); background:rgba(91,135,201,0.14); border:1px solid var(--flag-dim); }
.sport-status.soon{ color:var(--ink-dim); background:var(--bg-raised); border:1px solid var(--line); }
/* The "sport can't be changed later" caption sat tight against the bottom
   of the card row, reading as if it belonged to the WNBA tile rather than
   to the field as a whole — given room 2026-09-09 so it reads as the
   field's own footnote. */
#createSportHint{ margin-top:14px; }

/* --- Team pool picker (capped rankings — create-board form + the
   admin-only "Team pool" card on a board) --- */
.team-pool-picker{ margin-top:10px; }
.my-pool-picker{ margin-bottom:16px; }
.team-pool-grid{ display:flex; flex-wrap:wrap; gap:6px; margin-top:8px; }
.pool-chip{
  font-family:'IBM Plex Mono',monospace; font-weight:600; font-size:11px; letter-spacing:0.03em;
  border:1px solid var(--line); border-radius:6px; padding:6px 9px; background:var(--bg);
  color:var(--ink-dim); cursor:pointer; transition:background 0.1s, color 0.1s, border-color 0.1s;
}
.pool-chip:hover{ border-color:var(--flag-dim); }
.pool-chip.checked{ border-color:transparent; }
.pool-chip:disabled{ cursor:not-allowed; opacity:0.4; }

/* --- Conference-tab team picker (CFB, 138 teams) — variant C of the "CFB
   Team Picker" mockup artifact, picked by Matt 2026-09-25. Replaces the flat
   .team-pool-grid wall of chips for sports whose teams carry a `conference`
   (see renderConferencePicker() in app.js). Search overrides the tabs. --- */
.conf-picker-search{
  display:block; width:100%; margin:2px 0 10px; background:var(--bg); border:1px solid var(--line); border-radius:7px;
  color:var(--ink); font-family:'Inter',sans-serif; font-size:14px; padding:10px 12px; outline:none;
}
.conf-picker-search:focus{ border-color:var(--flag); }
.conf-picker-search::placeholder{ color:var(--ink-dim); }
.conf-tab-row{ display:flex; gap:2px; overflow-x:auto; border-bottom:1px solid var(--line); margin-bottom:10px; scrollbar-width:thin; }
.conf-tab{
  flex:0 0 auto; font-family:'IBM Plex Mono',monospace; font-size:11px; font-weight:600; letter-spacing:0.03em;
  color:var(--ink-dim); background:none; border:none; border-bottom:2px solid transparent;
  padding:8px 10px 9px; cursor:pointer; white-space:nowrap;
}
.conf-tab:hover{ color:var(--ink); }
.conf-tab.active{ color:var(--ink); border-bottom-color:var(--flag); }
.conf-tab-count{
  display:inline-block; min-width:16px; margin-left:5px; padding:0 4px; border-radius:8px;
  background:var(--flag-dim); color:var(--ink); font-size:10px; text-align:center; font-variant-numeric:tabular-nums;
}
.team-pool-grid.conf-picker{ display:block; }
.conf-picker-grid .pool-chip{ font-size:12px; padding:8px 11px; }
.pool-chip .chip-conf{ font-weight:400; opacity:0.7; margin-left:6px; }
.conf-picker-empty{ font-family:'IBM Plex Mono',monospace; font-size:12px; color:var(--ink-dim); padding:6px 0; }

/* --- Week-over-week movement indicator (aggregate results rows) --- */
.move-indicator{
  font-family:'IBM Plex Mono',monospace; font-size:11px; font-weight:600;
  letter-spacing:0.01em; min-width:24px; text-align:center; flex-shrink:0;
}
.move-up{ color:#8fe3a6; }
.move-down{ color:#ff9b93; }
.move-flat{ color:#a9b0bd; }
.move-new{
  color:var(--flag); border:1px solid var(--flag-dim); border-radius:4px;
  padding:1px 4px; font-size:9px; letter-spacing:0.04em;
}

.pending-row{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding:10px 12px; border:1px solid var(--line); border-radius:8px; margin-bottom:8px;
  background:var(--bg); font-family:'Inter',sans-serif; font-size:14px;
}
.pending-row .link-btn{ margin-left:10px; }
.pending-row .deny-btn{ color:var(--pen); }

/* --- Week bar (browse any week in this board's range — the results
   card, and the ranking card's open/closed state, both key off whichever
   week is selected here). This is the first thing shown under the board
   header/eyebrow, replacing the old small in-card week <select> so
   browsing past weeks doesn't require first finding it. --- */
.week-bar{
  display:flex; align-items:center; justify-content:space-between; gap:16px;
  background:var(--bg-raised); border:1px solid var(--line); border-radius:12px;
  padding:16px 18px; margin-bottom:20px;
}
.week-bar-left{ min-width:0; flex:1; }
.week-bar-label{
  font-family:'IBM Plex Mono',monospace; font-size:10.5px; letter-spacing:0.14em;
  color:var(--ink-dim); text-transform:uppercase; margin-bottom:6px;
}
.week-select-wrap{ position:relative; display:inline-block; max-width:100%; }
select.week-select-big{
  appearance:none; -webkit-appearance:none; background:transparent; border:none; outline:none;
  color:var(--ink); font-family:'Oswald',sans-serif; font-weight:600; font-size:22px; text-transform:uppercase;
  letter-spacing:0.01em; padding:0 26px 0 0; cursor:pointer; max-width:100%;
}
select.week-select-big option{ background:var(--bg-raised); color:var(--ink); font-size:14px; }
.week-select-chevron{
  position:absolute; right:2px; top:50%; transform:translateY(-50%);
  width:14px; height:14px; color:var(--ink-dim); pointer-events:none;
}
.week-bar-sub{ font-family:'IBM Plex Mono',monospace; font-size:11.5px; color:var(--ink-dim); margin-top:5px; }

/* Live/Locked status pill — used both on the week bar (for whichever
   week is selected) and, smaller, on the results card itself so a
   locked week reads as "final" even after scrolling past the bar. */
.status-pill{
  flex-shrink:0; display:inline-flex; align-items:center; gap:6px; font-family:'IBM Plex Mono',monospace;
  font-weight:600; font-size:11px; letter-spacing:0.06em; text-transform:uppercase; border-radius:20px; padding:6px 12px;
}
.status-pill.small{ padding:4px 9px; }
.status-pill svg{ width:11px; height:11px; flex-shrink:0; }
.status-pill.live{ color:var(--flag); border:1px solid var(--flag-dim); background:rgba(91,135,201,0.12); }
.status-pill.locked{ color:var(--pen); border:1px solid var(--pen-dim); background:rgba(228,54,43,0.10); }
.live-dot{ width:6px; height:6px; border-radius:50%; background:var(--flag); flex-shrink:0; animation:week-live-pulse 1.8s ease-in-out infinite; }
@keyframes week-live-pulse{ 0%,100%{ opacity:1; } 50%{ opacity:0.35; } }

/* --- Ranking rows --- */
.hint{ font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--ink-dim); margin-bottom:14px; }
.draft-status{ margin-top:10px; margin-bottom:0; display:flex; align-items:center; gap:8px; flex-wrap:wrap; }

/* .row-list/.row are shared between the ranking list and the aggregate
   results list, so both read as the same component — just the ranking
   list's rows are draggable and the results list's aren't (.static). */
.row-list{ border:1px solid var(--line); border-radius:10px; overflow:hidden; }
ul#rankList{ list-style:none; }
.row{
  display:flex; align-items:center; gap:14px; background:var(--bg-raised);
  border-bottom:1px solid var(--line); padding:12px 14px; cursor:grab;
}
.row:last-child{ border-bottom:none; }
.row:hover{ background:#1f2530; }
.row.dragging{ opacity:0.35; }
.row.drag-over{ box-shadow: inset 0 2px 0 var(--flag); }
.row.static{ cursor:default; }

/* Grouped tightly so the numeral sits close to the grab handle, leaving the
   14px row gap to work for the crest box instead of the gutter. */
.row-lead{ display:flex; align-items:center; gap:5px; flex-shrink:0; }
.drag-dot{ color:var(--ink-dim); font-size:14px; letter-spacing:2px; flex-shrink:0; user-select:none; }
.rank-num{ font-family:'IBM Plex Mono',monospace; font-weight:600; font-size:18px; color:#f5f5f5; width:26px; text-align:right; flex-shrink:0; }

.crest-box{
  display:flex; align-items:center; gap:10px; border-radius:8px; padding:6px 12px;
  min-height:44px; flex:1; min-width:0; overflow:hidden;
}
/* Sized to the football badge's own 100:64 aspect ratio (25:16) rather than
   a square — was a 32x32 circle until 2026-09-08, replaced with a football
   shape per user request/design exploration (see footballBadgeSVG() in
   app.js, and shareDrawFootballBadge() in share.js for the canvas-export
   counterpart). */
.crest-logo-wrap{ width:44px; height:28px; flex-shrink:0; display:flex; align-items:center; justify-content:center; position:relative; }
.football-badge{ display:block; width:100%; height:100%; }
/* Hockey puck badge (added 2026-09-08) — same box, different viewBox aspect
   ratio (100x74 vs. the football badge's 100x64); SVG's default
   preserveAspectRatio="xMidYMid meet" letterboxes rather than stretches, so
   this sizing rule is identical to .football-badge's on purpose. */
.hockey-badge{ display:block; width:100%; height:100%; }
/* Basketball badge (real NBA team badges added 2026-09-16) — same box
   again, square 100x100 viewBox this time; xMidYMid meet still letterboxes
   it inside the same 44x28/38x24 box the other two sports use, so no new
   .crest-logo-wrap sizing rule is needed here either. */
.basketball-badge{ display:block; width:100%; height:100%; }
/* Name + stat chip side by side by default; the narrow-phone breakpoint
   below stacks them instead of letting the name get crushed. */
.crest-main{ display:flex; align-items:center; gap:8px; flex:1; min-width:0; }
.crest-name{
  flex:1; min-width:0; font-family:'Oswald',sans-serif; font-weight:600; font-size:14px;
  text-transform:uppercase; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.crest-name-short{ display:none; letter-spacing:0.02em; }

/* Record + this-week result, e.g. "9-3" + "W". Sits on a fixed dark scrim
   rather than each team's own ink color — 32 background colors is too many
   to hand-tune contrast for individually, and a translucent black backing
   stays legible over every one of them. Result color is semantic (win/loss/
   tie/bye) layered on top of that same scrim for the same reason. */
.crest-stat{
  display:inline-flex; align-items:center; gap:5px; flex-shrink:0;
  background:rgba(0,0,0,0.38); border-radius:5px; padding:3px 7px;
  font-family:'IBM Plex Mono',monospace; font-size:11px; line-height:1;
}
.crest-record{ color:#f2f3f5; font-variant-numeric:tabular-nums; }
.crest-result{ font-weight:700; letter-spacing:0.03em; }
.crest-result-w{ color:#8fe3a6; }
.crest-result-l{ color:#ff9b93; }
.crest-result-t{ color:#dde2ec; }
.crest-result-bye{ color:#a9b0bd; font-weight:600; }

/* Up/down nudge buttons — a one-tap alternative to dragging or Move,
   shown alongside both at every width (2026-08-26, at the user's request
   — an earlier version showed these only on mobile, in place of Move). */
.nudge-btns{ display:flex; flex-direction:column; gap:3px; flex-shrink:0; }
.nudge-btn{
  width:26px; height:19px; padding:0; border-radius:5px; border:1px solid var(--line);
  background:var(--bg); color:var(--ink-dim); cursor:pointer;
  display:flex; align-items:center; justify-content:center; font-size:9px; line-height:1;
}
.nudge-btn:hover:not(:disabled){ color:var(--flag-hover); border-color:var(--flag-hover); }
.nudge-btn:disabled{ opacity:0.3; cursor:default; }

/* Below ~480px the ranking row swaps the full "City Mascot" name (e.g.
   "Arizona Cardinals") for just the mascot ("Cardinals") — the team badge
   already carries the location as a 3-letter code, so the full name
   was redundant with it, and a beta tester asked for mascot-only on mobile
   specifically (2026-08-26) rather than the full name truncating awkwardly
   on the narrowest phones. Desktop keeps the full name (plenty of room). */
@media (max-width: 480px){
  .crest-name-full{ display:none; }
  .crest-name-short{ display:inline; }

  /* A bit more give for the crest box specifically: the row's own side
     padding and the numeral's column both shrink a touch. */
  li.row{ padding-left:10px; padding-right:10px; gap:10px; }
  .rank-num{ width:20px; font-size:16px; }

  /* "Your Board" movement badges (2026-09-22) add a third element to
     row-lead (drag-dot + rank-num already live here) on top of the
     nudge/Move controls this row already fights for space with below —
     same trim-not-hide treatment as everything else in this block. */
  .row-lead{ gap:3px; }
  .move-indicator{ min-width:18px; font-size:10px; }

  /* The Move control (slot input + confirm/cancel) leaves no room for the
     name on a narrow screen while it's open — drop it and lean on the logo
     + rank number instead of truncating awkwardly. */
  .row.move-active .crest-name,
  .row.move-active .crest-stat{ display:none; }

  /* Both the nudge arrows and Move sit in the row at every width (see
     .nudge-btns/.movers above) — on a phone that's two controls competing
     with the crest for space, so each gets trimmed here to give the
     mascot name more room before it has to truncate. Desktop keeps the
     larger, easier-to-hit sizing since it isn't short on width. */
  .crest-name{ font-size:12.5px; }
  .movers{ gap:4px; }
  .nudge-btn{ width:21px; height:17px; font-size:8px; }
  .move-btn{ padding:6px 8px; font-size:10px; }

  /* The crest box itself gives a little more back too — even with the
     trims above, the two longest mascot names ("Buccaneers",
     "Commanders") were still clipping by ~10-15px. */
  .crest-box{ gap:8px; padding-left:8px; padding-right:8px; }
  .crest-logo-wrap{ width:38px; height:24px; }
}

/* On the narrowest phones (~360px and below — still a common Android
   width), the abbreviation + stat chip no longer both fit on one line at
   readable size; the name loses the fight and truncates to one letter.
   Stack them instead of shrinking the name further. */
@media (max-width: 374px){
  .crest-main{ flex-direction:column; align-items:flex-start; gap:1px; }
  .crest-name{ flex:none; width:100%; }
  .crest-box{ padding-top:5px; padding-bottom:5px; }
}

.movers{ display:flex; align-items:center; gap:6px; flex-shrink:0; }
.move-btn{
  font-family:'IBM Plex Mono',monospace; font-weight:600; font-size:11px; letter-spacing:0.05em;
  text-transform:uppercase; background:var(--flag); color:#f5f7ff; border:none; border-radius:6px;
  padding:8px 13px; cursor:pointer;
}
.move-btn:hover{ background:var(--flag-hover); }
.move-input{
  width:46px; background:var(--bg); border:1px solid var(--flag-dim); border-radius:6px;
  color:var(--ink); font-family:'IBM Plex Mono',monospace; font-size:13px; padding:6px 4px; text-align:center; outline:none;
}
.move-input:focus{ border-color:var(--flag); }
.move-confirm, .move-cancel{
  width:28px; height:28px; padding:0; border-radius:6px; border:1px solid var(--line);
  background:var(--bg); color:var(--ink-dim); cursor:pointer; display:flex; align-items:center; justify-content:center; font-size:13px;
}
.move-confirm:hover{ color:var(--flag-hover); border-color:var(--flag-hover); }
.move-cancel:hover{ color:var(--pen); border-color:var(--pen-dim); }

.submit-row{ display:flex; align-items:center; gap:14px; margin-top:20px; }

/* --- Aggregate --- */
.agg-meta{
  font-family:'IBM Plex Mono',monospace; font-size:12px; color:var(--ink-dim);
  margin-bottom:14px; display:flex; justify-content:space-between; align-items:center; gap:10px; flex-wrap:wrap;
}
.agg-meta-left{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.agg-controls{ display:flex; align-items:center; gap:12px; flex-shrink:0; }

/* Each aggregate row reuses the ranking row's crest-box look (row-lead,
   crest-box, crest-main, crest-name, crest-stat) so the two lists read as
   one visual system. The only new piece is the chevron that reveals the
   spread bar, which used to sit open under every row by default. */
.spread-toggle{
  flex-shrink:0; width:30px; height:30px; border-radius:7px; border:1px solid var(--line);
  background:var(--bg); color:var(--ink-dim); cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  transition:color 0.15s, border-color 0.15s;
}
.spread-toggle:hover{ color:var(--flag-hover); border-color:var(--flag-hover); }
.spread-toggle[aria-expanded="true"]{ color:var(--flag); border-color:var(--flag-dim); }
.spread-toggle svg{ width:13px; height:13px; transition:transform 0.15s; }
.spread-toggle[aria-expanded="true"] svg{ transform:rotate(180deg); }

.spread-panel{ background:var(--bg); padding:14px 16px 16px; border-bottom:1px solid var(--line); }
.spread-track{ position:relative; height:5px; background:var(--line); border-radius:3px; overflow:hidden; }
.spread-fill{ position:absolute; top:0; bottom:0; background:var(--turf-dim); border-radius:3px; }
.spread-avg{ position:absolute; top:-2px; width:2px; height:9px; background:var(--flag); }
.spread-caption{
  display:flex; justify-content:space-between; gap:10px; margin-top:9px;
  font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--ink-dim);
}

/* Shareable-image export (see share.js) — renders a board's results to an
   off-screen <canvas> (#shareCanvas in index.html) and downloads it as a
   PNG. This row just holds the two trigger buttons; the canvas itself is
   never shown on the page. */
.share-row{
  display:flex; align-items:center; gap:14px; flex-wrap:wrap;
  margin-top:16px; padding-top:14px; border-top:1px solid var(--line);
}

/* list-toggle (the old <details> wrapper around individual submissions) was
   removed in the 2026-09-08 board-page reorg — that section is now its own
   collapsible .card like everything else; see .card-title-row below. */

/* Individual submissions: a rank(1-32) x submitter pivot table, each cell a
   team chip colored with that team's own brand color (never the sample
   sheet's colors) — mirrors the spreadsheet layout this is replacing. */
.ind-table-wrap{
  border:1px solid var(--line); border-radius:10px; overflow:auto; max-height:560px; margin-top:10px;
}
table.ind-table{ border-collapse:collapse; width:100%; }
.ind-table th, .ind-table td{
  padding:7px 9px; text-align:center; white-space:nowrap; border-bottom:1px solid var(--line);
}
.ind-table thead th{
  position:sticky; top:0; z-index:2; background:var(--bg-raised); color:var(--ink);
  font-family:'Oswald',sans-serif; font-weight:600; font-size:12px; text-transform:uppercase; letter-spacing:0.02em;
}
.ind-sub-time{
  font-family:'IBM Plex Mono',monospace; font-weight:400; font-size:9.5px; text-transform:none;
  color:var(--ink-dim); letter-spacing:0; margin-top:2px;
}
.ind-table tbody tr:last-child td{ border-bottom:none; }
.ind-table .ind-rank-col{
  position:sticky; left:0; z-index:1; background:var(--bg-raised); color:var(--ink-dim);
  font-family:'IBM Plex Mono',monospace; font-weight:600; border-right:1px solid var(--line);
}
.ind-table thead th.ind-rank-col{ z-index:3; }
.ind-chip{
  display:inline-block; min-width:38px; padding:4px 8px; border-radius:5px;
  font-family:'IBM Plex Mono',monospace; font-weight:700; font-size:11px; letter-spacing:0.03em;
}

/* Right-edge fade + arrow hint for the individual-submissions table, shown
   only while there's more to scroll to (toggled via the .can-scroll-right
   class — see updateIndScrollHints in app.js). Added 2026-08-24 after the
   mobile-layout review found the table clipping extra submitter columns on
   narrow screens with no indication there was more to scroll to. (A
   matching left-edge hint isn't useful here — it would render directly
   under the opaque sticky rank column, which always sits at the same
   left:0 edge and would paint over it.) */
.ind-scroll-container{ position:relative; }
.ind-scroll-hint-right{
  position:absolute; top:var(--ind-hint-top, 34px); bottom:0; right:0; width:36px;
  display:flex; align-items:center; justify-content:flex-end; padding-right:5px;
  background:linear-gradient(to left, var(--bg-raised) 35%, transparent);
  opacity:0; pointer-events:none; transition:opacity 0.15s ease;
}
.ind-scroll-hint-right svg{ width:13px; height:13px; color:var(--ink-dim); flex-shrink:0; }
.ind-scroll-container.can-scroll-right .ind-scroll-hint-right{ opacity:1; }
@media (prefers-reduced-motion: reduce){
  .ind-scroll-hint-right{ transition:none; }
}

/* Master Board (2026-09-11): a rank(1-N) x week pivot table, same shape and
   the same data-team-color/data-team-ink chip pattern as .ind-table above
   — deliberately its own class set rather than reusing .ind-* directly, so
   the two tables' sticky headers/scroll hints (each keyed to its own
   #...TableWrap id — see updateMasterScrollHints() in app.js) never fight
   over the same --ind-hint-top custom property if a future change ever
   let both render at once. */
.master-table-wrap{
  border:1px solid var(--line); border-radius:10px; overflow:auto; max-height:560px; margin-top:10px;
}
table.master-table{ border-collapse:collapse; width:100%; }
.master-table th, .master-table td{
  padding:7px 9px; text-align:center; white-space:nowrap; border-bottom:1px solid var(--line);
}
.master-table thead th{
  position:sticky; top:0; z-index:2; background:var(--bg-raised); color:var(--ink);
  font-family:'Oswald',sans-serif; font-weight:600; font-size:12px; text-transform:uppercase; letter-spacing:0.02em;
}
.master-table tbody tr:last-child td{ border-bottom:none; }
.master-table .master-rank-col{
  position:sticky; left:0; z-index:1; background:var(--bg-raised); color:var(--ink-dim);
  font-family:'IBM Plex Mono',monospace; font-weight:600; border-right:1px solid var(--line);
}
.master-table thead th.master-rank-col{ z-index:3; }
/* min-width matches .ind-chip's 38px (2026-09-12) — both hold the same
   3-letter team abbreviation now that Master Board chips switched from
   full mascot names to abbreviations (see loadMasterBoard() in app.js). */
.master-chip{
  display:inline-block; min-width:38px; padding:4px 8px; border-radius:5px;
  font-family:'IBM Plex Mono',monospace; font-weight:700; font-size:11px; letter-spacing:0.03em;
}

/* Overall / Mine segmented switch above the Master Board table
   (2026-09-26) — same --line/--flag tokens as .spread-toggle, so the
   selected half reads as the app's usual "on" blue. */
.master-view-bar{ display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin-bottom:10px; }
.master-view-toggle{
  display:inline-flex; border:1px solid var(--line); border-radius:8px;
  overflow:hidden; background:var(--bg);
}
/* Member picker for the Individual view (2026-09-27) — same height and
   border as the segmented switch beside it; wraps under it on narrow
   screens rather than squeezing either. */
.master-member-select{
  min-width:0; max-width:100%; height:32px; padding:0 10px; border:1px solid var(--line); border-radius:8px;
  background:var(--bg); color:var(--ink); font-family:'Inter',sans-serif; font-size:13px; cursor:pointer;
}
.master-member-select:focus-visible{ outline:2px solid var(--flag); outline-offset:1px; }
.master-member-select option{ background:var(--bg-raised); color:var(--ink); }
/* ▲/▼ badge + chip side by side in an Individual-view cell, badge on the
   left (2026-09-27, per Matt) like "Your Board"'s badge sitting before the
   team; reuses .move-indicator (see the aggregate rows above). */
.master-cell{ display:inline-flex; align-items:center; gap:4px; }
.master-cell .move-indicator{ min-width:22px; font-size:10px; }
.master-view-btn{
  min-width:84px; padding:7px 14px; border:none; background:transparent; color:var(--ink-dim);
  font-family:'Oswald',sans-serif; font-weight:600; font-size:12px; text-transform:uppercase; letter-spacing:0.04em;
  cursor:pointer; transition:color 0.15s, background 0.15s;
}
.master-view-btn + .master-view-btn{ border-left:1px solid var(--line); }
.master-view-btn:hover{ color:var(--flag-hover); }
.master-view-btn.active{ color:var(--flag); background:rgba(91,135,201,0.12); }
.master-view-btn:focus-visible{ outline:2px solid var(--flag); outline-offset:-2px; }
@media (prefers-reduced-motion: reduce){
  .master-view-btn{ transition:none; }
}

.master-scroll-container{ position:relative; }
.master-scroll-hint-right{
  position:absolute; top:var(--master-hint-top, 34px); bottom:0; right:0; width:36px;
  display:flex; align-items:center; justify-content:flex-end; padding-right:5px;
  background:linear-gradient(to left, var(--bg-raised) 35%, transparent);
  opacity:0; pointer-events:none; transition:opacity 0.15s ease;
}
.master-scroll-hint-right svg{ width:13px; height:13px; color:var(--ink-dim); flex-shrink:0; }
.master-scroll-container.can-scroll-right .master-scroll-hint-right{ opacity:1; }
@media (prefers-reduced-motion: reduce){
  .master-scroll-hint-right{ transition:none; }
}

.empty{ font-family:'IBM Plex Mono',monospace; color:var(--ink-dim); font-size:13px; padding:30px 0; text-align:center; line-height:1.7; }
.back-link{ display:inline-block; margin-bottom:16px; font-family:'IBM Plex Mono',monospace; font-size:12px; color:var(--ink-dim); cursor:pointer; text-decoration:underline; }
.back-link:hover{ color:var(--flag-hover); }

footer{
  margin-top:36px; display:flex; align-items:center; gap:10px;
  font-family:'IBM Plex Mono',monospace; font-size:10.5px; color:var(--ink-dim); opacity:0.6;
}
.footer-mark{ height:22px; width:auto; flex-shrink:0; }

/* Ko-fi support note — its own line for the same reason nfl-disclaimer
   (below) is: it reads as a distinct aside, not part of the "Rankings
   recompute live..." row's voice. Slightly more visible than the legal
   disclaimer since this is an actual call-to-action, and the link itself
   gets the brand accent color so it doesn't just fade into boilerplate. */
.support-note{
  margin-top:10px;
  font-family:'IBM Plex Mono',monospace; font-size:10px; line-height:1.5;
  color:var(--ink-dim); opacity:0.65;
}
.support-note a{ color:var(--flag); text-decoration:underline; }
.support-note a:hover{ color:var(--flag-hover); }

/* Trademark disclaimer — the app displays real team crests/colors for
   multiple leagues (NFL live, NHL live, NBA/MLB/WNBA still "coming soon"
   but already named on the sport selector — see §11 of the release plan),
   and this makes explicit that Collaboranker isn't any of them saying so.
   Renamed from .nfl-disclaimer 2026-09-09 once the text itself stopped
   being NFL-only. Deliberately its own line below the footer proper (not
   folded into the "Rankings recompute live..." row) so it reads as a
   standalone legal notice rather than part of the app's own voice. */
.league-disclaimer{
  margin-top:10px;
  font-family:'IBM Plex Mono',monospace; font-size:9.5px; line-height:1.5;
  color:var(--ink-dim); opacity:0.5;
}

/* --- Board identity (name/description + admin edit) --- */
.board-identity{ margin-bottom:18px; }
/* Row layout added 2026-09-12 for the sport badge — title/description on
   the left (can wrap/shrink freely), badge fixed-size on the right. Wraps
   to its own line under a long name/description on a narrow phone rather
   than squeezing the text column down further. */
.board-identity-row{ display:flex; align-items:flex-start; justify-content:space-between; gap:16px; flex-wrap:wrap; }
.board-identity-text{ flex:1 1 220px; min-width:0; }
/* Reuses .sport-card/.sport-badge/.sport-name from the create-board sport
   selector above (same badge art, same box), but static — no .enabled/
   .selected classes, since a board's sport can't be changed once created. */
.board-sport-badge{ flex:0 0 auto; }
/* The board name itself — sized/weighted to match this page's other
   headers (e.g. #membersCard/#inviteCard/#teamPoolCard's card-title
   labels below) rather than the small mono .eyebrow tag it used to
   share with the site's own "Crowd Sourced Sports Rankings" tagline. */
.board-name{
  font-family:'Oswald',sans-serif; font-weight:600; font-size:19px;
  text-transform:uppercase; letter-spacing:0.01em; color:var(--ink); margin-bottom:8px;
}
.board-description{
  font-family:'Inter',sans-serif; font-size:14px; line-height:1.5; color:var(--ink-dim);
  margin-top:2px; white-space:pre-wrap;
}

/* --- Card title rows (2026-09-08 board-page reorg) ---
   Every board-page card's header now shares this one component: a title in
   19px white Oswald (the same treatment "Who's on this board"/"Invite
   link"/"Ranking size" already used), plus an optional trailing meta note
   and collapse chevron. Two flavors:
   - `<button class="card-title-row" data-collapse-toggle>` — the
     collapsible cards (everything except Browsing Week and Overall Board).
     Clicking it toggles the card's `.collapsed` class; see
     initCollapsibleSections()/applyStoredCollapseStates() in app.js for the
     click handling and the per-board localStorage persistence.
   - `<div class="card-title-row is-static">` — Overall Board only: same
     look, not interactive, no chevron. */
.card-title-row{
  display:flex; align-items:center; gap:8px; width:100%; margin-bottom:10px;
}
button.card-title-row{
  background:none; border:none; padding:0; font:inherit; text-align:left; cursor:pointer;
}
button.card-title-row:focus-visible{ outline:2px solid var(--flag); outline-offset:3px; border-radius:4px; }
/* Groups the title with its optional meta note (currently just Individual
   submissions' "N submissions") so the two wrap TOGETHER on a narrow phone
   instead of the meta note detaching to its own line at the far right —
   the bug behind the 2026-09-08 spacing fix. `min-width:0` lets this flex
   item actually shrink/wrap instead of forcing the row wider than the
   card; `align-items:baseline` keeps the much-smaller mono meta text
   sitting on the title's baseline rather than floating at its vertical
   center. */
.card-title-group{
  display:flex; flex-wrap:wrap; align-items:baseline; gap:6px; row-gap:2px;
  flex:1; min-width:0;
}
.card-title{
  font-family:'Oswald',sans-serif; font-weight:600; font-size:19px;
  color:var(--ink); letter-spacing:0.01em;
}
.card-title-meta{
  font-family:'IBM Plex Mono',monospace; font-weight:500; font-size:11px;
  color:var(--ink-dim); letter-spacing:0.02em;
}
.collapse-chevron{
  width:12px; height:8px; flex-shrink:0; margin-left:auto; color:var(--ink-dim);
  transition:transform 0.15s ease, color 0.15s ease;
}
button.card-title-row:hover .collapse-chevron{ color:var(--flag-hover); }
.card.collapsed .collapse-chevron{ transform:rotate(-90deg); }
.card.collapsed > .card-body{ display:none; }

/* --- Board roster (item 6) --- */
.member-row{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding:9px 12px; border:1px solid var(--line); border-radius:8px; margin-bottom:6px;
  background:var(--bg); font-family:'IBM Plex Mono',monospace; font-weight:500;
  font-size:13px; text-transform:uppercase; letter-spacing:0.03em;
}
.member-row:last-child{ margin-bottom:0; }
.member-admin-tag{
  font-family:'IBM Plex Mono',monospace; font-size:10px; letter-spacing:0.05em; text-transform:uppercase;
  color:var(--flag); border:1px solid var(--flag-dim); border-radius:4px; padding:2px 6px;
}

/* --- Ballot-size slider (create-board form + admin "Ranking size" card) —
   replaces the old fixed 5/10/14/32 radio buttons with a free 2-31 slider,
   those four sizes kept on as quick-pick presets (item 4). --- */
.pool-size-control{ margin-top:8px; }
.pool-size-presets{ display:flex; flex-wrap:wrap; gap:8px; margin-bottom:12px; }
.preset-btn{
  font-family:'IBM Plex Mono',monospace; font-weight:600; font-size:11px; letter-spacing:0.03em;
  border:1px solid var(--line); border-radius:6px; padding:7px 11px; background:var(--bg);
  color:var(--ink-dim); cursor:pointer; transition:border-color 0.1s, color 0.1s;
}
.preset-btn:hover{ border-color:var(--flag-dim); color:var(--ink); }
.preset-btn.active{ border-color:var(--flag); color:var(--flag); background:rgba(91,135,201,0.1); }
.pool-size-slider{
  width:100%; accent-color:var(--flag); cursor:pointer; display:block; margin-bottom:10px;
}
.pool-size-readout{
  font-family:'Oswald',sans-serif; font-weight:600; font-size:15px; text-transform:uppercase;
  letter-spacing:0.01em; color:var(--ink);
}

/* --- Honorable-mention toggle (create-board form + admin panel) --- */
.checkbox-field-label{
  display:flex; align-items:center; gap:8px; cursor:pointer;
  font-family:'Inter',sans-serif; font-size:14px; color:var(--ink); margin-bottom:8px;
}
.checkbox-field-label input{ accent-color:var(--flag); flex-shrink:0; }
.hm-slots-choice{ display:flex; gap:16px; margin-top:10px; }
.radio-option-inline{
  display:flex; align-items:center; gap:6px; cursor:pointer;
  font-family:'Inter',sans-serif; font-size:13px; color:var(--ink-dim);
}
.radio-option-inline input{ accent-color:var(--flag); }
/* A slot count the current ranking size can't support (ranked + honorable
   mentions would exceed the league's 32 teams — see setupPoolSizeControl's
   render() in app.js) reads as unavailable rather than just failing to
   check when clicked. */
.radio-option-inline.disabled{ color:var(--line); cursor:not-allowed; }
.radio-option-inline input:disabled{ accent-color:var(--line); cursor:not-allowed; }

/* --- Trivia (item 9) --- */
.trivia-block{
  margin-top:16px; padding-top:14px; border-top:1px solid var(--line);
}
.trivia-label{
  font-family:'IBM Plex Mono',monospace; font-size:10.5px; letter-spacing:0.14em;
  color:var(--ink-dim); text-transform:uppercase; margin-bottom:6px;
}
/* Which round "Trivia" is showing/being edited (added 2026-09-20 — trivia
   went per-round, so this is no longer implied by context the way a single
   board-wide blurb didn't need to say). Un-does the label's own uppercase/
   letter-spacing so a week label like "Week 3" reads normally next to it. */
.trivia-week-label{
  text-transform:none; letter-spacing:normal; font-weight:400; margin-left:6px;
}
.trivia-block p{
  font-family:'Inter',sans-serif; font-size:14px; line-height:1.6; color:var(--ink); white-space:pre-wrap;
}

textarea{
  width:100%; background:var(--bg); border:1px solid var(--line); border-radius:7px;
  color:var(--ink); font-family:'Inter',sans-serif; font-size:14px; padding:11px 13px; outline:none;
  resize:vertical;
}
textarea:focus{ border-color:var(--flag); }

/* --- Suggested stat callouts (auto-generated riser/faller + bold-take
   blurbs, shown above the trivia textarea in the admin's edit card — see
   loadStatCallouts() in app.js / get_stat_callouts_data() in rankings.py) --- */
.callouts-box{
  margin-bottom:16px; padding-bottom:14px; border-bottom:1px solid var(--line);
}
.callouts-label{
  font-family:'IBM Plex Mono',monospace; font-size:10.5px; letter-spacing:0.14em;
  color:var(--ink-dim); text-transform:uppercase; margin-bottom:8px;
}
.callout-row{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding:9px 11px; border:1px solid var(--line); border-radius:7px; background:var(--bg);
  margin-bottom:6px;
}
.callout-text{
  font-family:'Inter',sans-serif; font-size:13px; line-height:1.5; color:var(--ink);
}
.callout-text.callout-riser{ border-left:2px solid #8fe3a6; padding-left:8px; }
.callout-text.callout-faller{ border-left:2px solid #ff9b93; padding-left:8px; }
.callout-text.callout-bold_take{ border-left:2px solid var(--flag); padding-left:8px; }
.callout-row .callout-insert-btn{ flex-shrink:0; white-space:nowrap; }
/* "Nothing to suggest this round" — deliberately quieter than a real
   callout row (no border, no insert button), but present, so an admin can
   tell the feature ran and found nothing rather than wondering whether it
   failed. Added 2026-09-09 after exactly that confusion. */
.callout-empty{
  font-family:'IBM Plex Mono',monospace; font-size:11px; line-height:1.6;
  color:var(--ink-dim); padding:2px 0;
}

.hidden{ display:none !important; }

/* Utility classes standing in for what used to be inline style="" attributes
   in index.html (margin-top:14px etc.) — needed so the page can run under a
   Content-Security-Policy with no 'unsafe-inline' in style-src (see the
   release plan doc's Content-Security-Policy section). Team-color and
   layout-percentage styling that varies per team/row is handled differently
   — see applyDynamicStyles() in app.js — since a fixed set of utility
   classes can't cover an unbounded range of values. */
.mt-6{ margin-top:6px; }
.mt-10{ margin-top:10px; }
.mt-12{ margin-top:12px; }
.mt-14{ margin-top:14px; }
.mb-0{ margin-bottom:0; }
.inline{ display:inline; }


/* ===================== Team profile (2026-09-29) =====================
   Opened from any read-only team bar/chip on a board (see
   static/js/team_profile.js). Built from the app's own components
   (.card, .crest-box, .sport-card, .spread-*, .status-pill, .member-row);
   only the layout below is new. Design: "team profile, variant B". */
[data-team-profile]{ cursor:pointer; }
.crest-box[data-team-profile]:hover{ box-shadow:0 0 0 2px var(--flag-dim); }
[data-team-profile]:focus-visible{ outline:2px solid var(--flag); outline-offset:2px; }
body.tp-open{ overflow:hidden; }
.tp-overlay{ position:fixed; inset:0; z-index:1000; display:flex; justify-content:center; align-items:flex-start; padding:24px 12px; }
.tp-backdrop{ position:absolute; inset:0; background:rgba(8,10,14,0.72); }
.tp-sheet{
  position:relative; width:min(760px,100%); max-height:calc(100vh - 48px); overflow-y:auto; overscroll-behavior:contain;
  background:var(--bg); border:1px solid var(--line); border-radius:12px; box-shadow:0 24px 70px rgba(0,0,0,0.55);
  padding:18px 18px 4px;
}
.tp-top{ display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:12px; }
.tp-top .eyebrow{ margin-bottom:0; }
/* Close: Collaboranker blue (button.primary's --flag/--flag-hover), white glyph */
.tp-close{
  width:30px; height:30px; flex-shrink:0; border-radius:7px; border:none; background:var(--flag); color:#ffffff;
  cursor:pointer; display:flex; align-items:center; justify-content:center; transition:background 0.15s;
}
.tp-close:hover{ background:var(--flag-hover); }
.tp-close:focus-visible{ outline:2px solid var(--flag); outline-offset:2px; }
.tp-close svg{ width:12px; height:12px; }

/* hero = an enlarged .crest-box */
.tp-hero{ display:flex; align-items:stretch; gap:12px; margin-bottom:18px; }
.tp-hero .crest-box{ min-height:84px; padding:12px 18px; gap:16px; border-radius:10px; }
.tp-hero .crest-logo-wrap{ width:88px; height:56px; }
.tp-name-wrap{ flex:1; min-width:0; }
.tp-hero .crest-name{ display:block; font-size:26px; letter-spacing:0.01em; line-height:1.1; }
.tp-hero-sub{ margin-top:6px; display:flex; gap:8px; flex-wrap:wrap; }
.tp-hero .crest-stat{ font-size:12px; padding:4px 8px; }
.tp-sport{ justify-content:center; padding:10px 12px; }

.tp-card{ margin-bottom:16px; }
.tp-card .card-title-row .status-pill{ margin-left:auto; }
.tp-hint-tight{ margin-bottom:0; }

/* This week: tiles in the .sport-card box style */
.tp-stats{ display:grid; grid-template-columns:repeat(4,1fr); gap:8px; margin-bottom:14px; }
.tp-stat{ border:1px solid var(--line); border-radius:9px; background:var(--bg); padding:12px 12px 10px; }
.tp-stat .v{ font-family:'IBM Plex Mono',monospace; font-weight:600; font-size:22px; color:#f5f5f5; display:flex; align-items:center; gap:6px; }
.tp-stat .v .nr{ color:var(--ink-dim); }
.tp-stat .v .tp-of{ font-size:13px; color:var(--ink-dim); font-weight:500; }
.tp-stat .k{ font-family:'Oswald',sans-serif; font-weight:600; font-size:12px; text-transform:uppercase; letter-spacing:0.03em; color:var(--ink-dim); margin-top:4px; }

/* Top-N spread: #1-#N track + a separate NR bin */
.tp-spread-row{ display:flex; align-items:center; gap:4px; }
.tp-spread-row .spread-track{ flex:1; }
.tp-spread-nr{ width:18%; max-width:34px; height:5px; border-radius:3px; box-shadow:inset 0 0 0 1px var(--line); }
.tp-spread-nr.on{ background:var(--turf-dim); box-shadow:none; }
.tp-nr-cap{ color:#c98b92; }

/* Week by week */
.tp-weeks{ border:1px solid var(--line); border-radius:10px; overflow:hidden; }
.tp-wk{
  display:grid; grid-template-columns:70px 200px 90px 1fr 90px; align-items:center; gap:12px;
  padding:12px 14px; border-bottom:1px solid var(--line); background:var(--bg-raised);
}
.tp-wk:last-child{ border-bottom:none; }
.tp-wk.head{ background:var(--bg); padding-top:9px; padding-bottom:9px; }
.tp-wk.head span{ font-family:'IBM Plex Mono',monospace; font-size:10.5px; letter-spacing:0.1em; text-transform:uppercase; color:var(--ink-dim); }
.tp-wk .wk{ font-family:'IBM Plex Mono',monospace; font-size:12px; color:var(--ink-dim); line-height:1.3; }
.tp-wk .wk b{ display:block; font-family:'Oswald',sans-serif; font-weight:600; font-size:15px; color:var(--ink); text-transform:uppercase; }
.tp-wk .wk .tp-wk-label{ font-size:13px; }
.tp-wk .tp-wk-pill{ margin-top:4px; padding:2px 6px; font-size:9px; gap:4px; }
.tp-wk .tp-wk-pill svg{ width:9px; height:9px; }
.tp-wk .game{ display:flex; align-items:center; gap:8px; font-family:'IBM Plex Mono',monospace; font-size:12px; min-width:0; }
.tp-wk .game .at{ color:var(--ink-dim); width:12px; text-align:right; flex-shrink:0; }
/* Opponent chips: one fixed width with the abbreviation centered
   (2026-09-29). .ind-chip's min-width left 2-letter codes (NE, SF, LV)
   hugging the chip's left edge while 3-letter ones filled it; 44px also
   fits CFB's 4-letter codes, so every row's result and score line up. */
.tp-wk .game .ind-chip{ width:44px; min-width:0; box-sizing:border-box; padding-left:0; padding-right:0; text-align:center; flex-shrink:0; }
.tp-wk .game .tp-score, .tp-wk .game .tp-kick{ white-space:nowrap; }
.tp-wk .game .tp-kick{ color:var(--ink-dim); }
.tp-wk .game.tp-bye{ font-family:'Oswald',sans-serif; letter-spacing:0.06em; color:var(--ink-dim); }
.tp-wk .rank{ display:flex; align-items:center; gap:6px; }
.tp-wk .rank .n{ font-family:'IBM Plex Mono',monospace; font-weight:600; font-size:18px; color:#f5f5f5; min-width:34px; text-align:right; }
.tp-wk .rank .n.nr{ color:var(--ink-dim); font-size:15px; letter-spacing:0.04em; }
.tp-wk .rank .n.dash{ color:var(--ink-dim); opacity:0.5; }
.tp-wk .rank .who{ display:none; }
.tp-wk .spread{ min-width:0; }
.tp-wk .spread .spread-caption{ margin-top:6px; font-size:10.5px; }
.tp-foot{ display:flex; justify-content:space-between; gap:12px; flex-wrap:wrap; margin-top:12px; }

/* Rank trend */
.tp-legend{ display:flex; gap:16px; font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--ink-dim); margin-bottom:6px; }
.tp-sw{ display:inline-block; width:14px; height:2px; border-radius:2px; vertical-align:middle; margin-right:6px; }
.tp-sw-dot{ display:inline-block; width:8px; height:8px; border-radius:2px; margin-right:6px; }
.tp-sw-overall{ background:#5B87C9; }
.tp-sw-you{ background:#B8822E; }
.tp-chart{ position:relative; }
.tp-chart svg{ display:block; width:100%; height:auto; overflow:visible; }
.tp-chart-empty{ padding:18px 0; }
.tp-tip{
  position:absolute; pointer-events:none; background:var(--bg); border:1px solid var(--line); border-radius:7px;
  padding:7px 9px; font-family:'IBM Plex Mono',monospace; font-size:11px; line-height:1.6; white-space:nowrap;
  opacity:0; transition:opacity 0.12s; transform:translate(-50%,-112%);
}
.tp-tip.on{ opacity:1; }

/* This week's ballots */
.tp-ballots .member-row{ gap:10px; }
.tp-ballots .pos{ font-family:'IBM Plex Mono',monospace; font-weight:600; font-size:15px; width:34px; text-align:right; color:#f5f5f5; flex-shrink:0; }
.tp-ballots .pos.dim{ color:var(--ink-dim); font-size:13px; }
.tp-ballots .nm{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.tp-ballots .tp-pending{ color:var(--ink-dim); }
.tp-ballots .tp-pending .pos{ color:var(--ink-dim); }
.tp-tag-bull{ color:#8fe3a6; border-color:rgba(143,227,166,0.35); }
.tp-tag-bear{ color:#ff9b93; border-color:rgba(255,155,147,0.35); }
.tp-tag-dim{ color:var(--ink-dim); border-color:var(--line); }

@media (prefers-reduced-motion: reduce){
  .tp-close, .tp-tip{ transition:none; }
}

/* Phones: full-screen sheet, rows stack into three lines */
@media (max-width:700px){
  .tp-overlay{ padding:0; }
  .tp-backdrop{ display:none; }
  .tp-sheet{ width:100%; max-height:100vh; height:100%; border-radius:0; border:none; box-shadow:none; padding:14px 12px 2px; }
  .tp-sport{ display:none; }
  .tp-hero .crest-box{ min-height:72px; padding:10px 14px; gap:12px; }
  .tp-hero .crest-logo-wrap{ width:62px; height:40px; }
  .tp-hero .crest-name{ font-size:20px; white-space:normal; }
  .tp-stats{ grid-template-columns:repeat(2,1fr); }
  .tp-card{ padding:16px; }
  .spread-caption.tp-tw-cap{ display:grid; grid-template-columns:1fr auto; row-gap:4px; }
  .spread-caption.tp-tw-cap > span:nth-child(2){ grid-row:2; grid-column:1 / -1; }
  .spread-caption.tp-tw-cap > span:nth-child(3){ grid-row:1; grid-column:2; text-align:right; }
  .tp-wk{
    grid-template-columns:40px 1fr 1fr; grid-template-areas:"wk game game" "wk ov you" "wk spread spread";
    row-gap:8px; column-gap:10px; padding:11px 12px;
  }
  .tp-wk.head{ display:none; }
  .tp-wk .wk{ grid-area:wk; align-self:start; font-size:10px; }
  .tp-wk .wk .tp-full{ display:none; }
  .tp-wk .wk .tp-wk-label{ font-size:11px; }
  .tp-wk .wk .status-pill.locked .tp-wk-pill-text{ display:none; }
  .tp-wk .wk .status-pill.locked{ padding:3px 5px; }
  .tp-wk .game{ grid-area:game; }
  .tp-wk .ov{ grid-area:ov; }
  .tp-wk .you{ grid-area:you; }
  .tp-wk .spread{ grid-area:spread; }
  .tp-wk .rank .n{ font-size:15px; min-width:28px; text-align:left; }
  .tp-wk .rank .who{ display:inline; font-family:'IBM Plex Mono',monospace; font-size:9.5px; color:var(--ink-dim); letter-spacing:0.05em; width:28px; }
  .tp-wk.future, .tp-wk.bye{ grid-template-areas:"wk game game"; }
  .tp-wk.future .spread, .tp-wk.future .rank, .tp-wk.bye .spread, .tp-wk.bye .rank{ display:none; }
}

/* Rank trend "Compare" chips (2026-09-30): toggle up to two people's own
   boards onto the chart. Slot colors match the chart lines (amber, teal). */
.tp-compare{ display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin:2px 0 10px; }
.tp-compare-label{ font-family:'IBM Plex Mono',monospace; font-size:10.5px; letter-spacing:0.1em; text-transform:uppercase; color:var(--ink-dim); margin-right:4px; }
.tp-chip{
  display:inline-flex; align-items:center; gap:6px; border:1px solid var(--line); background:var(--bg); color:var(--ink-dim);
  border-radius:999px; padding:5px 11px; font-family:'Inter',sans-serif; font-size:12.5px; cursor:pointer;
  transition:color 0.15s, border-color 0.15s;
}
.tp-chip:hover:not(:disabled){ color:var(--ink); border-color:var(--flag-dim); }
.tp-chip.on{ color:var(--ink); border-color:var(--flag); background:rgba(91,135,201,0.12); }
.tp-chip:disabled{ opacity:0.45; cursor:not-allowed; }
.tp-chip:focus-visible{ outline:2px solid var(--flag); outline-offset:2px; }
.tp-chip .tp-sw-dot{ margin-right:0; }
.tp-sw-slot0{ background:#B8822E; }
.tp-sw-slot1{ background:#199e70; }
.tp-legend{ flex-wrap:wrap; }
@media (prefers-reduced-motion: reduce){ .tp-chip{ transition:none; } }

/* NHL/NBA weeks with several games (2026-10-01): compact items that wrap */
.tp-wk .game.tp-multi{ flex-wrap:wrap; gap:6px 10px; }
.tp-wk .game .tp-g{ display:inline-flex; align-items:center; gap:4px; white-space:nowrap; }
.tp-wk .game .tp-g .at{ width:auto; min-width:0; }
.tp-wk .game.tp-multi .ind-chip{ width:38px; }
