/* src/public/css/league_public.css
 *
 * The public league page's stylesheet — /leagues/<slug>, rendered by
 * src/dashboard/templates/public/league_view_public.pug.
 *
 * ── WHY THIS IS A FILE AND NOT A <style> BLOCK (2026-09-17) ───────────────
 * It used to be a <style> block, inline in the template, 43,703 bytes of it.
 * Measured against production: the page answered in 48 ms warm and 137 ms
 * cold and shipped 149,403 bytes of HTML, of which this was 43,703 —
 * render-blocking, byte-for-byte identical on every league page, and re-sent
 * and re-parsed every time a reader opened another league.
 *
 * The operator, on a phone: "It also feels really slow opening the page up
 * too when clicking on it." He was right and it was never the server.
 *
 * As a file it is served `public, max-age=31536000, immutable`, so the second
 * league page a reader opens costs nothing at all for it.
 *
 * ⚠️ CACHE BUSTING IS AUTOMATIC AND MUST STAY THAT WAY. The template links
 * this as `/css/league_public.css?v=${__cssVer}`, and __cssVer is a content
 * hash that INCLUDES this file (computeAssetVersion, src/dashboard/safe_pug.ts).
 * Edit this file and the URL rolls by itself. Never hand-maintain a version
 * in the template: a year-long immutable cache behind a token that does not
 * move is a CSS fix that ships and changes nothing, and this repo has done
 * exactly that four separate times.
 */

:root {
  --lp-bg-card:   #11141b;
  --lp-bg-card-2: #15191f;
  --lp-line:      rgba(244,241,234,0.10);
  --lp-line-2:    rgba(244,241,234,0.20);
  --lp-text:      #f4f1ea;
  --lp-text-mute: rgba(244,241,234,0.62);
  --lp-text-dim:  rgba(244,241,234,0.38);
  --lp-red:       #38e939;
  --lp-gold:      #8ff593;
  --lp-green:     #4cd5a3;
  --lp-blue:      #79c4ff;
  --safe-bottom:  env(safe-area-inset-bottom, 0px);

  /* ── 10-band rating color tokens (2026-05-13) ──
     Mirrors player_view.pug / compare_players.pug so any rating
     surfaced on this page reads the same color scale as the
     player + compare hubs (green = good, red = bad). Defined
     here for any future rating-band consumer on the public
     league page. */
  --rating-99:       #fdb913;
  --rating-elite:    #0d6e3f;
  --rating-great:    #1a8e4a;
  --rating-good:     #2ed573;
  --rating-fair:     #9ad12e;
  --rating-avg:      #e8c628;
  --rating-below:    #e89328;
  --rating-poor:     #dc5a35;
  --rating-bad:      #c92e2e;
  --rating-terrible: #7a1d1d;
}
.rating-band-99       { background: var(--rating-99)       !important; color: #1a1207 !important; }
.rating-band-elite    { background: var(--rating-elite)    !important; color: #fff !important; }
.rating-band-great    { background: var(--rating-great)    !important; color: #fff !important; }
.rating-band-good     { background: var(--rating-good)     !important; color: #0a1a10 !important; }
.rating-band-fair     { background: var(--rating-fair)     !important; color: #0a1a10 !important; }
.rating-band-avg      { background: var(--rating-avg)      !important; color: #1a1207 !important; }
.rating-band-below    { background: var(--rating-below)    !important; color: #fff !important; }
.rating-band-poor     { background: var(--rating-poor)     !important; color: #fff !important; }
.rating-band-bad      { background: var(--rating-bad)      !important; color: #fff !important; }
.rating-band-terrible { background: var(--rating-terrible) !important; color: #fff !important; }
.rating-text-99       { color: var(--rating-99)       !important; }
.rating-text-elite    { color: var(--rating-good)     !important; }
.rating-text-great    { color: var(--rating-great)    !important; }
.rating-text-good     { color: var(--rating-good)     !important; }
.rating-text-fair     { color: var(--rating-fair)     !important; }
.rating-text-avg      { color: var(--rating-avg)      !important; }
.rating-text-below    { color: var(--rating-below)    !important; }
.rating-text-poor     { color: var(--rating-poor)     !important; }
.rating-text-bad      { color: var(--rating-bad)      !important; }
.rating-text-terrible { color: var(--rating-terrible) !important; }

.lp-shell {
  /* Page rail clamped to the same --w-page (1180px) as compare /
     player / team / leaders so the public league view sits in the
     same vertical band as its siblings instead of sprawling 60px
     wider on widescreen. Falls back to 1180px when the marketing
     layout token isn't defined. */
  max-width: var(--w-page, 1180px);
  margin: 0 auto;
  padding: 2rem 1.25rem calc(70px + var(--safe-bottom));
}

/* ═══════ HEADER (rework 2026-05-13) ═══════
   Was a single "All leagues" pill above the hero; now matches
   /compare + /player + /team breadcrumb pattern so the page
   reads as part of the same layout system. Chain is
   Leagues ▸ <league.displayName>. */
.header {
  position: relative;
  max-width: var(--w-page, 1180px);
  margin: 0 auto 1.25rem;
  padding: 0;
}
.header-inner {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}
.breadcrumb {
  display: inline-flex; align-items: center; flex-wrap: wrap;
  gap: 0.5rem;
  min-width: 0;
  font-family: var(--font-mono); font-size: 0.88rem;
  letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--lp-text-mute);
}
.breadcrumb a {
  color: var(--lp-text-mute); text-decoration: none;
  transition: color 140ms ease;
  display: inline-flex; align-items: center; gap: 0.35rem;
  min-height: 44px;
  padding: 0.18rem 0.1rem;
}
.breadcrumb a:hover { color: var(--lp-text); }
.breadcrumb-sep { opacity: 0.45; }
.breadcrumb-current {
  color: var(--lp-text);
  padding: 0.28rem 0.55rem;
  background: rgba(244,241,234,0.06);
  border: 1px solid rgba(244,241,234,0.1);
  border-radius: 4px;
  font-weight: 700;
  white-space: normal;
  word-break: break-word;
}
/* Narrow phones: tighten the breadcrumb spacing only; the name
   itself now wraps instead of clipping, so no max-width here. */
@media (max-width: 380px) {
  .breadcrumb { font-size: 0.81rem; gap: 0.35rem; }
}

/* Legacy .lp-crumb retained for backwards compatibility (any
   deep-link surfacing this style should still render fine).
   Not used in the new header. */
.lp-crumb {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.88rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--lp-text-mute);
  text-decoration: none;
  margin-bottom: 1.25rem;
  padding: 0.4rem 0.7rem;
  min-height: 40px;
  border-radius: 6px;
  border: 1px solid var(--lp-line);
  background: rgba(244,241,234,0.02);
}
.lp-crumb:hover { color: var(--lp-text); border-color: var(--lp-line-2); }

/* ═══════ HERO ═══════
   Big bold league identity card. Diagonal accent + tier glow when
   paid. Background fades to transparent at the edges so it bleeds
   into the body bg instead of looking like a walled-off rectangle
   on widescreen desktops. */
.lp-hero {
  position: relative;
  overflow: hidden;
  border: 0;
  border-radius: 18px;
  padding: 2.25rem 2rem 2rem;
  background:
    radial-gradient(ellipse 80% 100% at 50% 50%,
      rgba(21,25,31,0.92) 0%,
      rgba(21,25,31,0.7) 55%,
      rgba(21,25,31,0) 100%),
    radial-gradient(circle at 0% 0%, rgba(56,233,57,0.10), transparent 55%),
    radial-gradient(circle at 100% 100%, rgba(143,245,147,0.06), transparent 60%);
  margin-bottom: 2rem;
}
.lp-hero::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 4px;
  background: linear-gradient(90deg, var(--lp-red), var(--lp-gold), var(--lp-red));
  background-size: 200% 100%;
  animation: lp-shimmer 3.4s linear infinite;
}
@keyframes lp-shimmer {
  0%   { background-position: 0% 50%; }
  100% { background-position: 200% 50%; }
}
.lp-hero.is-gold::before   { background: linear-gradient(90deg, #fdb913, #fff2c2, #fdb913, #fff8d4, #fdb913); background-size: 200% 100%; }
.lp-hero.is-silver::before { background: linear-gradient(90deg, #9aa1ad, #ffffff, #c0c5cd, #f1f3f7, #9aa1ad); background-size: 200% 100%; }
.lp-hero.is-bronze::before { background: linear-gradient(90deg, #8a5224, #b87333, #f1c89a, #b87333, #8a5224); background-size: 200% 100%; }

.lp-hero-pills { display: flex; flex-wrap: wrap; gap: 0.45rem; margin-bottom: 0.85rem; }
.lp-pill {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 0.32rem 0.6rem;
  border-radius: 4px;
  color: var(--lp-text-mute);
  background: rgba(244,241,234,0.05);
  border: 1px solid var(--lp-line-2);
  white-space: nowrap;
}
.lp-pill.is-recruiting { color: var(--lp-green); background: rgba(76,213,163,0.12); border-color: rgba(76,213,163,0.42); }
.lp-pill.is-full       { color: var(--lp-text-mute); }
.lp-pill.is-paid       { color: #fdb913; background: rgba(253,185,19,0.14); border-color: rgba(253,185,19,0.42); }
.lp-pill.is-free       { color: var(--lp-green); background: rgba(76,213,163,0.12); border-color: rgba(76,213,163,0.42); }
.lp-pill.tier-gold     { color: #fdb913; background: rgba(253,185,19,0.16); border-color: rgba(253,185,19,0.5); }
.lp-pill.tier-silver   { color: #d8dbe2; background: rgba(192,197,205,0.12); border-color: rgba(192,197,205,0.45); }
.lp-pill.tier-bronze   { color: #d99063; background: rgba(184,115,51,0.16); border-color: rgba(184,115,51,0.45); }

.lp-hero-name {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2rem, 5vw, 3.6rem);
  letter-spacing: -0.01em;
  line-height: 0.95;
  margin: 0 0 0.65rem;
  color: var(--lp-text);
  text-transform: uppercase;
}
.lp-hero-headline {
  color: var(--lp-text-mute);
  font-size: clamp(1rem, 1.4vw, 1.15rem);
  line-height: 1.55;
  margin: 0 0 1.4rem;
  max-width: 65ch;
}

.lp-hero-stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.85rem;
  max-width: 720px;
}
@media (min-width: 768px) { .lp-hero-stats { grid-template-columns: repeat(4, 1fr); } }
.lp-hero-stat {
  padding: 0.7rem 0.85rem;
  background: rgba(0,0,0,0.28);
  border: 1px solid var(--lp-line);
  border-radius: 10px;
}
.lp-hero-stat-label {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--lp-text-dim);
  margin-bottom: 0.3rem;
}
.lp-hero-stat-value {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.4rem;
  color: var(--lp-text);
  letter-spacing: -0.01em;
}
.lp-hero-stat-sub {
  font-family: var(--font-mono);
  font-size: 0.88rem;
  color: var(--lp-text-mute);
  margin-top: 0.15rem;
}

/* ═══════ MAIN GRID ═══════ */
.lp-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
}
@media (min-width: 992px) {
  .lp-grid { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 1.75rem; }
}
.lp-main { display: flex; flex-direction: column; gap: 1.25rem; min-width: 0; }
.lp-aside { display: flex; flex-direction: column; gap: 1.25rem; min-width: 0; }
.lp-aside-sticky {
  position: sticky;
  top: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

/* ═══════ CARDS ═══════
   Cards used to sit on the body as solid lighter rectangles with
   hard borders — on widescreen desktops you could see the "walls"
   where the panel ended and the body bg returned. The new
   treatment uses a radial fade that's opaque in the center and
   transparent at the edges, so the panel feels like a soft halo
   on top of the page rather than a cut-out rectangle. */
.lp-card {
  position: relative;
  background:
    radial-gradient(ellipse 95% 110% at 50% 50%,
      rgba(21,25,31,0.85) 0%,
      rgba(21,25,31,0.55) 70%,
      rgba(21,25,31,0) 100%);
  border: 0;
  border-radius: 14px;
  overflow: hidden;
}
.lp-card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(244,241,234,0.06),
    rgba(244,241,234,0) 35%,
    rgba(244,241,234,0) 70%,
    rgba(244,241,234,0.04));
  mix-blend-mode: overlay;
  opacity: 0.7;
}
.lp-card-head {
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--lp-line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}
.lp-card-title {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 0.92rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--lp-text);
}
.lp-card-title i { color: var(--lp-gold); font-size: 1.05rem; }
.lp-card-body {
  padding: 1.1rem 1.25rem 1.25rem;
}
.lp-card-body.no-pad { padding: 0; }

/* Prose cards (about / rules / how to join) */
.lp-prose {
  color: var(--lp-text);
  font-size: 0.97rem;
  line-height: 1.65;
  white-space: pre-wrap;
  /* 2026-09-18: pre-wrap keeps the league's own line breaks but says
     nothing about a single word wider than the card — a pasted Discord
     invite or a run-on tag ran straight out the right edge of the page on
     a phone. `anywhere` breaks only when there is no other option, so
     ordinary sentences still break at spaces. `break-all` was rejected:
     it breaks mid-word even when a space was available, which is what
     turned an export URL into "anchi / sehu" on the exports table. */
  overflow-wrap: anywhere;
  min-width: 0;
}

/* ═══════ JOIN CARD (sticky sidebar) ═══════ */
.lp-join {
  background:
    radial-gradient(circle at 50% 0%, rgba(76,213,163,0.14), transparent 60%),
    var(--lp-bg-card);
  border: 1px solid rgba(76,213,163,0.35);
  border-radius: 14px;
  padding: 1.5rem;
  text-align: center;
}
.lp-join h3 {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 1.25rem;
  letter-spacing: 0.04em;
  color: var(--lp-green);
  text-transform: uppercase;
  margin: 0 0 0.4rem;
}
.lp-join-spots {
  font-family: var(--font-mono);
  color: var(--lp-text-mute);
  font-size: 0.8rem;
  margin-bottom: 1rem;
}
.lp-join-cta {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.lp-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  min-height: 44px;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-radius: 8px;
  text-decoration: none;
  transition: transform 0.15s ease, opacity 0.15s ease;
  font-weight: 600;
}
.lp-btn:hover { transform: translateY(-1px); opacity: 0.92; }
.lp-btn.primary { background: var(--lp-green); color: #0a1414; }
.lp-btn.discord { background: #5865f2; color: #fff; }
.lp-btn.ghost   { background: rgba(244,241,234,0.05); color: var(--lp-text); border: 1px solid var(--lp-line-2); }

/* ═══════ INFO STATS (sidebar) ═══════ */
.lp-info-stat {
  display: flex;
  justify-content: space-between;
  padding: 0.55rem 0;
  border-bottom: 1px dashed var(--lp-line);
  font-size: 0.92rem;
}
.lp-info-stat:last-child { border-bottom: 0; }
.lp-info-stat .label { color: var(--lp-text-mute); font-size: 0.78rem; font-family: var(--font-mono); letter-spacing: 0.05em; text-transform: uppercase; }
.lp-info-stat .value { color: var(--lp-text); font-weight: 700; font-family: var(--font-mono); font-size: 0.85rem; text-align: right; }

/* ═══════ DIVISION LEADERS ═══════ */
.lp-divleader-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 0.5rem;
}
.lp-divleader {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.55rem 0.7rem;
  background: rgba(244,241,234,0.025);
  border: 1px solid var(--lp-line);
  border-radius: 8px;
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s, background 0.15s;
}
.lp-divleader:hover { border-color: var(--lp-line-2); background: rgba(244,241,234,0.04); }
.lp-divleader-logo {
  width: 36px;
  height: 36px;
  object-fit: contain;
  flex-shrink: 0;
}
.lp-divleader-meta { min-width: 0; }
.lp-divleader-div {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--lp-gold);
}
.lp-divleader-team {
  font-weight: 700;
  color: var(--lp-text);
  font-size: 0.85rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lp-divleader-rec {
  font-family: var(--font-mono);
  font-size: 0.88rem;
  color: var(--lp-text-mute);
}

/* ═══════ RECENT RESULTS ═══════ */
a.lp-results-week.is-link {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  text-decoration: none;
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease;
  padding: 0.18rem 0.4rem;
  border-radius: 4px;
}
a.lp-results-week.is-link:hover {
  color: var(--lp-text);
  background: rgba(244,241,234,0.04);
}
.lp-results-week-arrow { font-size: 0.76rem; opacity: 0.5; }
a.lp-results-week.is-link:hover .lp-results-week-arrow { opacity: 1; }
.lp-results-row {
  position: relative;
  display: grid;
  grid-template-columns: 56px 1fr auto 32px auto 1fr 24px;
  gap: 0.5rem;
  align-items: center;
  padding: 0.7rem 0.8rem;
  border-bottom: 1px solid var(--lp-line);
  transition: background 140ms ease;
}
.lp-results-row.has-link { cursor: pointer; }
.lp-results-row.has-link:hover { background: rgba(244,241,234,0.04); }
.lp-results-row:last-child { border-bottom: 0; }
/* Whole-row click target — sits behind the team anchors via z-index
   so a click on a team logo/name still goes to the team page, but
   a click anywhere else on the row opens the box score. */
.lp-results-overlay {
  position: absolute; inset: 0;
  z-index: 1;
  border-radius: 6px;
}
.lp-results-row > .lp-results-week,
.lp-results-row > .lp-results-side,
.lp-results-row > .lp-results-score,
.lp-results-row > .lp-results-at,
.lp-results-row > .lp-results-chev { position: relative; z-index: 2; }
/* Trailing chevron — telegraphs the whole row is clickable. */
.lp-results-chev {
  display: flex; align-items: center; justify-content: center;
  color: var(--lp-text-dim);
  font-size: 0.85rem;
  transition: color 140ms ease, transform 140ms ease;
  pointer-events: none;
}
.lp-results-row.has-link:hover .lp-results-chev { color: var(--lp-gold); transform: translateX(2px); }
.lp-results-week {
  font-family: var(--font-mono);
  font-size: 0.81rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--lp-gold);
}
.lp-results-side {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
  color: var(--lp-text-mute);
  text-decoration: none;
  transition: color 0.15s ease, transform 0.15s ease;
}
a.lp-results-side { cursor: pointer; }
a.lp-results-side:hover { color: var(--lp-gold); transform: translateX(2px); }
a.lp-results-side.lp-results-side-r:hover { transform: translateX(-2px); }
.lp-results-side.is-winner { color: var(--lp-text); }
.lp-results-side-r { justify-content: flex-end; text-align: right; }
.lp-results-logo { width: 24px; height: 24px; object-fit: contain; flex-shrink: 0; }
.lp-results-name {
  font-weight: 700;
  font-size: 0.85rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lp-results-score {
  font-family: var(--font-mono);
  font-weight: 800;
  font-size: 1rem;
  color: var(--lp-text-mute);
  font-variant-numeric: tabular-nums;
}
.lp-results-score.is-winner { color: var(--lp-green); }
.lp-results-at { font-family: var(--font-mono); color: var(--lp-text-dim); font-size: 0.86rem; text-align: center; }

/* ═══════ GOTW ═══════ */
.lp-gotw {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 1rem;
  align-items: center;
  padding: 1.25rem 0.85rem 0.75rem;
}
.lp-gotw-side { text-align: center; display: block; text-decoration: none; color: inherit; transition: transform 0.18s ease; }
a.lp-gotw-side { cursor: pointer; }
a.lp-gotw-side:hover { transform: translateY(-2px); }
a.lp-gotw-side:hover .lp-gotw-name { color: var(--lp-gold); }
.lp-gotw-logo { width: 64px; height: 64px; object-fit: contain; margin: 0 auto 0.5rem; }
.lp-gotw-name { font-family: var(--font-display); font-weight: 800; font-size: 1.05rem; color: var(--lp-text); }
.lp-gotw-votes { font-family: var(--font-mono); font-size: 0.88rem; color: var(--lp-text-mute); }
.lp-gotw-vs { font-family: var(--font-display); font-size: 1rem; font-weight: 800; letter-spacing: 0.18em; color: var(--lp-text-dim); }

/* ═══════ STANDINGS ═══════ */
.lp-stand-grid { display: grid; grid-template-columns: 1fr; gap: 1.25rem; }
@media (min-width: 768px) { .lp-stand-grid { grid-template-columns: 1fr 1fr; } }
.lp-stand-div {
  background: rgba(244,241,234,0.02);
  border: 1px solid var(--lp-line);
  border-radius: 10px;
  padding: 0.75rem 0.85rem;
  /* Mobile guard: the 7-column standings table (Team / Owner / W L T
     PF PA) can exceed the card width on narrow phones. Scroll the
     table inside its own card instead of overflowing the page. */
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.lp-stand-div-name {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--lp-gold);
  margin-bottom: 0.45rem;
}
/* 2026-07-22 fix: table had no table-layout, so the 7 columns
   (Team/Owner/W/L/T/PF/PA) auto-sized off content width. The Team
   column's abbr+city spans had no white-space/overflow control, so
   a long city name (e.g. "Pittsburgh") could render right up against
   — or past — the Owner column with no guaranteed gap, reading as
   the team name "running into" the owner name on narrow phones.
   table-layout:fixed + explicit per-column widths give every column
   a guaranteed share; the Team name itself now truncates with an
   ellipsis instead of colliding with its neighbor. */
.lp-stand-table { width: 100%; border-collapse: collapse; font-family: var(--font-mono); font-size: 0.78rem; table-layout: fixed; }
.lp-stand-table th:nth-child(1), .lp-stand-table td:nth-child(1) { width: 30%; }
.lp-stand-table th:nth-child(2), .lp-stand-table td:nth-child(2) { width: 26%; }
.lp-stand-table th:nth-child(3), .lp-stand-table td:nth-child(3),
.lp-stand-table th:nth-child(4), .lp-stand-table td:nth-child(4) { width: 8%; }
.lp-stand-table th:nth-child(5), .lp-stand-table td:nth-child(5) { width: 7%; }
.lp-stand-table th:nth-child(6), .lp-stand-table td:nth-child(6),
.lp-stand-table th:nth-child(7), .lp-stand-table td:nth-child(7) { width: 10.5%; }
.lp-stand-table th { color: var(--lp-text-dim); font-size: 0.76rem; letter-spacing: 0.12em; text-transform: uppercase; padding: 0.25rem 0.3rem; text-align: right; font-weight: 600; }
.lp-stand-table th:first-child { text-align: left; }
.lp-stand-table td {
  padding: 0.35rem 0.3rem;
  color: var(--lp-text);
  font-variant-numeric: tabular-nums;
  text-align: right;
  border-bottom: 1px solid rgba(244,241,234,0.04);
  overflow: hidden;
}
.lp-stand-table td:first-child { text-align: left; }
.lp-stand-table tbody tr:last-child td { border-bottom: 0; }
.lp-stand-logo { width: 18px; height: 18px; object-fit: contain; vertical-align: middle; margin-right: 0.35rem; flex-shrink: 0; }
.lp-stand-abbr { font-weight: 700; flex-shrink: 0; }
.lp-stand-sub {
  color: var(--lp-text-dim);
  font-size: 0.86rem;
  margin-left: 0.25rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
/* Owner column — surfaces the EA username for each franchise so
   visitors know who's running the team. Open teams (no userName
   or "CPU") get a recruiting-green chip so they pop visually.
   Column width now comes from the table-layout:fixed rule above —
   the old fixed `max-width:130px` here fought that on wide screens
   and did nothing to prevent the Team column overlap on narrow
   ones; the chip itself still ellipsizes via its own max-width:100%. */
.lp-stand-owner { text-align: left !important; overflow: hidden; }
.lp-owner-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-family: var(--font-mono);
  font-size: 0.82rem;
  letter-spacing: 0.04em;
  padding: 0.18rem 0.45rem;
  border-radius: 4px;
  color: var(--lp-text-mute);
  background: rgba(244,241,234,0.04);
  border: 1px solid var(--lp-line);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.lp-owner-chip.is-open {
  color: var(--lp-green);
  background: rgba(76,213,163,0.10);
  border-color: rgba(76,213,163,0.4);
  font-weight: 700;
  letter-spacing: 0.10em;
}
.lp-stand-table tbody tr.is-open td {
  background: linear-gradient(90deg, rgba(76,213,163,0.06), transparent 70%);
}

/* Open Teams panel — quick scan of available franchises. Single
   column on phones, 2-up on tablet, 3-up on desktop. Each card
   is a single click to the team detail. */
.lp-open-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.5rem;
}
@media (min-width: 640px) { .lp-open-grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1000px) { .lp-open-grid { grid-template-columns: 1fr 1fr 1fr; } }
.lp-open-card {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.65rem 0.8rem;
  border-radius: 10px;
  background:
    radial-gradient(ellipse 110% 130% at 50% 50%,
      rgba(76,213,163,0.10) 0%,
      rgba(76,213,163,0.04) 60%,
      rgba(76,213,163,0) 100%);
  border: 1px solid rgba(76,213,163,0.30);
  text-decoration: none;
  color: inherit;
  transition: transform 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.lp-open-card:hover {
  transform: translateY(-1px);
  border-color: rgba(76,213,163,0.6);
}
.lp-open-logo { width: 36px; height: 36px; object-fit: contain; flex-shrink: 0; }
.lp-open-info { min-width: 0; flex: 1; }
.lp-open-name {
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--lp-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lp-open-meta {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.82rem;
  letter-spacing: 0.06em;
  color: var(--lp-text-mute);
  margin-top: 0.15rem;
}
.lp-open-sep { color: var(--lp-text-dim); }
.lp-open-tag {
  color: var(--lp-green);
  font-weight: 700;
  letter-spacing: 0.12em;
}
.lp-open-howto {
  margin-top: 1rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--lp-line);
  font-size: 0.85rem;
  color: var(--lp-text-mute);
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

/* ═══════ NEWSWIRE ═══════ */
/* 2026-08-13: the same tweet card the in-app Newswire renders, which is
   the same card src/renderers/twitterCardV2.ts posts into Discord —
   avatar, name, verified seal, @handle, timestamp, body, activity row.
   The post surface is LIGHTER than the panel it sits on: the panel paints
   about rgb(19,23,28) (its radial gradient over the page), the post about
   rgb(30,34,38). A box darker than its host reads as a hole. */
.lp-news { display: flex; flex-direction: column; gap: 0.6rem; padding: 0.8rem; }
.lp-news-row {
  display: flex;
  gap: 0.7rem;
  padding: 0.8rem 0.85rem;
  border: 1px solid var(--lp-line);
  border-radius: 14px;
  background: rgba(244, 241, 234, 0.05);
  min-width: 0;
}
.lp-news-av {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  overflow: hidden;
  display: block;
}
.lp-news-av img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Initials fallback — the renderer's own last resort. Never a broken img. */
.lp-news-av-disc {
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 0.88rem;
  letter-spacing: 0.03em;
  color: #ffffff;
}
.lp-news-main { flex: 1 1 auto; min-width: 0; }
/* The source link wraps the TEXT ONLY. The activity row below is its
   sibling, so hovering a count never lights up a clickable region — those
   numbers are decoration and nothing in the product can act on them. */
.lp-news-open { display: block; text-decoration: none; color: inherit; }
.lp-news-open:hover .lp-news-persona { color: var(--lp-gold); }
.lp-news-meta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.2rem;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  line-height: 1.3;
}
.lp-news-name-line, .lp-news-subline {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.4rem;
  align-items: center;
  min-width: 0;
}
.lp-news-persona { color: var(--lp-text); font-weight: 700; }
.lp-news-seal { flex: 0 0 auto; width: 15px; height: 15px; }
.lp-news-handle { color: var(--lp-text-mute); min-width: 0; overflow-wrap: anywhere; }
.lp-news-sep { color: var(--lp-text-mute); }
/* Was --lp-text-dim (0.38), measured 3.22:1 against the painted card —
   under the 4.5:1 floor. --lp-text-mute measures 6.3:1 here. */
.lp-news-age { color: var(--lp-text-mute); }
.lp-news-body {
  margin-top: 0.4rem;
  color: var(--lp-text);
  font-size: 0.92rem;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
/* DISPLAY ONLY, AND MUST STAY THAT WAY. card_metrics.ts opens with
   "Generate plausible fake engagement numbers" and nothing in the product
   can like or repost, so these are inert spans — never buttons, never
   links. Wraps on purpose: four groups do not fit one 390px line. */
.lp-news-acts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 0.8rem;
  margin-top: 0.55rem;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--lp-text-mute);
}
.lp-news-act { display: inline-flex; align-items: center; gap: 0.35rem; }
.lp-news-act svg { flex: 0 0 auto; width: 15px; height: 15px; fill: currentColor; stroke: none; }
.lp-news-act-rt { color: var(--lp-green); }
.lp-news-act-lk { color: #f0568c; }
.lp-news-act span { color: var(--lp-text-mute); }

/* ═══════ POWER RANKINGS ═══════ */
.lp-pwr-row {
  display: grid;
  grid-template-columns: 36px 28px 1fr auto auto;
  gap: 0.6rem;
  align-items: center;
  min-height: 44px;
  padding: 0.55rem 0.85rem;
  border-bottom: 1px solid var(--lp-line);
}
.lp-pwr-row:last-child { border-bottom: 0; }
.lp-pwr-rank { font-family: var(--font-display); font-weight: 800; color: var(--lp-text-mute); font-size: 0.95rem; }
.lp-pwr-logo { width: 24px; height: 24px; object-fit: contain; }
.lp-pwr-info { min-width: 0; }
.lp-pwr-team { font-weight: 700; color: var(--lp-text); font-size: 0.88rem; }
.lp-pwr-sub { font-family: var(--font-mono); font-size: 0.84rem; color: var(--lp-text-mute); }
.lp-pwr-change { font-family: var(--font-mono); font-size: 0.78rem; font-weight: 700; min-width: 30px; text-align: center; }
.lp-pwr-change.up   { color: var(--lp-green); }
.lp-pwr-change.down { color: #ff5c5c; } /* danger red — stays red (--lp-red is the FH green accent now) */
.lp-pwr-change.flat { color: var(--lp-text-dim); }
.lp-pwr-score { font-family: var(--font-mono); font-weight: 800; color: var(--lp-gold); font-variant-numeric: tabular-nums; }
a.lp-pwr-row { text-decoration: none; color: inherit; }
a.lp-pwr-row:hover { background: rgba(244,241,234,0.03); }
a.lp-stand-team-link {
  display: inline-flex;
  align-items: center;
  min-width: 0;
  max-width: 100%;
  text-decoration: none;
  color: inherit;
}
a.lp-stand-team-link:hover .lp-stand-abbr { color: var(--lp-gold); }

/* ═══════ PLAYOFFS ═══════ */
.lp-playoffs-shell { display: flex; flex-direction: column; gap: 1.25rem; }
.lp-sb-card {
  background: linear-gradient(135deg, rgba(212,175,55,0.10), rgba(212,175,55,0.02));
  border: 1px solid rgba(212,175,55,0.35);
  border-radius: 14px;
  padding: 1.25rem 1.25rem 1rem;
}
.lp-sb-card.is-pending {
  background: rgba(244,241,234,0.02);
  border: 1px dashed var(--lp-line);
}
.lp-sb-eyebrow {
  font-family: var(--font-mono);
  font-size: 0.86rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--lp-gold);
  margin-bottom: 0.85rem;
  font-weight: 700;
}
.lp-sb-card.is-pending .lp-sb-eyebrow { color: var(--lp-text-mute); }
.lp-sb-season { color: var(--lp-text-mute); font-weight: 600; }
.lp-sb-game {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 1rem;
  align-items: center;
  text-decoration: none;
  color: inherit;
  transition: transform 0.18s ease;
}
.lp-sb-game:hover { transform: translateY(-2px); }
.lp-sb-side {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  min-width: 0;
}
.lp-sb-side:last-child { flex-direction: row-reverse; text-align: right; }
.lp-sb-side.is-winner .lp-sb-name { color: var(--lp-gold); }
.lp-sb-side-info { flex: 1; min-width: 0; }
.lp-sb-logo { width: 54px; height: 54px; object-fit: contain; flex-shrink: 0; }
.lp-sb-seed {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.12em;
  color: var(--lp-text-dim);
}
.lp-sb-name {
  font-family: var(--font-display);
  font-weight: 800;
  color: var(--lp-text);
  font-size: 1rem;
  letter-spacing: 0.02em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lp-sb-score {
  font-family: var(--font-mono);
  font-weight: 800;
  font-size: 1.4rem;
  color: var(--lp-text);
}
.lp-sb-divider { text-align: center; }
.lp-sb-vs {
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 800;
  letter-spacing: 0.18em;
  color: var(--lp-text-dim);
}
.lp-sb-final {
  font-family: var(--font-mono);
  font-size: 0.86rem;
  letter-spacing: 0.18em;
  color: var(--lp-gold);
  font-weight: 700;
}
.lp-sb-pending {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  color: var(--lp-text-mute);
  font-style: italic;
  padding: 0.85rem 0;
}

.lp-po-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
}
@media (min-width: 900px) {
  .lp-po-grid { grid-template-columns: 1fr 1fr; }
}
.lp-po-conf {
  background: rgba(244,241,234,0.02);
  border: 1px solid var(--lp-line);
  border-radius: 12px;
  padding: 1rem;
}
.lp-po-conf-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.85rem;
  padding-bottom: 0.65rem;
  border-bottom: 1px solid var(--lp-line);
}
/* 2026-07-22 polish: this badge was a flat solid-gradient square with
   plain text — functionally a "styled text badge" already, but with
   no depth or emblem cues it read as a placeholder/broken-image box
   at a glance. A faint shield watermark + inset highlight gave it
   the look of an intentional crest instead.

   2026-08-09: superseded. It now shows the real AFC/NFC conference
   mark supplied by the operator, served from /images/conference/.
   The gradient square, the inset chrome and the lettered label are
   all retained ONLY behind `.is-fallback`, which the img's onerror
   handler sets if the artwork can't load. */
.lp-po-conf-badge {
  position: relative;
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 0.85rem;
  letter-spacing: 0.08em;
  color: #fff;
  flex-shrink: 0;
}
.lp-po-conf-mark {
  display: block;
  width: 34px;
  height: 34px;
  object-fit: contain;
}
.lp-po-conf-badge-label { position: relative; z-index: 1; display: none; }
.lp-po-conf-badge.is-fallback {
  border-radius: 8px;
  overflow: hidden;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.22),
    inset 0 -8px 12px rgba(0,0,0,0.28);
}
.lp-po-conf-badge.is-fallback .lp-po-conf-badge-label { display: inline; }
.lp-po-conf-badge.is-fallback.is-afc { background: linear-gradient(135deg, #c41230, #8b0a1a); }
.lp-po-conf-badge.is-fallback.is-nfc { background: linear-gradient(135deg, #1f4e9c, #143057); }
.lp-po-conf-title {
  font-family: var(--font-display);
  font-weight: 800;
  letter-spacing: 0.04em;
  color: var(--lp-text);
  font-size: 1rem;
}

.lp-po-seeds { display: flex; flex-direction: column; gap: 0.35rem; margin-bottom: 1rem; }
.lp-po-seed {
  display: grid;
  grid-template-columns: 22px 28px 1fr auto;
  gap: 0.55rem;
  align-items: center;
  min-height: 44px;
  padding: 0.45rem 0.55rem;
  border-radius: 7px;
  background: rgba(244,241,234,0.02);
  border: 1px solid transparent;
  text-decoration: none;
  color: inherit;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.lp-po-seed:hover {
  background: rgba(212,175,55,0.05);
  border-color: rgba(212,175,55,0.18);
}
.lp-po-seed-num {
  font-family: var(--font-display);
  font-weight: 900;
  color: var(--lp-gold);
  font-size: 0.95rem;
  text-align: center;
}
.lp-po-seed-logo { width: 24px; height: 24px; object-fit: contain; }
.lp-po-seed-info { min-width: 0; }
.lp-po-seed-name {
  font-weight: 700;
  color: var(--lp-text);
  font-size: 0.82rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lp-po-seed-record {
  font-family: var(--font-mono);
  font-size: 0.82rem;
  color: var(--lp-text-mute);
}
.lp-po-seed-chip {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  padding: 0.18rem 0.4rem;
  border-radius: 4px;
  background: rgba(212,175,55,0.15);
  color: var(--lp-gold);
  font-weight: 700;
}

.lp-po-round { margin-top: 0.85rem; }
.lp-po-round-label {
  font-family: var(--font-mono);
  font-size: 0.76rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--lp-text-dim);
  margin-bottom: 0.5rem;
  font-weight: 700;
}
.lp-po-empty {
  padding: 0.65rem;
  font-style: italic;
  color: var(--lp-text-dim);
  font-size: 0.78rem;
  text-align: center;
  background: rgba(244,241,234,0.02);
  border-radius: 7px;
}
.lp-po-match {
  display: grid;
  grid-template-columns: 1fr auto 1fr auto;
  gap: 0.4rem;
  align-items: center;
  min-height: 44px;
  padding: 0.55rem 0.65rem;
  border-radius: 8px;
  background: rgba(244,241,234,0.025);
  border: 1px solid var(--lp-line);
  margin-bottom: 0.35rem;
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.lp-po-match:hover { border-color: rgba(212,175,55,0.3); background: rgba(244,241,234,0.04); }
.lp-po-match.is-projected { opacity: 0.7; border-style: dashed; }
.lp-po-match.is-emphasis { border-color: rgba(212,175,55,0.35); background: rgba(212,175,55,0.04); }
.lp-po-match-side {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
  color: var(--lp-text-mute);
}
.lp-po-match-side.is-winner { color: var(--lp-text); }
.lp-po-match-side.is-winner .lp-po-match-name { color: var(--lp-gold); }
.lp-po-match-seed {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--lp-text-dim);
  font-weight: 700;
}
.lp-po-match-logo { width: 20px; height: 20px; object-fit: contain; }
.lp-po-match-name {
  font-weight: 700;
  font-size: 0.78rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lp-po-match-score {
  font-family: var(--font-mono);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  margin-left: auto;
}
.lp-po-match-vs {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--lp-text-dim);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}
.lp-po-match-tag {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  color: var(--lp-text-dim);
  font-weight: 700;
  text-align: right;
}
.lp-po-match-tag.is-final { color: var(--lp-gold); }

/* ═══════ EMPTY STATES ═══════ */
.lp-empty {
  padding: 1.5rem 1.25rem;
  text-align: center;
  color: var(--lp-text-mute);
}
.lp-empty i { display: block; font-size: 1.8rem; color: var(--lp-text-dim); margin-bottom: 0.5rem; }
.lp-empty h6 { font-family: var(--font-display); font-weight: 800; letter-spacing: 0.04em; color: var(--lp-text); margin: 0 0 0.35rem; }
.lp-empty p { font-size: 0.85rem; margin: 0; }

/* ═══════ BOT-NOT-CONNECTED BANNER ═══════
   Shown when a league has published a directory listing but
   hasn't connected the MaddenPro bot — no league data flows.
   Friendly explanation + soft CTA to add the bot.
*/
.lp-no-bot {
  margin: 0 0 2rem;
  padding: 1.5rem 1.5rem 1.65rem;
  border-radius: 14px;
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(ellipse 80% 100% at 50% 50%,
      rgba(143,245,147,0.10) 0%,
      rgba(143,245,147,0.04) 55%,
      rgba(143,245,147,0) 100%);
}
.lp-no-bot::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg, var(--lp-gold), var(--lp-red), transparent);
}
.lp-no-bot-eyebrow {
  font-family: var(--font-mono);
  font-size: 0.81rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--lp-gold);
  margin-bottom: 0.45rem;
  font-weight: 700;
}
.lp-no-bot-title {
  font-family: var(--font-display);
  font-weight: 900;
  letter-spacing: 0.02em;
  color: var(--lp-text);
  font-size: clamp(1.15rem, 2.4vw, 1.55rem);
  margin: 0 0 0.6rem;
  line-height: 1.15;
}
.lp-no-bot-body {
  color: var(--lp-text-mute);
  font-size: 0.95rem;
  line-height: 1.6;
  margin: 0 0 1rem;
  max-width: 56ch;
}
.lp-no-bot-body strong { color: var(--lp-text); font-weight: 700; }
.lp-no-bot-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.7rem 1.2rem;
  border-radius: 8px;
  background: var(--lp-red);
  color: var(--accent-ink, #06220a);
  text-decoration: none;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 700;
  transition: transform 140ms ease;
}
.lp-no-bot-cta:hover { transform: translateY(-1px); }
.lp-no-bot-cta.is-ghost {
  background: transparent;
  color: var(--lp-text);
  border: 1px solid var(--lp-line-2);
}
.lp-no-bot-actions { display: flex; flex-wrap: wrap; gap: 0.55rem; }

/* ═══════ PORTAL LINKS (2026-08-02) ═══════
   Owner report: "for standings it takes me to a page I like for league
   standings… I need to make sure that is wired in on the website in the
   leagues because I can't see that on the website alone."

   The league portal (/league/:leagueId/standings | /leaders | /compare |
   /achievements) has always existed, but this page — the ONLY public
   entry point to a league — never linked to it, so those pages were
   reachable only from the in-app "Public" buttons that have now been
   removed. This strip is the website's door into the portal.

   Deliberately NOT a copy of _portal_tabs.pug: that partial is styled for
   the portal's own dark chrome (app.css-adjacent tokens) and carries
   sign-in CTAs. This is the same link SET rendered in this page's own
   .lp-* visual language. One implementation of each page still — these
   are links, not duplicated content.

   Content links only, no purchase CTA (Apple 3.1.1) — this page renders
   inside the app shell too. */
.lp-portal {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0.5rem;
}
.lp-portal-link {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 44px;
  padding: 0.7rem 0.85rem;
  border-radius: 10px;
  background: rgba(244,241,234,0.025);
  border: 1px solid var(--lp-line);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s ease, background 0.15s ease, transform 0.15s ease;
}
.lp-portal-link:hover {
  border-color: var(--lp-line-2);
  background: rgba(244,241,234,0.05);
  transform: translateY(-1px);
}
.lp-portal-link:focus-visible { outline: 2px solid var(--lp-gold); outline-offset: 2px; }
.lp-portal-link i { color: var(--lp-gold); font-size: 1.05rem; flex-shrink: 0; }
.lp-portal-label {
  font-family: var(--font-mono);
  font-size: 0.82rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--lp-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lp-portal-chev { margin-left: auto; color: var(--lp-text-dim); font-size: 0.8rem; }
.lp-portal-link:hover .lp-portal-chev { color: var(--lp-gold); }

/* Tags */
.lp-tags { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-top: 0.85rem; }
.lp-tag {
  font-family: var(--font-mono);
  font-size: 0.86rem;
  letter-spacing: 0.08em;
  padding: 0.28rem 0.55rem;
  border-radius: 4px;
  background: rgba(244,241,234,0.05);
  color: var(--lp-text-mute);
  border: 1px solid var(--lp-line);
}

/* ═══════ RESULTS ROW — ≤479px ═══════
   The 7-column scoreboard squeezes team-name columns to ~42px
   at 320px, clipping names to 1–2 characters. At tiny phone
   widths, drop the week chip and the "at" separator and reduce
   to 5 columns so each team side gets ≥100px of breathing room.
   The card heading ("Recent results") keeps context for the
   week label that's hidden. */
@media (max-width: 479px) {
  .lp-results-row {
    grid-template-columns: 1fr auto auto 1fr 20px;
    gap: 0.35rem;
    padding: 0.6rem 0.65rem;
  }
  /* 2026-07-22 fix: `.lp-results-week{display:none}` alone never won
     against `a.lp-results-week.is-link{display:inline-flex}` above —
     that selector has higher specificity (0,2,1 vs 0,1,0), so CSS
     cascade rules always picked it regardless of source order. On
     any played/preview game (i.e. whenever gameHref exists, which is
     nearly always) the WK-badge + arrow stayed visible at ≤479px but
     the grid was already recut to 5 columns, so the extra 6th visible
     item had nowhere to go and wrapped the row into a second line.
     Repeating the exact `a.lp-results-week.is-link` selector here
     matches specificity, and same-specificity + later-in-source wins. */
  .lp-results-week,
  a.lp-results-week.is-link { display: none; }
  .lp-results-at   { display: none; }
  .lp-results-logo { width: 20px; height: 20px; }
  .lp-results-name { font-size: 0.78rem; }
  .lp-results-score { font-size: 0.88rem; }
}

/* Standings — ≤479px: the fixed column widths above already stop the
   Team/Owner overlap, but the city sub-name (e.g. "Pittsburgh") is
   the least essential part of the Team cell at this width — drop it
   so the abbr + owner chip both get more breathing room. */
@media (max-width: 479px) {
  .lp-stand-table th, .lp-stand-table td { padding: 0.3rem 0.22rem; }
  .lp-stand-sub { display: none; }
  .lp-owner-chip { font-size: 0.74rem; padding: 0.14rem 0.32rem; }
}

/* ── Below the standings: drawn when it is reached, not before ────────────
 *
 * 2026-09-17. The page is ~1,900 elements and eight tables. Everything below
 * the standings — the playoff picture, the power rankings, the newswire, the
 * League TV card and the recap card — is real content a reader wants and a
 * crawler should index, so it stays in the HTML exactly as it was. What it
 * does NOT need to do is cost layout and paint before anyone has scrolled to
 * it, which on a phone is a chunk of the "slow to open" the operator felt.
 *
 * `content-visibility: auto` is the browser's own answer to that: skip the
 * rendering work for a subtree that is off screen, and do it the moment it
 * comes near. Nothing is hidden — find-in-page, anchor links, screen readers
 * and search engines all still reach it, which is the whole reason this is
 * the mechanism rather than a JavaScript "load more" that would strip the
 * content out of a public, indexed page.
 *
 * `contain-intrinsic-size` is the placeholder height used while a section is
 * skipped. Without it the scrollbar jumps around as sections are reached;
 * `auto 900px` means "remember the real height once you have seen it, and
 * guess 900px until then". A browser that does not support either property
 * simply renders the page the way it always did.
 */
.lp-defer {
  content-visibility: auto;
  contain-intrinsic-size: auto 900px;
}
