/*
 * Holocron Rating Index — Design System
 * Dark theme, holocron crystal aesthetic.
 */

/* ============================================================
   DESIGN TOKENS
   ============================================================ */

:root {
  /* Colors — from Pencil design (design/hri-design.pen) */
  --bg:              #0B1120;
  --surface:         #111827;
  --card:            #1A2332;
  --card-hover:      #1E2A3D;
  --input:           #0F1A2A;
  --border:          #1E3A5F;
  --text-primary:    #F1F5F9;
  --text-secondary:  #CBD5E1;
  --text-tertiary:   #94A3B8;
  --accent:          #0EA5E9;
  --accent-hover:    #38BDF8;
  --accent-surface:  var(--accent-subtle);
  --accent-glow:     rgba(56, 189, 248, 0.2);

  /* Accent alpha scale. Use these instead of inline rgba() calls so
     hover/active/surface tints stay consistent across the stylesheet.
       wash    — almost-there tint (backgrounds, grid, hovers on dark cards)
       subtle  — chip bg, surface tint
       soft    — callout bg, active-filter bg, header underline
       mid     — focus ring halo, medium glow
       strong  — primary border, strong chip border
       hot     — reserved for #1 rank, peak states */
  --accent-wash:     rgba(14, 165, 233, 0.04);
  --accent-subtle:   rgba(14, 165, 233, 0.08);
  --accent-soft:     rgba(14, 165, 233, 0.18);
  --accent-mid:      rgba(14, 165, 233, 0.25);
  --accent-strong:   rgba(14, 165, 233, 0.4);
  --accent-hot:      rgba(14, 165, 233, 0.6);
  --positive:        #22C55E;
  --negative:        #EF4444;
  --warning:         #F59E0B;

  /* Tier colors — distinct hues for instant recognition */
  --tier-planetary:  #22C55E;
  --tier-sector:     #F59E0B;
  --tier-regional:   #0EA5E9;
  --tier-galactic:   #7C3AED;

  /* Format identity colors. Reuses existing palette hues rather than
     adding new ones — Premier owns the accent (primary format), Limited
     echoes warning/amber (smaller pool, warmer hue), Eternal borrows
     the violet family (tracked separately from the Overall composite). */
  --fmt-premier:     var(--accent);
  --fmt-limited:     #F59E0B;
  --fmt-eternal:     #A78BFA;

  /* Rank medal colors */
  --rank-gold:       #F59E0B;
  --rank-silver:     #CBD5E1;
  --rank-bronze:     #D97706;

  /* Typography — Geist family from Pencil design */
  --font-display: 'Geist', system-ui, sans-serif;
  --font-body:    'Inter', system-ui, sans-serif;
  --font-data:    'Geist Mono', 'JetBrains Mono', monospace;

  /* Spacing (8px base) */
  --space-2xs:  4px;
  --space-xs:   8px;
  --space-sm:   12px;
  --space-md:   16px;
  --space-lg:   24px;
  --space-xl:   32px;
  --space-2xl:  48px;
  --space-3xl:  64px;

  /* Border radii */
  --radius-sm:   4px;
  --radius-md:   8px;
  --radius-lg:   12px;
  --radius-full: 20px;
}

/* ============================================================
   RESET / BASE
   ============================================================ */

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

html {
  font-size: 16px;
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.5;
  background-color: var(--bg);
  color: var(--text-primary);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  isolation: isolate;
}

a {
  color: var(--accent);
  text-decoration: none;
}

a:hover {
  color: var(--accent-hover);
}

img, svg {
  display: block;
  max-width: 100%;
}

table {
  border-collapse: collapse;
}

/* ============================================================
   BACKGROUND SURFACE — schematic grid
   Faint tactical-display grid fixed to the viewport, masked
   to fade from top-center outward. Sits behind all content.
   ============================================================ */

body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    linear-gradient(var(--accent-subtle) 1px, transparent 1px),
    linear-gradient(90deg, var(--accent-subtle) 1px, transparent 1px);
  background-size: 48px 48px;
  -webkit-mask-image: radial-gradient(ellipse at top, black 0%, transparent 70%);
          mask-image: radial-gradient(ellipse at top, black 0%, transparent 70%);
}

/* ============================================================
   LAYOUT
   ============================================================ */

.container {
  width: 100%;
  max-width: 1440px;
  margin-inline: auto;
  padding-inline: 32px;
}

main {
  flex: 1;
}

.content-area {
  padding: 32px 80px 48px;
}

/* ============================================================
   SITE HEADER (matches Pencil NavBar component)
   ============================================================ */

.site-header {
  background-color: var(--surface);
  position: sticky;
  top: 0;
  z-index: 100;
}

.site-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 56px;
  padding: 0 32px;
}

.nav-left { display: flex; align-items: center; }

.site-logo {
  display: flex;
  align-items: center;
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text-primary);
  transition: color 0.15s ease;
}

.site-logo:hover {
  color: var(--accent);
}

.nav-logo-img {
  height: 36px;
  width: auto;
  transition: opacity 0.15s ease;
}

.site-logo:hover .nav-logo-img { opacity: 0.85; }

.nav-links {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
}

.nav-link {
  font-family: var(--font-body);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-secondary);
  transition: color 0.15s ease;
}

.nav-link:hover {
  color: var(--text-primary);
}

.nav-link--active {
  color: var(--accent);
  font-weight: 600;
}

/* ============================================================
   SITE FOOTER
   ============================================================ */

.site-footer {
  background-color: var(--surface);
  border-top: 1px solid var(--border);
  padding-block: var(--space-lg);
  margin-top: auto;
}

.footer-text {
  font-size: 0.8125rem;
  color: var(--text-tertiary);
  text-align: center;
  line-height: 1.6;
}

.footer-link {
  color: var(--text-secondary);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.footer-link:hover {
  color: var(--text-primary);
}

/* ============================================================
   TYPOGRAPHY
   ============================================================ */

.heading-xl {
  font-family: var(--font-display);
  font-size: 1.75rem;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.heading-lg {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.3;
}

.label {
  font-family: var(--font-body);
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--text-tertiary);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ============================================================
   DATA TYPOGRAPHY
   ============================================================ */

.data {
  font-family: var(--font-data);
  font-size: 0.8125rem;
  font-weight: 400;
  color: var(--text-primary);
}

.data-lg {
  font-family: var(--font-data);
  font-size: 1rem;
  font-weight: 500;
  color: var(--text-primary);
}

/* ============================================================
   RATING NUMBERS
   Glow ONLY on hero and table rating — no glow elsewhere.
   ============================================================ */

.rating-number {
  font-family: var(--font-data);
  font-weight: 700;
  color: var(--accent);
  line-height: 1;
}

/* Hero: large glow (profile page, featured display) */
.rating-number--hero {
  font-size: 3rem;  /* 48px */
  text-shadow: 0 0 12px var(--accent-glow);
}

/* Table: subtle glow in the ratings column */
.rating-number--table {
  font-size: 0.8125rem;
  text-shadow: 0 0 8px var(--accent-glow);
}

/* ============================================================
   RATING CHANGE
   ============================================================ */

.rating-change {
  font-family: var(--font-data);
  font-size: 0.8125rem;
  font-weight: 500;
}

.rating-change--positive {
  color: var(--positive);
}

.rating-change--negative {
  color: var(--negative);
}

/* ============================================================
   RATING DEVIATION
   ============================================================ */

.rd {
  font-family: var(--font-data);
  font-size: 0.6875rem;
  color: var(--text-tertiary);
}

/* ============================================================
   HERO SECTION (Rankings page top)
   ============================================================ */

/* Vertical stack: logo anchors top, title + subtitle as a lockup below,
   stats strip at the bottom. Three clear tiers with generous gap between
   them (--space-xl = 32px) so the hero reads as a composition, not a
   single crowded row. */
.hero-section {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-xl);
  padding: 48px 80px 40px;
}

/* Bottom divider inset to match the content-area's horizontal padding,
   so the line aligns with the visible edges of the table rows below
   instead of running edge-to-edge of the hero's own 1280px box. Media
   queries below track the responsive padding changes. */
.hero-section::after {
  content: '';
  position: absolute;
  left: 80px;
  right: 80px;
  bottom: 0;
  height: 1px;
  background: var(--border);
}

.hero-lockup {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  min-width: 0;
  text-align: center;
}

.hero-logo {
  height: 128px;
  width: auto;
  flex-shrink: 0;
  display: block;
  filter: drop-shadow(0 0 20px var(--accent-soft));
}

.hero-title {
  font-family: var(--font-display);
  font-size: 36px;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--text-primary);
  margin: 0;
  line-height: 1;
}

.hero-sub {
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 400;
  color: var(--text-secondary);
  margin: 0;
  letter-spacing: 0.005em;
  line-height: 1.4;
}

.hero-sub strong {
  color: var(--accent);
  font-weight: 600;
}

/* Global stats banner at the top of the rankings page — three big numbers
   (Rated Players / Tournaments Tracked / Matches Analyzed). Distinct
   namespace from the profile's .hero-stat tree below, which was being
   silently shadowed by the later-declared profile rule. */
/* Force the stats strip onto its own row beneath the logo + title lockup,
   centered. Flex-basis: 100% flips it into a second flex line so it no
   longer competes with the hero title horizontally. Smaller numbers match
   the demoted position — still readable, but no longer shouting over the
   title. */
.global-stats {
  display: flex;
  align-items: stretch;
  justify-content: center;
  gap: 28px;
  flex-basis: 100%;
}

.global-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 88px;
}

.global-stat__value {
  font-family: var(--font-data);
  font-size: 20px;
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: -0.02em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.global-stat__label {
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 500;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.hero-divider {
  width: 1px;
  align-self: stretch;
  background: var(--border);
}

/* ============================================================
   TOURNAMENTS INDEX — layout rhythm
   Scoped overrides to cap content width, restore hero hierarchy,
   and stack filter concerns vertically so the page has a proper
   heading / controls / table / footer rhythm instead of a single
   undifferentiated slab of rows.
   ============================================================ */

/* Cap the table column at a comfortable reading width on 1440+ screens.
   Below 1280px the rule is a no-op (max-width kicks in only above the
   cap); above it, the row text stops running the full monitor width. */
.tournaments-index {
  max-width: 1280px;
  margin-inline: auto;
}

/* Hero strip: the title earns real display-size weight; the count
   sits immediately next to it like a dateline ("Tournaments · 799
   rated events"), not stretched to the far edge where it floats
   disconnected. The shared .section-header default is space-between
   (leaderboard pairs title with a right-aligned control); on this
   page the count is a supporting stat for the title, so flush-start. */
.tournaments-index .section-header {
  justify-content: flex-start;
  align-items: baseline;
  gap: var(--space-md);
  margin-top: var(--space-xl);
  margin-bottom: var(--space-xl);
}

.section-header__title {
  font-family: var(--font-display);
  font-size: 1.75rem;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.1;
  letter-spacing: -0.01em;
}

.section-header__meta {
  margin: 0;
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-tertiary);
}

.section-header__count {
  font-family: var(--font-data);
  font-size: 14px;
  font-weight: 600;
  color: var(--text-secondary);
  letter-spacing: 0.01em;
}

/* (filtered) is a link to clear every filter in one shot. The dotted
   underline appears only on hover so the default state reads as a quiet
   status marker, not a blue web link. Chrome becomes functionality. */
.section-header__filtered {
  font-family: var(--font-data);
  font-size: 11px;
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-left: var(--space-2xs);
  text-decoration: none;
  border-bottom: 1px dotted transparent;
  transition: border-color 150ms ease;
}

a.section-header__filtered:hover,
a.section-header__filtered:focus-visible {
  border-bottom-color: color-mix(in oklch, var(--accent) 60%, transparent);
  outline: none;
}

/* Search input wrap — holds the field and the `/` keyboard-shortcut
   badge. Position: relative so the badge can absolute-position at the
   right edge without knocking the input's own padding. The badge stays
   out of the way of typed input via right-side padding on the input. */
.search-input-wrap {
  position: relative;
  width: 100%;
  max-width: 480px;
}

.search-input-wrap .search-input {
  width: 100%;
  padding-right: 36px;
}

.search-input__hint {
  position: absolute;
  top: 50%;
  right: 10px;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  font-family: var(--font-data);
  font-size: 11px;
  font-weight: 600;
  color: var(--text-tertiary);
  background: color-mix(in oklch, var(--border) 60%, transparent);
  border: 1px solid var(--border);
  border-radius: 4px;
  pointer-events: none;
  opacity: 0.8;
  transition: opacity 150ms ease, color 150ms ease;
}

.search-input-wrap:focus-within .search-input__hint {
  opacity: 0;
}

/* Hide the hint on small screens — mobile users don't have a keyboard
   and the badge would just eat input padding. */
@media (max-width: 640px) {
  .search-input__hint { display: none; }
  .search-input-wrap .search-input { padding-right: 16px; }
}


/* Filter stack — search + two labeled groups stacked vertically.
   Related rows sit 12px apart; the whole stack separates from the
   table below by a generous 32px so the table reads as a distinct
   block with real whitespace above and below it. */
.filter-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin-bottom: var(--space-xl);
}

.filter-stack__search .search-input {
  width: 100%;
  max-width: 480px;
}

.filter-stack__group {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

.filter-stack__label {
  font-family: var(--font-data);
  font-size: 11px;
  font-weight: 600;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  min-width: 56px;
}

/* Row height matches DESIGN.md spec for TournamentRow (52px).
   The shared .rank-row base is 56px for the leaderboard where the
   rating number wants more presence; tournaments are a denser list
   and earn the 4px back. Also adds an inter-column gap so adjacent
   cells (Players/Winner, Winner/Date, Tier/Format) don't collide —
   numeric and text values had been butting up against each other
   at the cell boundary with no visual breath. Header matches so
   column labels stay perfectly aligned with row cells. Mobile
   override below restores the tighter 2-line card gaps so the
   compact card layout keeps its density. */
.tournaments-index .tournament-row,
.tournaments-index .table-header {
  gap: var(--space-md);
}

.tournaments-index .tournament-row {
  height: 52px;
}

/* Mobile: release the fixed 52px desktop height so the 2-3 line wrap
   card can grow to fit its content. The base .tournament-row mobile
   rule (below, in the main responsive block) sets height: auto too,
   but this scoped selector has higher specificity and wins — without
   this override, long winner usernames overflow the row and collide
   with the next card's title. Gaps pulled in here so the whole mobile
   behavior for tournaments-index is visible in one place. */
@media (max-width: 640px) {
  .tournaments-index .tournament-row {
    height: auto;
    row-gap: 6px;
    column-gap: 10px;
  }
}

/* Pagination breathing room — reads as a page footer, not as row 51. */
.tournaments-index .pagination {
  padding-top: var(--space-xl);
  margin-top: var(--space-sm);
}

/* Small-screen stack: the filter-stack__group wraps its label above
   the chip row so chips still get a full horizontal scroll lane.
   Mobile table-header sticky offset is handled elsewhere. */
@media (max-width: 640px) {
  .filter-stack__group {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2xs);
  }
  .tournaments-index .section-header {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2xs);
    margin-top: var(--space-lg);
    margin-bottom: var(--space-lg);
  }
  .section-header__title {
    font-size: 1.5rem;
  }
}

/* ============================================================
   FILTER ROW (search + chips) — legacy, still used elsewhere
   ============================================================ */

.filter-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 20px;
}

.filter-row .search-input {
  width: 480px;
  max-width: 480px;
}

.filter-chips {
  display: flex;
  gap: 8px;
  align-items: center;
}

.chip {
  display: inline-flex;
  align-items: center;
  padding: 6px 16px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background-color: var(--card);
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 500;
  color: var(--text-secondary);
  cursor: pointer;
  transition: all 0.15s ease;
  white-space: nowrap;
}

.chip:hover {
  border-color: var(--accent);
  color: var(--text-primary);
}

/* Tactile press — chip scales down a hair on click-and-hold and springs
   back. 60ms is under the perceptual threshold of "laggy" but long enough
   to feel the click. Respects prefers-reduced-motion. */
.chip:active {
  transform: scale(0.96);
  transition: transform 0.06s ease;
}

@media (prefers-reduced-motion: reduce) {
  .chip:active { transform: none; }
}

.chip--active {
  border-color: var(--accent);
  background-color: var(--accent);
  color: var(--bg);
  font-weight: 600;
}

/* Tier-colored chip variants. Inactive state uses the tier hue for text +
   hover border; active state fills with the tier color (matching the same
   tier's badge on the tournament rows below). */
.chip--tier-planetary { color: var(--tier-planetary); }
.chip--tier-planetary:hover { border-color: var(--tier-planetary); color: var(--tier-planetary); }
.chip--tier-planetary.chip--active { background-color: var(--tier-planetary); border-color: var(--tier-planetary); color: var(--bg); }

.chip--tier-sector { color: var(--tier-sector); }
.chip--tier-sector:hover { border-color: var(--tier-sector); color: var(--tier-sector); }
.chip--tier-sector.chip--active { background-color: var(--tier-sector); border-color: var(--tier-sector); color: var(--bg); }

.chip--tier-regional { color: var(--tier-regional); }
.chip--tier-regional:hover { border-color: var(--tier-regional); color: var(--tier-regional); }
.chip--tier-regional.chip--active { background-color: var(--tier-regional); border-color: var(--tier-regional); color: var(--bg); }

.chip--tier-galactic { color: var(--tier-galactic); }
.chip--tier-galactic:hover { border-color: var(--tier-galactic); color: var(--tier-galactic); }
.chip--tier-galactic.chip--active { background-color: var(--tier-galactic); border-color: var(--tier-galactic); color: var(--bg); }

/* Format-colored chip variants. Inactive shows the format hue as tinted
   text; active fills with the format color. Same pattern as tier chips
   so the two filter rows on /tournaments read the same visual language. */
.chip--fmt-premier { color: var(--fmt-premier); }
.chip--fmt-premier:hover { border-color: var(--fmt-premier); color: var(--fmt-premier); }
.chip--fmt-premier.chip--active { background-color: var(--fmt-premier); border-color: var(--fmt-premier); color: var(--bg); }

.chip--fmt-limited { color: var(--fmt-limited); }
.chip--fmt-limited:hover { border-color: var(--fmt-limited); color: var(--fmt-limited); }
.chip--fmt-limited.chip--active { background-color: var(--fmt-limited); border-color: var(--fmt-limited); color: var(--bg); }

.chip--fmt-eternal { color: var(--fmt-eternal); }
.chip--fmt-eternal:hover { border-color: var(--fmt-eternal); color: var(--fmt-eternal); }
.chip--fmt-eternal.chip--active { background-color: var(--fmt-eternal); border-color: var(--fmt-eternal); color: var(--bg); }

/* ============================================================
   SEARCH INPUT
   ============================================================ */

.search-input {
  display: block;
  padding: 0 16px;
  background-color: var(--input);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font-family: var(--font-body);
  font-size: 16px;
  color: var(--text-primary);
  outline: none;
  transition: border-color 0.15s ease;
  height: 44px;
}

.search-input::placeholder { color: var(--text-tertiary); }
.search-input:focus { border-color: var(--accent); }

/* ============================================================
   TABLE CONTAINER (flex-based rows, not <table>)
   Matches Pencil RankRow / TournRow components
   ============================================================ */

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

.table-header {
  display: flex;
  align-items: center;
  height: 40px;
  padding: 0 20px;
  font-family: var(--font-data);
  font-size: 11px;
  font-weight: 500;
  color: var(--text-tertiary);
  letter-spacing: 0.5px;
  text-transform: uppercase;
  /* Sticks directly below the fixed site nav (56px desktop, 52px mobile) so
     column labels survive scrolls past rank ~15. Background matches --bg so
     the header doesn't render transparent when the sticky kicks in. Mobile
     top offset is handled in the <=640px breakpoint below. */
  position: sticky;
  top: 56px;
  z-index: 10;
  background: var(--bg);
}

@media (max-width: 640px) {
  .table-header { top: 52px; }
}

/* Profile pages already have their own sticky header (.profile-sticky) in
   the same vertical slot — stacking another sticky layer under it just
   obscures the column labels. Drop the sticky behavior here; profile
   tables are paginated to 10 rows so the column labels are rarely
   scrolled out of view anyway. */
.profile-page .table-header {
  position: static;
  top: auto;
}

/* Content-width cap — same 1280px envelope as .tournaments-index and
   .tournament-show. Keeps every top-level user-facing view optically
   aligned on wide monitors: rankings, profile, per-event audit, and both
   tournament pages all center on the same vertical column. Below 1280px
   the rule is a no-op (max-width only kicks in when the viewport is
   wider). Tables inside (all on the shared .table-container primitive)
   inherit the constraint without any per-component width changes.

   The leaderboard's .hero-section sits OUTSIDE .content-area in the DOM,
   so it gets its own matching cap — otherwise the banner would run
   full-bleed while the filter/table below it sat in the middle, with
   mismatched left edges. Capping it here keeps the whole page on one
   centerline. */
.leaderboards-show,
.profile-page,
.player-audit {
  max-width: 1280px;
  margin-inline: auto;
}

.hero-section {
  max-width: 1280px;
  margin-inline: auto;
}

/* Rank row (leaderboard) */
.rank-row {
  display: flex;
  align-items: center;
  height: 56px;
  padding: 0 20px;
  background: var(--card);
  border-radius: 6px;
  text-decoration: none;
  transition: background 0.1s ease;
  color: inherit;
}

.rank-row:hover { background: var(--card-hover); }

.rank-row--empty {
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 4px;
  height: auto;
  min-height: 72px;
  padding: 16px 20px;
  color: var(--text-tertiary);
  font-size: 13px;
  text-align: center;
}

.rank-row--empty:hover { background: var(--card); }

.rank-row--empty__headline {
  margin: 0;
  color: var(--text-secondary);
  font-weight: 500;
}

.rank-row--empty__recovery {
  margin: 0;
  font-size: 12px;
  color: var(--text-tertiary);
}

.rank-row--empty__link {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px dotted color-mix(in oklch, var(--accent) 40%, transparent);
  transition: border-color 150ms ease;
}

.rank-row--empty__link:hover,
.rank-row--empty__link:focus-visible {
  border-bottom-color: var(--accent);
  outline: none;
}

/* On desktop, .rank-meta and .tourn-meta are invisible to layout — their
   children participate in the row's flex container directly, matching the
   table-header column widths. On mobile they collapse into a second row. */
.rank-meta, .tourn-meta { display: contents; }

/* Tournament row (profile) */
.tourn-row {
  display: flex;
  align-items: center;
  height: 52px;
  padding: 0 20px;
  background: var(--card);
  border-radius: 6px;
}

/* Column widths — rank table.
   Rank column sized to fit 5 digits at 16px Geist Mono Bold (~48px content)
   plus right-side breathing room before the player name starts. Right-aligned
   so numbers stay visually flush as digit count changes. */
/* Every numeric column right-aligns on desktop so digits line up vertically
   down the table. tabular-nums keeps same-digit counts at the same pixel
   width — critical for the leaderboard where small differences between
   rating numbers should read at a glance. */
.th-rank, .rank-num    { width: 72px; padding-right: 16px; text-align: right; font-variant-numeric: tabular-nums; }
.th-player, .rank-player { flex: 1; min-width: 0; }
.th-rating, .rank-rating { width: 80px; text-align: right; font-variant-numeric: tabular-nums; }
.th-record, .rank-record { width: 70px; text-align: right; font-variant-numeric: tabular-nums; }
.th-winrate, .rank-winrate { width: 60px; text-align: right; font-variant-numeric: tabular-nums; }
.th-events, .rank-events { width: 60px; text-align: right; font-variant-numeric: tabular-nums; }
.th-confidence, .rank-confidence { width: 90px; text-align: right; font-variant-numeric: tabular-nums; }

/* Column widths — tournament table */
.th-event, .tourn-event   { flex: 1; }
.th-tier, .tourn-tier     { width: 100px; text-align: center; }
.th-delta, .tourn-delta   { width: 80px; text-align: right; }
.th-date, .tourn-date     { width: 90px; text-align: right; }
.tourn-record             { width: 80px; text-align: center; }
.tourn-rating             { width: 80px; text-align: right; }

/* Global tournaments index columns — reuses .rank-row for the row chrome.
   Winner cell is left-aligned so the gold ★ markers stack into a clean
   podium line down the column instead of drifting around a center point
   as usernames change length. Tier/Format stay center-aligned because
   the badge and tag read as centered chips; Players/Date stay right
   because they're numeric/temporal. */
.th-format, .tourn-format   { width: 80px; text-align: center; font-family: var(--font-data); font-size: 11px; color: var(--text-tertiary); text-transform: uppercase; letter-spacing: 0.4px; }
.th-players, .tourn-players { width: 72px; text-align: right; font-family: var(--font-data); font-size: 13px; color: var(--text-secondary); }
.th-winner, .tourn-winner   { width: 140px; text-align: left; }

/* Winner cell repeats on every row — glow here would debase the "accent glow
   means rating hero / #1 rank / Galactic tier badge" signal (see DESIGN.md
   glow-restraint principle). Color alone carries the link affordance; row
   hover raises the row background for the interactive feedback. A dotted
   underline fills in on precision-hover, matching the inline-link idiom
   used by .rank-row--empty__link — rewards the user who aimed at the name. */
.tourn-winner__name {
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 600;
  color: var(--accent);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: inline-block;
  max-width: calc(100% - 20px);
  vertical-align: middle;
  border-bottom: 1px dotted transparent;
  transition: border-color 200ms ease, color 150ms ease;
}

.tourn-winner__name:hover,
.tourn-winner__name:focus-visible {
  border-bottom-color: color-mix(in oklch, var(--accent) 60%, transparent);
  outline: none;
}

/* Gold star before the winner name. Scope is the single event, so the
   winner IS the #1 of that event — same rank-gold token used for the
   overall leaderboard's gold medal. One glyph, screen-reader hidden,
   so the density stays tight and the cell still reads as a player link. */
.tourn-winner__medal {
  display: inline-block;
  margin-right: 5px;
  font-size: 11px;
  color: var(--rank-gold);
  vertical-align: baseline;
  line-height: 1;
  pointer-events: none;
  user-select: none;
}

.tourn-winner__empty {
  font-family: var(--font-data);
  font-size: 13px;
  color: var(--text-tertiary);
}

/* Stretched-link pattern: the tournament name is the primary link for the
   row, but its ::before overlay covers the whole card so clicking any
   empty cell still navigates. Other row links (like the winner name) use
   .stretched-link-escape to sit above the overlay and keep their own href. */
.tournament-row {
  position: relative;
  cursor: pointer;
}

.tournament-row .stretched-link::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: auto;
}

.tournament-row .stretched-link-escape {
  position: relative;
  z-index: 1;
}

.tournament-row .tourn-event-name {
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 500;
  color: var(--text-primary);
}

/* Rank number medals */
.rank-num {
  font-family: var(--font-data);
  font-size: 16px;
  font-weight: 700;
  color: var(--text-secondary);
}
.rank--gold   { color: var(--rank-gold); }
.rank--silver { color: var(--rank-silver); }
.rank--bronze { color: var(--rank-bronze); }

/* Player cell with avatar */
.rank-player {
  display: flex;
  align-items: center;
  gap: 12px;
}

.player-avatar {
  width: 34px;
  height: 34px;
  border-radius: 17px;
  background: var(--border);
  flex-shrink: 0;
}

.player-name {
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
}

.player-username {
  font-size: 11px;
  font-weight: 400;
  color: var(--text-tertiary);
  margin-left: 4px;
}

/* Rating column */
.rank-rating {
  font-family: var(--font-data);
  font-size: 13px;
  font-weight: 700;
  color: var(--accent);
}

/* Record, win rate, events */
.rank-record, .tourn-record {
  font-family: var(--font-data);
  font-size: 13px;
  color: var(--text-secondary);
}

.rank-winrate {
  font-family: var(--font-data);
  font-size: 13px;
}

/* Win-rate sign tints — pulled out of an inline style so the view stays
   CSP-friendly and the color semantic lives with the rest of the type.
   The neutral variant renders on zero-match ranked players (rare data
   edge) where "0.0%" in red would falsely imply a losing record. */
.rank-winrate--positive { color: var(--positive); }
.rank-winrate--negative { color: var(--negative); }
.rank-winrate--neutral  { color: var(--text-tertiary); }

/* Sparkbars on the Win% and Confidence columns — thin 2px bar at the
   bottom of each cell, width scaled by the row's --magnitude custom
   property. Same data-density pattern as the tournament-show rating
   shift table: a visual layer on top of the number so the whole column
   is scannable at a glance. Gradient fades from transparent to the
   full signal color, reading as "lit" from the right edge. */
.rank-winrate,
.rank-confidence {
  position: relative;
  overflow: hidden;
}

.rank-winrate::after,
.rank-confidence::after {
  content: '';
  position: absolute;
  right: 0;
  bottom: 0;
  height: 2px;
  width: calc(var(--magnitude, 0) * 100%);
  border-radius: 1px;
  pointer-events: none;
}

.rank-winrate--positive::after {
  background: linear-gradient(to left,
    rgba(34, 197, 94, 0.85),
    rgba(34, 197, 94, 0.15));
}

.rank-winrate--negative::after {
  background: linear-gradient(to left,
    rgba(239, 68, 68, 0.85),
    rgba(239, 68, 68, 0.15));
}

.rank-confidence--established::after {
  background: linear-gradient(to left,
    rgba(34, 197, 94, 0.75),
    rgba(34, 197, 94, 0.15));
}

.rank-confidence--developing::after {
  background: linear-gradient(to left,
    rgba(245, 158, 11, 0.75),
    rgba(245, 158, 11, 0.15));
}

.rank-confidence--provisional::after {
  background: linear-gradient(to left,
    rgba(148, 163, 184, 0.5),
    rgba(148, 163, 184, 0.1));
}

.rank-events {
  font-family: var(--font-data);
  font-size: 13px;
  color: var(--text-secondary);
}


/* Confidence badge */
.confidence-badge {
  font-family: var(--font-data);
  font-size: 13px;
  color: var(--text-secondary);
  cursor: help;
  border-bottom: 1px dotted var(--text-tertiary);
}

/* Sortable column header on the tournaments index (Date). Inherits the
   table-header typography so it reads as part of the row; the arrow is
   the only visual signal that the column is interactive. */
.th-date__sort {
  color: inherit;
  text-decoration: none;
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
}

.th-date__sort:hover .th-date__arrow,
.th-date__sort:focus-visible .th-date__arrow {
  color: var(--accent);
}

.th-date__sort:focus-visible {
  outline: 1px solid color-mix(in oklch, var(--accent) 50%, transparent);
  outline-offset: 2px;
  border-radius: 3px;
}

.th-date__arrow {
  color: var(--text-tertiary);
  font-size: 12px;
  transition: color 150ms ease;
}

/* Tournament row specifics */
.tourn-event-name {
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
}

.tourn-event-external {
  font-family: var(--font-data);
  font-size: 10px;
  color: var(--text-tertiary);
  text-decoration: none;
  margin-left: 8px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  transition: color 150ms ease;
  white-space: nowrap;
}

/* Event location as a dim second line under the event name. Search matches
   location server-side, so surfacing it here is how the row tells the user
   "that 'Milwaukee' you typed? matched this." Inter body font keeps it as
   narrative context; Geist Mono would misread as a data field. */
.tourn-event__location {
  display: block;
  margin-top: 2px;
  font-family: var(--font-body);
  font-size: 12px;
  color: var(--text-tertiary);
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Same location string in the tournament show-page hero meta strip —
   sits inline with tier/format/date/player-count. Uses the meta row's
   existing typography scale; no new tokens introduced. Mirrors the index
   ellipsis cap so an unusually long upstream location string can't blow
   out the meta row on mobile; full string still accessible via Melee. */
.tournament-hero__location {
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-tertiary);
  max-width: 32ch;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tourn-event-external:hover {
  color: var(--accent);
}

.tourn-event-external::after {
  content: " \2192";
}

/* On the index row, the "→" glyph is hidden at rest (50 rows × an arrow
   would read as chrome) and fades in only on hover or keyboard focus.
   The link still opens Melee in a new tab; the arrow just surfaces as
   an "external" affordance once the user's cursor declares intent. */
.tournament-row .tourn-event-external::after {
  opacity: 0;
  display: inline-block;
  transition: opacity 150ms ease;
}

.tournament-row .tourn-event-external:hover::after,
.tournament-row .tourn-event-external:focus-visible::after {
  opacity: 1;
}

/* Keyboard focus ring — the winner-name link next door gets implicit
   focus via the browser default; this link deserves the same visibility
   so keyboard users can see where Tab landed above the stretched-link
   overlay. Matches the focus treatment used on other accent links. */
.tournament-row .tourn-event-external:focus-visible {
  outline: 1px solid color-mix(in oklch, var(--accent) 60%, transparent);
  outline-offset: 2px;
  border-radius: 3px;
  color: var(--accent);
}

.tourn-date {
  font-family: var(--font-data);
  font-size: 11px;
  color: var(--text-tertiary);
}

.format-label {
  font-family: var(--font-data);
  font-size: 11px;
  color: var(--text-tertiary);
  margin-left: 4px;
}

.tourn-rating {
  font-family: var(--font-data);
  font-size: 13px;
  font-weight: 700;
  color: var(--accent);
}

/* ============================================================
   BADGES (tier indicators — matches Pencil Tag components)
   ============================================================ */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  border-radius: 4px;
  font-family: var(--font-data);
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
  line-height: 1;
}

.badge--planetary      { color: var(--tier-planetary); background: rgba(34, 197, 94, 0.2); }
.badge--store_showdown { color: var(--text-secondary); background: rgba(148, 163, 184, 0.15); }
.badge--sector         { color: var(--tier-sector);    background: rgba(245, 158, 11, 0.2); }
.badge--regional       { color: var(--tier-regional);  background: var(--accent-mid); }
.badge--galactic       { color: var(--tier-galactic);  background: rgba(124, 58, 237, 0.2); }

/* ============================================================
   BREADCRUMB (profile page)
   ============================================================ */

.breadcrumb {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 24px;
}

.breadcrumb-link {
  font-size: 13px;
  color: var(--accent);
}

.breadcrumb-sep {
  font-size: 13px;
  color: var(--text-tertiary);
}

.breadcrumb-current {
  font-size: 13px;
  color: var(--text-secondary);
}

/* ============================================================
   PROFILE NAME
   ============================================================ */

.profile-name {
  font-family: var(--font-display);
  font-size: clamp(32px, 3.5vw, 44px);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: -0.025em;
  color: var(--text-primary);
  margin: 0;
}

.profile-name a {
  color: inherit;
}

.profile-name a:hover {
  color: var(--accent);
}

.profile-username {
  font-family: var(--font-data);
  font-size: 18px;
  font-weight: 400;
  color: var(--text-tertiary);
  letter-spacing: 0;
}

.profile-meta {
  display: flex;
  align-items: center;
  gap: 12px;
}

.rank-badge {
  font-family: var(--font-data);
  font-size: 11px;
  font-weight: 600;
  color: var(--text-secondary);
  background: var(--card);
  border: 1px solid var(--border);
  padding: 2px 8px;
  border-radius: 4px;
  letter-spacing: 0.02em;
}

.rank-badge--unranked {
  color: var(--text-tertiary);
}

/* Format qualifier appended to the rank (e.g. "Rank #1 Premier"). Slightly
   softer than the rank number itself so "#1" stays the headline and
   "Premier" reads as context. Uses currentColor inheritance so it tints
   through on gold/silver/bronze medal badges. */
.rank-badge__qualifier {
  font-weight: 400;
  opacity: 0.72;
}

/* Podium medals for ranks 1-3. The design system already defines the tokens
   (DESIGN.md §Rank medals) and the leaderboard table uses them via inline
   case. Only #1 earns a glow — silver and bronze are color-only so the
   accent budget stays reserved for gold. */
.rank-badge--gold {
  color: var(--rank-gold);
  border-color: color-mix(in oklch, var(--rank-gold) 45%, var(--border));
  box-shadow: 0 0 12px color-mix(in oklch, var(--rank-gold) 18%, transparent);
}

.rank-badge--silver {
  color: var(--rank-silver);
}

.rank-badge--bronze {
  color: var(--rank-bronze);
}

/* Compact variant for the per-format ranks inside the hero stat strip.
   Sits as its own line below the ±RD note so the format's headline rating
   stays the dominant element, but the rank gets the same badge treatment
   as the Overall rank chip above the hero. */
.rank-badge--format {
  align-self: flex-start;
  margin-top: 4px;
  font-size: 10px;
  padding: 2px 6px;
}


/* ============================================================
   PROFILE HERO — name + rank + dominant rating + stat-strip,
   all in one card so a player's vitals read as a single unit.
   ============================================================ */

.profile-hero {
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
  padding: 18px 22px 20px;
  margin-bottom: 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
}

/* Anchor name + big rating number on a shared first baseline so the two
   hero elements read as one horizontal line. Subordinate info (rank-badge
   under name, caption + delta under number) stacks below each without
   competing with the headline row. */
.profile-hero__top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
}

.profile-hero__id {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.profile-hero__rank { display: inline-flex; }

.profile-hero__rating {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--space-2xs);
  text-align: right;
  flex-shrink: 0;
}

/* Caption row — format label · ±CI · confidence %, all inline. Reads as
   a scoreboard subtitle under the big rating number rather than three
   separate stacked stats competing for vertical real estate. */
.profile-hero__caption {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  flex-wrap: wrap;
  justify-content: flex-end;
  margin-top: var(--space-2xs);
  font-family: var(--font-data);
  font-size: 12px;
  color: var(--text-tertiary);
}

.profile-hero__caption-sep {
  color: var(--text-tertiary);
  opacity: 0.5;
}

.profile-hero__label {
  font-family: var(--font-data);
  font-size: 11px;
  font-weight: 500;
  color: var(--text-tertiary);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.profile-hero__number {
  font-family: var(--font-data);
  font-size: 48px;
  font-weight: 700;
  color: var(--accent);
  line-height: 1;
  text-shadow: 0 0 16px var(--accent-glow);
  letter-spacing: -0.02em;
}

.profile-hero__number--muted {
  font-family: var(--font-data);
  font-size: 36px;
  color: var(--text-secondary);
  text-shadow: none;
  letter-spacing: normal;
}

.profile-hero__conf {
  font-family: var(--font-data);
  font-size: 12px;
  color: var(--text-tertiary);
}

.profile-hero__conf.confidence-badge {
  border-bottom: 1px dotted var(--text-tertiary);
}

/* Last-event pill. Reads like a stock ticker: sign + magnitude carries the
   whole message. Subordinate to the rating number but louder than the
   confidence % that sits above it — 13px vs 11px — because "what just moved"
   is the primary persona's job-to-be-done. Clicking deep-links to the
   per-tournament audit view. */
.profile-hero__delta {
  display: inline-flex;
  align-items: baseline;
  gap: 0;
  margin-top: 6px;
  font-family: var(--font-data);
  font-size: 13px;
  font-weight: 600;
  font-feature-settings: "tnum";
  line-height: 1;
  text-decoration: none;
  letter-spacing: 0.01em;
}

.profile-hero__delta:hover { filter: brightness(1.15); }

.profile-hero__delta--up    { color: var(--positive); }
.profile-hero__delta--down  { color: var(--negative); }
.profile-hero__delta--flat  { color: var(--text-tertiary); }

.profile-hero__delta-format {
  color: var(--text-secondary);
  font-weight: 500;
}

.profile-hero__delta-sep {
  color: var(--text-tertiary);
  font-weight: 400;
}

/* Context line — tournament name + date. Truncates long event names so the
   hero never wraps past two lines. The full name is available on hover via
   the link's title attribute. */
.profile-hero__delta-meta {
  display: block;
  max-width: 240px;
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-body);
  font-size: 11px;
  color: var(--text-tertiary);
  text-align: right;
}

.profile-hero__delta-meta-link {
  color: var(--text-secondary);
  text-decoration: none;
}

.profile-hero__delta-meta-link:hover { color: var(--accent); }

/* Stat-strip lives inside the hero card under the big rating. Tabular
   mono numerals so columns of digits line up between players. Top divider
   reads as a horizontal rule between the hero and the stat row. */
.profile-hero__stats {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 12px 18px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

.hero-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.hero-stat__label {
  font-family: var(--font-data);
  font-size: 10px;
  font-weight: 500;
  color: var(--text-tertiary);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.hero-stat__value {
  font-family: var(--font-data);
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
  font-feature-settings: "tnum";
  line-height: 1.1;
}

.hero-stat__value--muted {
  color: var(--text-tertiary);
  font-weight: 400;
}

.hero-stat__note {
  font-family: var(--font-data);
  font-size: 10px;
  color: var(--text-tertiary);
}

@media (max-width: 768px) {
  .profile-hero { padding: 14px 16px 16px; }
  .profile-hero__number { font-size: 40px; }
  .profile-hero__stats { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ============================================================
   PER-PLAYER PER-TOURNAMENT AUDIT HERO
   ============================================================ */

.audit-hero {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  padding-bottom: 20px;
  margin-bottom: 20px;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}

.audit-hero__title { flex: 1; min-width: 0; }

.audit-hero__meta {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 8px;
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-tertiary);
}

.audit-hero__date { color: var(--text-secondary); }
.audit-hero__record .data { color: var(--text-primary); font-weight: 600; }

.audit-hero__delta {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-shrink: 0;
}

.audit-hero__rating {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
}

.audit-hero__label {
  font-family: var(--font-data);
  font-size: 10px;
  font-weight: 500;
  color: var(--text-tertiary);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.audit-hero__number {
  font-family: var(--font-data);
  font-size: 32px;
  font-weight: 700;
  color: var(--accent);
  line-height: 1;
  letter-spacing: -0.02em;
}

/* ============================================================
   METRIC STRIP — demoted format ratings + stats
   ============================================================ */

.metric-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 12px 20px;
  margin-bottom: 32px;
  padding: 4px 0;
}

.metric-strip__item {
  display: flex;
  align-items: baseline;
  gap: 8px;
  white-space: nowrap;
}

.metric-strip__label {
  font-family: var(--font-data);
  font-size: 11px;
  font-weight: 500;
  color: var(--text-tertiary);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.metric-strip__value {
  font-family: var(--font-data);
  font-size: 16px;
  font-weight: 600;
  color: var(--text-primary);
}

.metric-strip__value--warning { color: var(--warning); }

.metric-strip__note {
  font-family: var(--font-data);
  font-size: 11px;
  color: var(--text-tertiary);
}

.metric-strip__sep {
  width: 1px;
  height: 16px;
  background: var(--border);
  align-self: center;
}

/* ============================================================
   SECTION HEADER
   ============================================================ */

.section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
  margin-top: 32px;
}

.heading-lg {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 600;
  color: var(--text-primary);
}

/* ============================================================
   PAGINATION
   ============================================================ */

.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding-top: 16px;
}

.page-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 36px;
  height: 36px;
  border-radius: 6px;
  background: var(--card);
  border: 1px solid var(--border);
  font-family: var(--font-data);
  font-size: 13px;
  color: var(--text-secondary);
  text-decoration: none;
  transition: all 0.15s ease;
}

.page-btn:hover {
  border-color: var(--accent);
  color: var(--text-primary);
}

.page-btn--active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--bg);
  font-weight: 600;
}

.page-dots {
  color: var(--text-tertiary);
  font-size: 13px;
}

/* ============================================================
   FOOTER NOTE
   ============================================================ */

.footer-note {
  font-family: var(--font-data);
  font-size: 11px;
  color: var(--text-tertiary);
  text-align: center;
  padding-top: 12px;
  margin-top: 20px;
}

/* ============================================================
   ABOUT / HOW IT WORKS PAGE
   ============================================================ */

.about-page { max-width: 1200px; margin: 0 auto; }

.about-title {
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 16px;
  letter-spacing: -0.01em;
}

/* System Health callout — the clamp-rate receipt, pulled up to the top of
   the page so the system's self-check is visible before the reader commits
   to 2,400 words of methodology. Mono numerals, tertiary framing, one
   dominant percentage with a tooltip for the raw counts. */
.about-health {
  display: grid;
  grid-template-columns: auto auto 1fr;
  gap: 16px 20px;
  align-items: baseline;
  padding: 14px 18px;
  margin-bottom: 40px;
  background: color-mix(in oklch, var(--accent) 6%, var(--card));
  border: 1px solid color-mix(in oklch, var(--accent) 22%, var(--border));
  border-radius: 8px;
  max-width: 68ch;
}

.about-health__label {
  font-family: var(--font-data);
  font-size: 10px;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.about-health__value {
  font-family: var(--font-data);
  font-size: 20px;
  font-weight: 700;
  color: var(--accent);
  font-feature-settings: "tnum";
  cursor: help;
}

.about-health__desc {
  font-size: 12px;
  color: var(--text-secondary);
  line-height: 1.6;
  grid-column: 1 / -1;
}

.about-health__desc strong { color: var(--text-primary); }

@media (max-width: 768px) {
  .about-health {
    grid-template-columns: auto 1fr;
  }
  .about-health__label { grid-column: 1; }
  .about-health__value { grid-column: 2; justify-self: end; }
}

/* Two-column layout on desktop: sticky TOC left, main content right. Mobile
   drops back to single column and the TOC is hidden — deep-linking from
   tooltips still works via the anchor IDs on each section. */
.about-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
}

.about-content { min-width: 0; max-width: 800px; }

.about-toc { display: none; }

@media (min-width: 1024px) {
  .about-layout {
    grid-template-columns: 220px minmax(0, 1fr);
    gap: 48px;
  }
  .about-toc {
    display: block;
    position: sticky;
    top: 80px;
    align-self: start;
    max-height: calc(100vh - 100px);
    overflow-y: auto;
  }
}

.about-toc-heading {
  font-family: var(--font-data);
  font-size: 10px;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin: 0 0 12px;
}

.about-toc-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.about-toc-list a {
  display: block;
  padding: 5px 10px;
  font-family: var(--font-data);
  font-size: 12px;
  color: var(--text-secondary);
  text-decoration: none;
  border-radius: 4px;
  transition: color 150ms ease, background-color 150ms ease;
}

.about-toc-list a:hover {
  color: var(--accent);
  background: color-mix(in oklch, var(--accent) 8%, transparent);
}

.about-toc-list a:focus-visible {
  outline: 1px solid color-mix(in oklch, var(--accent) 50%, transparent);
  outline-offset: 2px;
}

/* Anchor-jump offset so clicked section headings land below the sticky
   site nav (56px desktop, 52px mobile) instead of hiding behind it.
   Vertical rhythm between sections lives here too. */
.about-section {
  scroll-margin-top: 80px;
  margin-bottom: 48px;
}

/* H3 subheading used when an H2 section has internal structure — e.g. the
   three components of Event-Weighted K-Factor. Smaller than .about-heading,
   same display font, visible hierarchy without the extra padding of a new
   section break. */
.about-subheading {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 600;
  color: var(--text-primary);
  margin: 32px 0 10px;
  letter-spacing: -0.01em;
}

.about-intro {
  font-size: 16px;
  color: var(--text-secondary);
  line-height: 1.7;
  margin-bottom: 20px;
  max-width: 68ch;
}

.about-intro:last-of-type { margin-bottom: 40px; }

.about-intro strong { color: var(--text-primary); }

/* Second intro beat — the technical sentence for the analyst persona who
   skipped the first-timer welcome. Slightly quieter so the welcoming
   first beat stays dominant. */
.about-intro--technical {
  font-size: 15px;
  color: var(--text-tertiary);
}

.about-intro--technical strong { color: var(--text-secondary); }

.about-heading {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 12px;
}

.about-text {
  font-size: 16px;
  color: var(--text-secondary);
  line-height: 1.7;
  margin-bottom: 16px;
  max-width: 68ch;
}

.about-text strong { color: var(--text-primary); }
.about-text a { color: var(--accent); }
.about-text--muted { color: var(--text-tertiary); font-size: 13px; margin-top: 12px; }

/* Inline accent link used in prose paragraphs (changelog, about-intro). */
.inline-link {
  color: var(--accent);
  border-bottom: 1px solid transparent;
  transition: border-color 150ms ease, color 150ms ease;
}
.inline-link:hover {
  color: var(--accent-hover);
  border-bottom-color: var(--accent-hover);
}

/* Info cards */
.about-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}

.about-card-row {
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
}

.about-card-row:last-child { border-bottom: none; }

.about-card-label {
  font-family: var(--font-data);
  font-size: 11px;
  font-weight: 500;
  color: var(--text-tertiary);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 6px;
}

.about-card-value {
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 4px;
  letter-spacing: -0.01em;
}

.about-card-desc {
  font-size: 13px;
  color: var(--text-secondary);
  line-height: 1.6;
}

/* Numbered factors */
.about-factors {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.about-factor {
  display: flex;
  gap: 16px;
  align-items: flex-start;
}

.about-factor-num {
  width: 36px;
  height: 36px;
  border-radius: 8px;
  background: var(--card);
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-data);
  font-size: 13px;
  font-weight: 700;
  color: var(--text-primary);
  flex-shrink: 0;
}

/* Format-code tints for the P/L/E factor chips in the Formats section.
   Each uses the tier color as background with white text for contrast. */
.about-factor-num--sector   { background: var(--tier-sector); border-color: var(--tier-sector); color: var(--text-primary); }
.about-factor-num--regional { background: var(--tier-regional); border-color: var(--tier-regional); color: var(--text-primary); }
.about-factor-num--galactic { background: var(--tier-galactic); border-color: var(--tier-galactic); color: var(--text-primary); }

.about-factor-content { flex: 1; }

.about-factor-content h3 {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 4px;
}

.about-factor-content p {
  font-size: 13px;
  color: var(--text-secondary);
  line-height: 1.6;
  max-width: 68ch;
}

/* Tier/round tables */
.about-table {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}

.about-table-header {
  display: flex;
  padding: 10px 20px;
  font-family: var(--font-data);
  font-size: 11px;
  font-weight: 500;
  color: var(--text-tertiary);
  letter-spacing: 0.5px;
  text-transform: uppercase;
  border-bottom: 1px solid var(--border);
}

.about-table-row {
  display: flex;
  padding: 12px 20px;
  align-items: center;
  border-bottom: 1px solid var(--border);
}

.about-table-row:last-child { border-bottom: none; }

.about-table-col-tier { width: 140px; flex-shrink: 0; }
.about-table-col-val { width: 100px; flex-shrink: 0; font-weight: 600; color: var(--accent); }

/* Highlighted multiplier values — replaces inline style="color: var(--warning);"
   on the Putting-It-All-Together rows that call out finals-winner totals. */
.about-table-col-val--highlight { color: var(--warning); }
.about-table-col-val--champion  { color: var(--warning); font-weight: 700; }

/* The single "Galactic Finals (champion)" callout row — the one match worth
   the most in the system. Warm tint + slightly heavier border to match its
   semantic weight. Replaces an inline background style. */
.about-table-row--champion {
  background: color-mix(in oklch, var(--warning) 8%, transparent);
}

/* Labeled-list modifier tints for the Qualifying Events card. Replaces
   inline color styles on the Included / Excluded labels. */
.about-card-label--positive { color: var(--positive); }
.about-card-label--muted    { color: var(--text-tertiary); }
.about-table-col-desc { flex: 1; font-size: 13px; color: var(--text-secondary); }

/* Worked example — the one place on the page where the math is walked
   end-to-end instead of stated as a formula. Stepped numbered blocks
   so the reader can follow the order of operations visually. */
.about-example {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 24px;
}

.about-example__setup {
  font-size: 14px;
  color: var(--text-secondary);
  line-height: 1.7;
  margin: 0 0 24px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--border);
}

.about-example__steps {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.about-example__step {
  display: flex;
  gap: 16px;
  align-items: flex-start;
}

.about-example__step-num {
  width: 28px;
  height: 28px;
  border-radius: 14px;
  background: color-mix(in oklch, var(--accent) 18%, var(--card));
  border: 1px solid color-mix(in oklch, var(--accent) 35%, var(--border));
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-data);
  font-size: 12px;
  font-weight: 700;
  color: var(--accent);
  flex-shrink: 0;
  margin-top: 1px;
}

.about-example__step-body { flex: 1; min-width: 0; }

.about-example__step-heading {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  margin: 0 0 4px;
  letter-spacing: -0.005em;
}

.about-example__step-body p {
  font-size: 13px;
  color: var(--text-secondary);
  line-height: 1.7;
  margin: 0;
}

.about-example__step-body code {
  font-family: var(--font-data);
  font-size: 12px;
  background: color-mix(in oklch, var(--accent) 10%, transparent);
  color: var(--text-primary);
  padding: 1px 5px;
  border-radius: 3px;
}

/* ============================================================
   CHANGELOG — reverse-chronological entry list with sticky version
   sidebar. Shares the .content-area.about-page wrapper with how-it-works
   and inherits .about-title / .about-intro typography.
   ============================================================ */

.changelog-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
}

@media (min-width: 1024px) {
  .changelog-layout {
    grid-template-columns: 180px minmax(0, 1fr);
    gap: 48px;
  }
  .changelog-toc {
    position: sticky;
    top: 80px;
    align-self: start;
    max-height: calc(100vh - 100px);
    overflow-y: auto;
  }
}

.changelog-toc { display: none; }
@media (min-width: 1024px) { .changelog-toc { display: block; } }

.changelog-toc__heading {
  font-family: var(--font-data);
  font-size: 10px;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin: 0 0 12px;
}

.changelog-toc__list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.changelog-toc__link {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 10px;
  border-radius: 4px;
  text-decoration: none;
  color: var(--text-secondary);
  transition: color 150ms ease, background-color 150ms ease;
}

.changelog-toc__link:hover {
  color: var(--accent);
  background: color-mix(in oklch, var(--accent) 8%, transparent);
}

.changelog-toc__link:focus-visible {
  outline: 1px solid color-mix(in oklch, var(--accent) 50%, transparent);
  outline-offset: 2px;
}

.changelog-toc__version {
  font-family: var(--font-data);
  font-size: 13px;
  font-weight: 600;
}

.changelog-toc__date {
  font-family: var(--font-data);
  font-size: 10px;
  color: var(--text-tertiary);
}

.changelog-toc__link--current .changelog-toc__version {
  color: var(--accent);
}

.changelog-content { min-width: 0; max-width: 800px; }

.changelog-entries {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.changelog-entry {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 20px 24px 24px;
  scroll-margin-top: 80px;
  transition: border-color 150ms ease;
}

.changelog-entry:hover {
  border-color: color-mix(in oklch, var(--accent) 20%, var(--border));
}

.changelog-entry:target,
.changelog-entry--current {
  border-color: color-mix(in oklch, var(--accent) 40%, var(--border));
}

.changelog-entry:target .changelog-entry__permalink,
.changelog-entry:hover .changelog-entry__permalink {
  opacity: 1;
}

.changelog-entry__header {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}

.changelog-entry__meta {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

.changelog-entry__version {
  font-family: var(--font-data);
  font-size: 18px;
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: -0.01em;
}

/* Current version gets the accent color as the signal. No glow — glow is
   reserved for the rating hero, #1 rank, table rating cells, and the
   Galactic tier badge (see DESIGN.md glow-restraint principle). The
   paired "Live" tag on the same row carries the freshness signal. */
.changelog-entry--current .changelog-entry__version {
  color: var(--accent);
}

.changelog-entry__date {
  font-family: var(--font-data);
  font-size: 11px;
  color: var(--text-tertiary);
  letter-spacing: 0.04em;
}

.changelog-entry__badges {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
}

/* Small tags categorizing each change. "Rating change" is positive-tinted
   because that's the signal a player cares about when scanning the list.
   Engine / Display are neutral. "Live" is the top-version marker. */
.changelog-entry__tag {
  font-family: var(--font-data);
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 3px 8px;
  border-radius: 3px;
  border: 1px solid currentColor;
  white-space: nowrap;
}

.changelog-entry__tag--rating {
  color: var(--positive);
  background: color-mix(in oklch, var(--positive) 10%, transparent);
}

.changelog-entry__tag--engine {
  color: var(--text-secondary);
  background: transparent;
}

.changelog-entry__tag--display {
  color: var(--text-tertiary);
  background: transparent;
}

.changelog-entry__tag--current {
  color: var(--accent);
  background: color-mix(in oklch, var(--accent) 12%, transparent);
  border-color: color-mix(in oklch, var(--accent) 40%, var(--border));
}

.changelog-entry__permalink {
  font-family: var(--font-data);
  font-size: 16px;
  font-weight: 400;
  color: var(--text-tertiary);
  text-decoration: none;
  opacity: 0;
  transition: opacity 150ms ease, color 150ms ease;
  padding: 0 4px;
}

.changelog-entry__permalink:hover {
  opacity: 1;
  color: var(--accent);
}

/* Keyboard focus: reveal the glyph AND show a visible ring so the tab
   stop is discoverable. Matches the :focus-visible pattern used by
   `.th-date__sort` and `.about-faq-q` elsewhere in this file. */
.changelog-entry__permalink:focus-visible {
  opacity: 1;
  color: var(--accent);
  outline: 1px solid color-mix(in oklch, var(--accent) 60%, transparent);
  outline-offset: 2px;
  border-radius: 3px;
}

.changelog-entry__body {
  font-size: 14px;
  line-height: 1.7;
  color: var(--text-secondary);
}

.changelog-entry__headline {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 600;
  color: var(--text-primary);
  margin: 0 0 10px;
  letter-spacing: -0.005em;
}

.changelog-entry__prose {
  margin: 0;
}

.changelog-entry__prose code {
  font-family: var(--font-data);
  font-size: 12px;
  background: color-mix(in oklch, var(--accent) 8%, transparent);
  color: var(--text-primary);
  padding: 1px 5px;
  border-radius: 3px;
}

/* Mobile: tags stack below the version+date row when screen is narrow */
@media (max-width: 640px) {
  .changelog-entry__badges { margin-left: 0; }
  .changelog-entry__permalink { display: none; }
}

/* FAQ — native <details> disclosures. Collapsed by default so the 8-item
   block reads as a scannable index of questions; clicking any one opens
   just that answer. No JS, no ARIA, no state management. */
.about-faq {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0;
  margin-bottom: 8px;
  transition: border-color 150ms ease;
}

.about-faq[open] {
  border-color: color-mix(in oklch, var(--accent) 35%, var(--border));
}

.about-faq-q {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 16px 20px;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
  cursor: pointer;
  list-style: none;
  transition: color 150ms ease;
}

.about-faq-q::-webkit-details-marker { display: none; }

.about-faq-q::after {
  content: "+";
  margin-left: auto;
  font-family: var(--font-data);
  font-size: 18px;
  font-weight: 400;
  color: var(--text-tertiary);
  transition: transform 200ms ease, color 150ms ease;
}

.about-faq[open] .about-faq-q::after {
  content: "\2212"; /* minus sign */
  color: var(--accent);
}

.about-faq-q:hover { color: var(--accent); }

.about-faq-q:focus-visible {
  outline: 1px solid color-mix(in oklch, var(--accent) 50%, transparent);
  outline-offset: -1px;
  border-radius: 8px;
}

.about-faq-a {
  padding: 0 20px 18px;
  font-size: 13px;
  color: var(--text-secondary);
  line-height: 1.7;
  margin: 0;
}

.about-faq-a a { color: var(--accent); }

/* ============================================================
   RESPONSIVE
   ============================================================ */

@media (max-width: 1024px) {
  .content-area { padding: 24px 32px 32px; }
  .hero-section { padding: 36px 32px 28px; gap: 20px 28px; }
  .hero-section::after { left: 32px; right: 32px; }
  .hero-logo { height: 112px; }
  .hero-title { font-size: 32px; }
  .hero-sub { font-size: 14px; }
  .global-stats { gap: 20px; margin-left: 0; }
  .global-stat__value { font-size: 20px; }
  .global-stat { min-width: 80px; }
  .rank-confidence, .th-confidence { display: none; }
  .filter-row .search-input { width: 320px; max-width: 320px; }
}

@media (max-width: 640px) {
  .content-area { padding: 20px 16px 24px; }
  .hero-section { padding: 28px 16px 22px; gap: 18px 20px; flex-direction: column; text-align: center; align-items: center; }
  .hero-section::after { left: 16px; right: 16px; }
  .hero-logo { height: 96px; }
  .hero-lockup { align-items: center; }
  .hero-title { font-size: 26px; text-align: center; }
  .hero-sub { font-size: 13px; text-align: center; }
  .global-stats { flex-wrap: wrap; justify-content: center; gap: 14px 20px; margin-left: 0; }
  .global-stat { min-width: auto; align-items: center; }
  .global-stat__value { font-size: 18px; }
  .hero-divider { display: none; }

  .filter-row {
    flex-direction: column;
    align-items: stretch;
  }
  .filter-row .search-input { width: 100%; max-width: none; }
  .filter-chips { flex-wrap: wrap; }

  /* Hide desktop column headers on mobile — rows use stacked layout instead */
  .table-header .th-record,
  .table-header .th-winrate,
  .table-header .th-events,
  .table-header .th-confidence,
  .table-header .th-tier,
  .table-header .th-date,
  .table-header .th-format,
  .table-header .th-players,
  .table-header .th-winner,
  .table-header .th-delta { display: none; }

  /* Leaderboard row becomes a 2-line card */
  .rank-row {
    flex-wrap: wrap;
    height: auto;
    min-height: 64px;
    padding: 10px 16px;
    row-gap: 6px;
    column-gap: 12px;
  }
  /* Mobile: left-align so rank hugs the left edge and sits naturally before
     the player name. Wider than desktop's 72px isn't needed here since the
     row-gap of the wrapping flex keeps rank and name separated. 56px fits
     5 digits at 16px Geist Mono Bold with a touch of room. */
  .rank-num { width: 56px; padding-right: 8px; text-align: left; }
  .rank-player { flex: 1; min-width: 0; }
  .rank-rating { width: auto; text-align: right; }

  .rank-meta {
    display: flex;
    flex-basis: 100%;
    align-items: baseline;
    gap: 12px;
    font-size: 11px;
    color: var(--text-tertiary);
  }
  .rank-meta > span {
    width: auto;
    text-align: left;
    font-size: 11px;
    color: var(--text-tertiary);
  }
  .rank-meta .rank-winrate { font-weight: 600; }
  .rank-meta .rank-record::before { content: "W-L "; color: var(--text-tertiary); opacity: 0.7; }
  .rank-meta .rank-events::before { content: "Events "; color: var(--text-tertiary); opacity: 0.7; }
  .rank-meta .confidence-badge { font-size: 11px; color: var(--text-tertiary); }

  /* Tournament row becomes a 2-line card */
  .tourn-row {
    flex-wrap: wrap;
    height: auto;
    min-height: 60px;
    padding: 10px 16px;
    row-gap: 6px;
    column-gap: 12px;
    align-items: baseline;
  }
  .tourn-event { flex: 1; min-width: 0; }

  .tourn-meta {
    display: flex;
    flex-basis: 100%;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 6px 12px;
    font-size: 11px;
    color: var(--text-tertiary);
  }
  .tourn-meta > * {
    width: auto;
    text-align: left;
  }
  .tourn-meta .tourn-rating { font-size: 13px; }
  .tourn-meta .tourn-delta { margin-left: auto; }

  /* Tournaments index row (.rank-row.tournament-row): on mobile the event
     name takes a full-width first line, then tier/format/players/winner/
     date wrap beneath as a compact meta strip. Without this, the fixed-
     width columns flow awkwardly and the tier badge jams into the middle
     of a wrapping event name. */
  .tournament-row {
    flex-wrap: wrap;
    height: auto;
    min-height: 68px;
    padding: 10px 16px;
    row-gap: 6px;
    column-gap: 10px;
    align-items: baseline;
  }
  .tournament-row .tourn-event {
    flex-basis: 100%;
    width: 100%;
  }
  .tournament-row .tourn-tier,
  .tournament-row .tourn-format,
  .tournament-row .tourn-players,
  .tournament-row .tourn-winner,
  .tournament-row .tourn-date {
    width: auto;
    text-align: left;
    font-size: 12px;
  }
  .tournament-row .tourn-format,
  .tournament-row .tourn-players,
  .tournament-row .tourn-date {
    color: var(--text-tertiary);
  }
  .tournament-row .tourn-winner { margin-left: auto; }
  .tournament-row .tourn-players::after { content: " players"; opacity: 0.7; }

  .profile-hero {
    flex-direction: column;
    align-items: flex-start;
    gap: 16px;
  }
  .profile-hero__rating {
    align-items: flex-start;
    text-align: left;
  }
  .profile-hero__number { font-size: 40px; }
  .profile-hero__number--muted { font-size: 30px; }
  .profile-hero__delta-meta { text-align: left; }

  .metric-strip { gap: 8px 16px; }
  .metric-strip__sep { display: none; }

  .site-nav { padding: 0 16px; height: 52px; }
  .site-logo { font-size: 16px; }
  .nav-logo-img { height: 32px; }
}

/* ============================================================
   v3 — Trust layer: cohort toggle, RD bands, credible interval
   ============================================================ */

/* Secondary filter row — sits below the format chips and search */
.filter-row--secondary {
  margin-top: 12px;
  margin-bottom: 8px;
}

/* Overall format is experimental — visually muted so players prefer per-format */
.chip--experimental {
  opacity: 0.75;
  font-style: italic;
}

.chip--experimental.chip--active { opacity: 1; font-style: normal; }

/* Ranked / Provisional cohort toggle */
.cohort-toggle {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--card);
  padding: 4px;
}

.cohort-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border-radius: 4px;
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 500;
  color: var(--text-tertiary);
  cursor: pointer;
  transition: all 0.15s ease;
}

.cohort-chip:hover { color: var(--text-primary); }

.cohort-chip--active {
  background: var(--accent-surface);
  color: var(--accent);
  font-weight: 600;
}

.cohort-count {
  font-family: var(--font-data);
  font-size: 11px;
  color: var(--text-tertiary);
  background: var(--bg);
  padding: 1px 6px;
  border-radius: 10px;
  min-width: 18px;
  text-align: center;
}

.cohort-chip--active .cohort-count {
  background: var(--accent-soft);
  color: var(--accent);
}

/* Rating cell — number inherits typography from .rank-rating parent;
   only .rank-rating__ci below needs its own override for the smaller,
   dimmer ± credible-interval span. The .rank-row--provisional override
   further down still targets .rank-rating__number by class name to
   desaturate the number in provisional rows. */
.rank-rating__ci {
  font-family: var(--font-data);
  font-size: 11px;
  font-weight: 400;
  color: var(--text-tertiary);
  margin-left: 6px;
  cursor: help;
}

/* Champion rating — earned glow for the #1 player on any format's
   leaderboard. All rank ratings default to accent blue, so color alone
   isn't the differentiator; the champion gets a two-layer glow + bumped
   weight so the #1 number reads as "THE number." One row per page earns
   this. Matches the tournament-show champion pedestal treatment. */
.rank-rating__number--champion {
  font-weight: 800;
  text-shadow: 0 0 14px var(--accent-hot), 0 0 4px var(--accent-strong);
}

/* Provisional row — visually quieter on the ranked leaderboard if one slips
   in, and always on the Provisional tab. 0.82 was almost imperceptible
   against the already-dim palette; 0.65 actually reads as "still stabilizing"
   at a glance. Accent color loses its glow treatment. Hover restores to full
   so the row is still scannable on intent. */
.rank-row--provisional { opacity: 0.65; }
.rank-row--provisional .rank-rating__number { color: var(--text-secondary); }
.rank-row--provisional:hover { opacity: 1; }

/* ============================================================
   STYLED TOOLTIPS — replaces native title="" on data/help elements.
   Usage: <span class="has-tooltip" data-tooltip="Full sentence here">78%</span>
   Supports an optional position hint via data-tooltip-pos="left|right|bottom".
   Default anchor: above the element, center-aligned.
   ============================================================ */

.has-tooltip {
  position: relative;
  cursor: help;
}

.has-tooltip::before,
.has-tooltip::after {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease, transform 0.15s ease;
  z-index: 300;
}

/* Tooltip body */
.has-tooltip::after {
  content: attr(data-tooltip);
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-primary);
  padding: 10px 14px;
  border-radius: 6px;
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 400;
  line-height: 1.55;
  letter-spacing: 0.005em;
  text-align: left;
  text-transform: none;
  width: max-content;
  max-width: 320px;
  white-space: normal;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.55);
}

/* Caret */
.has-tooltip::before {
  content: "";
  bottom: calc(100% + 4px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  border: 6px solid transparent;
  border-top-color: var(--border);
  width: 0;
  height: 0;
}

.has-tooltip:hover::before,
.has-tooltip:hover::after,
.has-tooltip:focus-visible::before,
.has-tooltip:focus-visible::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* Right-anchor variant — for tooltips near the left edge */
.has-tooltip[data-tooltip-pos="right"]::after,
.has-tooltip[data-tooltip-pos="right"]::before {
  left: auto;
  right: 0;
  transform: translateX(0) translateY(4px);
}
.has-tooltip[data-tooltip-pos="right"]::before { right: 10px; }
.has-tooltip[data-tooltip-pos="right"]:hover::after,
.has-tooltip[data-tooltip-pos="right"]:hover::before { transform: translateX(0) translateY(0); }

/* Left-anchor variant — for tooltips near the right edge (leaderboard Confidence column) */
.has-tooltip[data-tooltip-pos="left"]::after,
.has-tooltip[data-tooltip-pos="left"]::before {
  left: 0;
  right: auto;
  transform: translateX(0) translateY(4px);
}
.has-tooltip[data-tooltip-pos="left"]::before { left: 10px; }
.has-tooltip[data-tooltip-pos="left"]:hover::after,
.has-tooltip[data-tooltip-pos="left"]:hover::before { transform: translateX(0) translateY(0); }

/* Bottom-anchor — for tooltips that would clip off the top of the viewport */
.has-tooltip[data-tooltip-pos="bottom"]::after {
  bottom: auto;
  top: calc(100% + 10px);
  transform: translateX(-50%) translateY(-4px);
}
.has-tooltip[data-tooltip-pos="bottom"]::before {
  bottom: auto;
  top: calc(100% + 4px);
  border-top-color: transparent;
  border-bottom-color: var(--border);
  transform: translateX(-50%) translateY(-4px);
}
.has-tooltip[data-tooltip-pos="bottom"]:hover::after,
.has-tooltip[data-tooltip-pos="bottom"]:hover::before { transform: translateX(-50%) translateY(0); }

/* Confidence percentage — leaderboard + profile. Hover reveals raw RD.
   Tier colors come from rd_band so a glance still tells you if a rating
   is established/developing/provisional, but the number is the data. */
.confidence-pct {
  display: inline-flex;
  align-items: baseline;
  font-family: var(--font-data);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text-secondary);
  cursor: help;
}

.confidence-pct--established { color: var(--positive); }
.confidence-pct--developing  { color: var(--warning); }
.confidence-pct--provisional { color: var(--text-tertiary); }

/* RD-band badges — retained for any lingering view usage */
.band-badge {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 10px;
  border: 1px solid transparent;
  cursor: help;
}

.band-badge--established {
  color: var(--positive);
  background: rgba(34, 197, 94, 0.08);
  border-color: rgba(34, 197, 94, 0.25);
}

.band-badge--developing {
  color: var(--warning);
  background: rgba(245, 158, 11, 0.08);
  border-color: rgba(245, 158, 11, 0.25);
}

.band-badge--provisional {
  color: var(--text-tertiary);
  background: rgba(148, 163, 184, 0.08);
  border-color: rgba(148, 163, 184, 0.2);
}

/* Provisional banner on profile pages */
.provisional-banner {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 16px;
  margin-bottom: 20px;
  background: rgba(245, 158, 11, 0.06);
  border: 1px solid rgba(245, 158, 11, 0.25);
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  font-size: 13px;
  line-height: 1.5;
}

.provisional-banner strong { color: var(--warning); font-weight: 600; }

/* Calm informational banner — tiny data, separate-format context, etc.
   Accent-blue tint instead of the warning-amber provisional banner. */
.format-notice {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 8px;
  padding: 10px 16px;
  margin-bottom: 20px;
  background: var(--accent-wash);
  border: 1px solid var(--accent-mid);
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  font-size: 13px;
  line-height: 1.5;
}

.format-notice strong {
  color: var(--accent);
  font-weight: 600;
}

/* Plain-English explainer inside each tournament dropdown on the profile page.
   Answers the community question "why did I get 0 points / so few points at
   a big tournament?" The label sits above the sentence in Geist Mono caps
   so it reads as a data row header, not a generic blurb. */
/* "Why Your Rating Moved" callout — warm amber instead of accent blue so
   it reads as an *insight* layer rather than competing with the site's
   primary accent. Amber = "pay attention, this is annotation," not
   "earned signal." Keeps the brand's accent budget reserved for ratings,
   rankings, and glow treatments. */
.tourn-explainer {
  margin: 0;
  padding: var(--space-sm) var(--space-md);
  background: rgba(245, 158, 11, 0.07);
  border-left: 2px solid var(--warning);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

.tourn-explainer__label {
  display: block;
  font-family: var(--font-data);
  font-size: 10px;
  font-weight: 700;
  color: var(--warning);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: var(--space-2xs);
}

.tourn-explainer__text {
  margin: 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--text-secondary);
}

/* Small persistent caption explaining the leaderboard sort order. Community
   feedback: players kept asking "why is Bobby above FAME when FAME has a
   higher rating?" — because we sort by the lower bound of the 95% CI, not
   the raw number. Caption lives right above the table so it's in scope
   whenever someone is scanning ranks. */
.sort-caption {
  font-size: 12px;
  color: var(--text-tertiary);
  margin: 6px 0 14px;
  line-height: 1.5;
}

.sort-caption code {
  font-family: var(--font-data);
  font-size: 12px;
  color: var(--text-secondary);
  background: none;
  padding: 0;
}

.sort-caption a {
  color: var(--text-secondary);
  border-bottom: 1px dotted currentColor;
  text-decoration: none;
}

.sort-caption a:hover { color: var(--accent); }

/* Admin surfaces (anomaly review, etc). Intentionally understated — these
   aren't end-user pages, so we lean on the same table/form primitives as
   the main app rather than building a second visual language. */
.admin-count {
  font-family: var(--font-data);
  font-size: 12px;
  color: var(--text-tertiary);
}

.admin-filter-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  align-items: flex-end;
  margin: 12px 0 20px;
  padding: 12px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

.admin-filter-row label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--text-tertiary);
}

.admin-filter-row input,
.admin-filter-row select {
  font-family: var(--font-data);
  font-size: 13px;
  color: var(--text-primary);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 6px 8px;
  min-width: 110px;
}

.admin-filter-row button {
  border: none;
  cursor: pointer;
  padding: 7px 14px;
}

/* Tournament detail page ─────────────────────────────────────────────── */

/* Cap show-page content width to match /tournaments index (1280px). Keeps
   both tournament views optically aligned on wide monitors — bracket and
   shift table stop running to the far edge where rows become tiring to
   scan. Below 1280px the rule is a no-op, same as the index's rule. */
.tournament-show {
  max-width: 1280px;
  margin-inline: auto;
}

/* Tournament hero — three tiers: title row (name + tier badge), meta row
   (format · date · location · melee link), and a two-pedestal data block
   (Champion on the left, Field Size on the right). The pedestal gives the
   page a dominant data point that matches the site's "rating is the hero"
   principle without inventing a fake number: champion is the narrative of
   any tournament, field size is the scale. Everything else subordinates. */
.tournament-hero {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  padding: var(--space-lg) 0;
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--space-2xl);
}

.tournament-hero__title-row {
  display: flex;
  align-items: baseline;
  gap: var(--space-md);
  flex-wrap: wrap;
}

.tournament-hero__name {
  font-family: var(--font-display);
  font-size: clamp(28px, 4vw, 36px);
  font-weight: 700;
  line-height: 1.1;
  color: var(--text-primary);
  margin: 0;
  flex: 1;
  min-width: 0;
}

.tournament-hero__meta {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  flex-wrap: wrap;
  font-family: var(--font-data);
  font-size: 12px;
  color: var(--text-tertiary);
}

.tournament-hero__meta-item {
  color: var(--text-secondary);
}

.tournament-hero__meta-sep {
  color: var(--text-tertiary);
  opacity: 0.6;
}

.tournament-hero__meta-link {
  color: var(--text-tertiary);
  text-decoration: none;
  border-bottom: 1px dashed transparent;
  transition: border-color 0.15s ease, color 0.15s ease;
}

.tournament-hero__meta-link:hover,
.tournament-hero__meta-link:focus-visible {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

/* Two-pedestal data block: champion (left) + field size (right). Separator
   above pushes it visually away from the name/meta. Grid with 1fr auto lets
   the champion take available width while field size hugs the right edge. */
.tournament-hero__pedestal {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--space-xl) var(--space-2xl);
  align-items: end;
  padding-top: var(--space-md);
  margin-top: var(--space-xs);
  border-top: 1px solid var(--border);
}

.tournament-hero__pedestal-label {
  display: block;
  font-family: var(--font-data);
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--text-tertiary);
  margin-bottom: var(--space-2xs);
}

.tournament-hero__champion {
  min-width: 0;
}

.tournament-hero__champion-name {
  font-family: var(--font-data);
  font-size: clamp(22px, 3.2vw, 28px);
  font-weight: 700;
  line-height: 1.15;
  color: var(--accent);
  text-shadow: 0 0 14px var(--accent-strong);
  text-decoration: none;
  transition: text-shadow 0.15s ease;
}

.tournament-hero__champion-name:hover,
.tournament-hero__champion-name:focus-visible {
  text-shadow: 0 0 22px var(--accent-hot);
}

.tournament-hero__champion-name--empty {
  color: var(--text-tertiary);
  text-shadow: none;
}

.tournament-hero__champion-meta {
  margin-top: var(--space-2xs);
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-tertiary);
}

.tournament-hero__runner-up {
  color: var(--text-secondary);
  text-decoration: none;
  border-bottom: 1px dashed transparent;
  transition: border-color 0.15s ease, color 0.15s ease;
}

.tournament-hero__runner-up:hover,
.tournament-hero__runner-up:focus-visible {
  color: var(--text-primary);
  border-bottom-color: var(--text-secondary);
}

.tournament-hero__finals-record {
  font-family: var(--font-data);
  color: var(--text-secondary);
  font-weight: 600;
}

.tournament-hero__field {
  text-align: right;
  line-height: 1;
}

.tournament-hero__field-number {
  display: block;
  font-family: var(--font-data);
  font-size: clamp(32px, 4.8vw, 44px);
  font-weight: 700;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

.tournament-hero__field-unit {
  display: block;
  font-family: var(--font-data);
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--text-tertiary);
  margin-top: var(--space-2xs);
}

/* Narrow viewports: stack the two pedestals so neither gets crushed. */
@media (max-width: 560px) {
  .tournament-hero__pedestal {
    grid-template-columns: 1fr;
    gap: var(--space-lg);
    align-items: start;
  }
  .tournament-hero__field {
    text-align: left;
  }
}

/* Actual bracket: Quarters → Semis → Finals, left to right. Each round is
   its own flexbox column with justify-content: space-around so matches
   stay vertically centered relative to what feeds them. Horizontal
   connector lines extend from every non-final match into the next column. */

.tournament-bracket {
  display: flex;
  align-items: stretch;
  gap: 40px;
  margin-bottom: 32px;
  padding: 4px 12px 12px;
}

.bracket-column {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1;
}

.bracket-column__label {
  font-family: var(--font-data);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-tertiary);
  text-align: center;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 16px;
}

.bracket-column__matches {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  gap: 8px;
}

.bracket-match {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

/* Horizontal connector extending rightward from every match in all
   columns except the last. Puts a tick-mark that reads as a bracket
   feed without requiring pairing metadata we don't have. */
.bracket-column:not(:last-child) .bracket-match::after {
  content: '';
  position: absolute;
  left: 100%;
  top: 50%;
  width: 40px;
  border-top: 1px solid var(--border);
}

/* Horizontal connector extending leftward into every match after the
   first column, meeting the outgoing line from the previous round. */
.bracket-column:not(:first-child) .bracket-match::before {
  content: '';
  position: absolute;
  right: 100%;
  top: 50%;
  width: 40px;
  border-top: 1px solid var(--border);
}

.bracket-match__player {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 4px 8px;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-family: var(--font-body);
  font-size: 13px;
}

.bracket-match__player a {
  color: inherit;
}

.bracket-match__player--winner {
  background: var(--accent-subtle);
  color: var(--text-primary);
  font-weight: 600;
}

.bracket-match__score {
  font-family: var(--font-data);
  font-size: 12px;
  color: var(--text-tertiary);
}

.bracket-match__player--winner .bracket-match__score {
  color: var(--accent);
  font-weight: 700;
}

/* Bracket crescendo: Quarters are the widest, most muted column (many matches,
   less narrative weight); Semis sit between; Finals gets the heaviest label,
   a slightly tinted surface, and a deeper glow on the winner. The entire
   bracket reads left-to-right as a drumbeat toward the champion. */
.bracket-column--quarterfinals .bracket-column__label {
  color: var(--text-tertiary);
  opacity: 0.75;
}

.bracket-column--semifinals .bracket-column__label {
  color: var(--text-tertiary);
}

.bracket-column--finals .bracket-column__label {
  color: var(--accent);
  font-weight: 700;
  letter-spacing: 1px;
  border-bottom-color: var(--accent);
}

.bracket-column--finals .bracket-match {
  background: var(--card);
  border-color: var(--accent-strong);
}

.bracket-column--finals .bracket-match__player--winner {
  background: var(--accent-soft);
}

.bracket-column--finals .bracket-match__player--winner a {
  color: var(--text-primary);
  text-shadow: 0 0 10px var(--accent-strong);
}

.bracket-column--finals .bracket-match__player--winner .bracket-match__score {
  text-shadow: 0 0 8px var(--accent-strong);
}

/* Responsive fallback: stack columns on narrow viewports. Connectors hide
   since they only make sense horizontally. */
@media (max-width: 768px) {
  .tournament-bracket {
    flex-direction: column;
    gap: var(--space-lg);
    padding: var(--space-xs) 0 var(--space-sm);
  }
  .bracket-column:not(:last-child) .bracket-match::after,
  .bracket-column:not(:first-child) .bracket-match::before {
    display: none;
  }
}

/* Section-header caption — small mono label sitting next to the heading
   in the right slot. Used on /tournaments/:id under "Rating Shift" to
   state the sort dimension. Mirrors .section-header__count/__filtered in
   weight and tone without carrying their specific semantics. */
.section-header__caption {
  font-family: var(--font-data);
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-tertiary);
}

/* Tournament rating-shift table — reuses .rank-row and the table-header
   column classes. Scoped to .tournament-show so the 52px compact row (same
   as /tournaments index) doesn't leak to the leaderboard which wants 56px
   to give the big rating number presence. Also adds two scoped column
   widths: 'Before' (pre-tournament rating) and a variant RD cell that
   drops the confidence-pill styling. */
.tournament-show .shift-row,
.tournament-show .table-header {
  height: 52px;
  gap: var(--space-md);
}

.tournament-show .table-header {
  height: 40px;
}

.th-shift-before, .shift-before {
  width: 80px;
  text-align: right;
  font-family: var(--font-data);
  font-size: 13px;
  color: var(--text-tertiary);
}

.shift-row .shift-rd {
  font-family: var(--font-data);
  font-size: 13px;
  color: var(--text-tertiary);
  font-weight: 500;
}

/* Delta sparkbar — a 2px bar at the bottom edge of every rating-change
   cell, width scaled to that row's |change| as a fraction of the page's
   biggest swing (--magnitude from the view). Green for gains, red for
   drops. Data-density move, not decoration: at a glance, a player can
   see "how big is this row's swing relative to the biggest on the page"
   without reading every number.

   The cell itself stays tight — the bar sits inside its padding box at
   the absolute bottom so it doesn't push layout or clip the number.
   When --magnitude is 0 (or unset on non-show pages), width is 0 and
   the bar is invisible. */
.tournament-show .tourn-delta {
  position: relative;
  overflow: hidden;
}

.tournament-show .tourn-delta::after {
  content: '';
  position: absolute;
  right: 0;
  bottom: 0;
  height: 2px;
  width: calc(var(--magnitude, 0) * 100%);
  border-radius: 1px;
  transition: width 0.3s ease-out;
  pointer-events: none;
}

.tournament-show .tourn-delta--up::after {
  background: linear-gradient(to left,
    rgba(34, 197, 94, 0.85),
    rgba(34, 197, 94, 0.15));
}

.tournament-show .tourn-delta--down::after {
  background: linear-gradient(to left,
    rgba(239, 68, 68, 0.85),
    rgba(239, 68, 68, 0.15));
}

/* Top Mover chip — awarded to the single player with the biggest |rating
   change| across the whole field (not the page). Lives inline next to the
   player name in the rating-shift table, small and tight. Accent glow is
   reserved — only one row on the page earns it. */
.top-mover-badge {
  display: inline-flex;
  align-items: center;
  margin-left: var(--space-xs);
  padding: 2px 8px;
  font-family: var(--font-data);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--accent);
  background: var(--accent-subtle);
  border: 1px solid var(--accent-mid);
  border-radius: var(--radius-full);
  text-shadow: 0 0 8px var(--accent-strong);
  line-height: 1.4;
  white-space: nowrap;
}

/* Reduced-motion: count-up controller already bails to the final value,
   but kill the sparkbar width-transition so it doesn't flash in from 0
   on navigation either. Both flourishes are data-decoration and MUST
   not impair the core read for users who've opted out of motion. */
@media (prefers-reduced-motion: reduce) {
  .tournament-show .tourn-delta::after {
    transition: none;
  }
}

/* Rating history chart — dark panel with a fixed height so the Chart.js
   canvas has somewhere to draw. No border beyond the container frame,
   the grid lines carry the structure. */
.rating-chart-wrap {
  height: 220px;
  padding: 12px 12px 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  margin-bottom: 24px;
}

.rating-chart { display: block; width: 100% !important; height: 100% !important; }

/* Head-to-head table — uses shared .table-container + .rank-row primitives,
   with a per-row left border vibe tint and a compact win/draw/loss split
   bar that carries the record visually. */
.th-h2h-record, .h2h-record   { width: 80px; text-align: center; font-family: var(--font-data); font-size: 13px; color: var(--text-secondary); }
.th-h2h-viz, .h2h-viz         { width: 110px; text-align: center; }
.th-h2h-winrate, .h2h-winrate { width: 70px; text-align: right; font-family: var(--font-data); font-size: 13px; }
.th-h2h-matches, .h2h-matches { width: 72px; text-align: right; font-family: var(--font-data); font-size: 13px; color: var(--text-secondary); }

.h2h-rating-fmt {
  font-family: var(--font-data);
  font-size: 10px;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.4px;
  margin-left: 6px;
}

/* Left accent border vibes — green for favored matchups, red for nemesis.
   4px strip so the aesthetic stays restrained (no full-row tinting). */
.h2h-row { border-left: 3px solid transparent; }
.h2h-row--favorable { border-left-color: var(--positive); }
.h2h-row--nemesis   { border-left-color: var(--negative); }
.h2h-row--even      { border-left-color: var(--border); }

.h2h-row--favorable .h2h-winrate { color: var(--positive); font-weight: 600; }
.h2h-row--nemesis   .h2h-winrate { color: var(--negative); font-weight: 600; }

/* Split bar: one flex row showing wins/draws/losses as proportional
   segments. Colored by outcome. Total width fixed by the column. */
.h2h-viz__bar {
  display: flex;
  align-items: stretch;
  width: 88px;
  height: 8px;
  border-radius: 4px;
  overflow: hidden;
  background: rgba(148, 163, 184, 0.12);
  margin: 0 auto;
}
.h2h-viz__win  { background: var(--positive); }
.h2h-viz__draw { background: var(--warning); opacity: 0.7; }
.h2h-viz__loss { background: var(--negative); }

/* ─── H2H inline expansion (details panel under each rival row) ─── */

/* Panel shell — matches .tourn-expand so the H2H expansion and the
   Tournament History expansion read as the same surface grammar. */
.h2h-expand {
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: none;
  border-bottom-left-radius: 6px;
  border-bottom-right-radius: 6px;
  overflow: hidden;
}

/* Hero row inside the expansion: horizontal split bar on the left
   (the rivalry at a glance), big win rate on the right (the headline
   number). Mirrors the hero density pattern from the profile. */
.h2h-expand__hero {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 16px 20px 12px;
  border-bottom: 1px solid rgba(148, 163, 184, 0.08);
  flex-wrap: wrap;
}
.h2h-expand__hero-main { flex: 1; min-width: 240px; }

.h2h-expand__hero-winrate {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
}
.h2h-expand__hero-winrate .h2h-vibe { margin-left: 0; margin-bottom: 2px; }
.h2h-expand__hero-winrate .audit-hero__label {
  font-size: 10px;
  letter-spacing: 1.2px;
}
.h2h-expand__hero-winrate .audit-hero__number {
  font-family: var(--font-data);
  font-size: 26px;
  color: var(--accent);
  font-feature-settings: "tnum";
  line-height: 1;
}

.h2h-vibe {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 1.2px;
  padding: 2px 8px;
  margin-left: 10px;
  border-radius: 3px;
  border: 1px solid currentColor;
  text-transform: uppercase;
}
.h2h-vibe--favorable { color: var(--positive); }
.h2h-vibe--nemesis   { color: var(--negative); }
.h2h-vibe--even      { color: var(--text-tertiary); }

/* Summary-row vibe chip — smaller, tinted variant of .h2h-vibe that sits
   inline next to the opponent name on the collapsed H2H row. A softer
   background tint (not just an outline) so the chip reads as a tag the
   eye can lock onto while scanning down the list. */
.h2h-row-chip {
  display: inline-flex;
  align-items: center;
  margin-left: var(--space-xs);
  padding: 1px 7px;
  font-family: var(--font-data);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  border-radius: var(--radius-full);
  border: 1px solid transparent;
  line-height: 1.5;
  white-space: nowrap;
}

.h2h-row-chip--favorable {
  color: var(--positive);
  background: rgba(34, 197, 94, 0.1);
  border-color: rgba(34, 197, 94, 0.3);
}

.h2h-row-chip--nemesis {
  color: var(--negative);
  background: rgba(239, 68, 68, 0.1);
  border-color: rgba(239, 68, 68, 0.3);
}

/* Horizontal split bar under the hero — proportional win/draw/loss
   breakdown visible at a glance. Reuses the tokens from the profile
   H2H aggregate row's viz for consistency. */
.h2h-hero__split {
  margin-top: 14px;
  max-width: 520px;
}
.h2h-hero__split-bar {
  display: flex;
  height: 10px;
  border-radius: 5px;
  overflow: hidden;
  background: rgba(148, 163, 184, 0.1);
}
.h2h-hero__split-bar > span { display: block; transition: width 200ms ease; }
.h2h-hero__split-bar .split--win  { background: var(--positive); }
.h2h-hero__split-bar .split--draw { background: var(--warning); opacity: 0.7; }
.h2h-hero__split-bar .split--loss { background: var(--negative); }

.h2h-hero__split-legend {
  display: flex;
  gap: 18px;
  margin-top: 8px;
  font-family: var(--font-data);
  font-size: 11px;
  color: var(--text-tertiary);
  letter-spacing: 0.3px;
  text-transform: uppercase;
}
.h2h-hero__split-legend > span::before {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 2px;
  margin-right: 6px;
  vertical-align: middle;
}
.h2h-hero__split-legend .legend--win::before  { background: var(--positive); }
.h2h-hero__split-legend .legend--draw::before { background: var(--warning); }
.h2h-hero__split-legend .legend--loss::before { background: var(--negative); }

/* H2H match table: overrides .tourn-matches grid (which is sized for the
   7-column audit view) with column priorities tuned for this page:
   tournament wide (it's the point), rating pills compact. Selector doubles
   up to beat .tourn-matches source-order specificity. */
.tourn-matches.h2h-match-table {
  display: grid;
  width: 100%;
  grid-template-columns:
    96px     /* Date */
    minmax(240px, 1fr)  /* Tournament — the scan anchor */
    56px     /* Round */
    72px     /* Format */
    86px     /* Player rating */
    86px     /* Opponent rating */
    72px;    /* Result */
  padding: 0 20px 16px;
}

.tourn-matches.h2h-match-table .tourn-matches__header > span {
  font-size: 10px;
  padding: 12px 0 10px;
}

/* Header "Date" aligns with row date values — rows carry 12px left
   padding for the outcome stripe, so the header's first cell has to
   match or the column labels look off. */
.tourn-matches.h2h-match-table .tourn-matches__header > span:first-child {
  padding-left: 15px;
}

/* Player name headers — mono + primary color so the two competitors
   read as column subjects, not dimmed labels. No truncation: when the
   name is longer than the column, it ellipsizes inline. */
.h2h-match-table__name-col {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-primary) !important;
  letter-spacing: 0.3px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Per-row outcome accent — 3px left stripe on the first cell of each
   match row. display:contents parent means we can't box-shadow the
   whole row, so we stripe the first span and pad it. Color = outcome,
   matches site-wide grammar. */
.tourn-matches.h2h-match-table .h2h-match-row > span {
  padding: 12px 0;
  border-bottom: 1px solid rgba(148, 163, 184, 0.08);
  align-self: center;
}
.tourn-matches.h2h-match-table .h2h-match-row:last-child > span { border-bottom: none; }

.tourn-matches.h2h-match-table .h2h-match-row > span:first-child {
  padding-left: 12px;
  border-left: 3px solid transparent;
}
.h2h-match-row--win  > span:first-child { border-left-color: var(--positive) !important; }
.h2h-match-row--loss > span:first-child { border-left-color: var(--negative) !important; }
.h2h-match-row--draw > span:first-child { border-left-color: var(--warning)  !important; }

/* Tournament name cell — unconstrained line wrapping off by default,
   so long names truncate gracefully instead of exploding the row. */
.h2h-match-row__tourn {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.h2h-match-row__tourn a {
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
  min-width: 0;
}
.h2h-match-row__tourn a:hover { color: var(--accent); }

/* Tier chip next to the tournament name — compact, data-dense
   classification without taking a separate column. */
.h2h-match-row__tier {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: 2px;
}
.h2h-match-row__tier--planetary { color: var(--positive); border: 1px solid var(--positive); }
.h2h-match-row__tier--sector    { color: var(--warning);  border: 1px solid var(--warning);  }
.h2h-match-row__tier--regional  { color: var(--accent);   border: 1px solid var(--accent);   }
.h2h-match-row__tier--galactic  { color: #A78BFA;         border: 1px solid #A78BFA;          }

/* Date cell — mono, tertiary, single line, right-aligned so numbers
   line up visually across rows. */
.tourn-matches.h2h-match-table .h2h-match-row .h2h-match-row__date {
  font-family: var(--font-data);
  font-size: 11px;
  color: var(--text-tertiary);
  white-space: nowrap;
}

/* Rating pill cells — center the pill so the numbers align across
   the two player rating columns. */
.tourn-matches.h2h-match-table .h2h-match-row > span:nth-child(5),
.tourn-matches.h2h-match-table .h2h-match-row > span:nth-child(6) {
  display: flex;
  justify-content: center;
  align-items: center;
}

@media (max-width: 768px) {
  .tourn-matches.h2h-match-table {
    grid-template-columns: auto 1fr 72px;
    padding: 0 12px;
  }
  .tourn-matches.h2h-match-table .h2h-match-row > span:nth-child(n+3):nth-child(-n+6) {
    display: none;
  }
  .tourn-matches.h2h-match-table .tourn-matches__header > span:nth-child(n+3):nth-child(-n+6) {
    display: none;
  }
}

/* ─── Profile sticky header + section nav ─── */
.profile-sticky {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding: 10px 0;
  margin-bottom: 20px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  backdrop-filter: blur(6px);
}

/* Kill the breadcrumb's own bottom margin when it's inside the sticky row —
   the sticky row already handles vertical rhythm. */
.profile-sticky .breadcrumb { margin-bottom: 0; }

.profile-section-nav {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}

.profile-section-nav__link {
  font-family: var(--font-data);
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--text-tertiary);
  padding: 5px 10px;
  border-radius: 5px;
  border: 1px solid transparent;
  text-decoration: none;
  transition: border-color 150ms ease, color 150ms ease;
}

.profile-section-nav__link:hover {
  color: var(--accent);
  border-color: var(--accent);
}

/* Anchored section targets get scroll-margin so clicks land below the
   sticky bar instead of having the heading tucked behind it. */
.section-anchor {
  scroll-margin-top: 72px;
}

/* Smooth scroll for in-page anchor jumps */
html { scroll-behavior: smooth; }

/* Styled horizontal rule between major profile sections (Rating History,
   Tournament History, Head-to-Head). Subtle accent highlight in the middle
   so it reads as a data-terminal section break, not a default gray line. */
.profile-section-divider {
  height: 0;
  margin: 36px 0;
  border: 0;
  border-top: 1px solid var(--border);
  background: transparent;
  position: relative;
}

.profile-section-divider::after {
  content: "";
  position: absolute;
  top: -1px;
  left: 50%;
  transform: translateX(-50%);
  width: 72px;
  height: 1px;
  background: var(--accent);
  opacity: 0.6;
}

/* Rating history section — chart wrapper is a block so the canvas height
   behaves. Format chips moved into the unified .profile-format-tabs. */
.rating-history-block { display: block; }
.rating-history-block .section-header { align-items: center; }

/* Empty-state overlay sits dead-center over the canvas when there's no
   data for the selected format. Chart still draws empty axes underneath
   so the layout doesn't reflow on tab switches. */
.rating-chart-wrap { position: relative; }
.rating-chart-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-data);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  pointer-events: none;
  background: linear-gradient(180deg, rgba(11, 17, 32, 0) 0%, rgba(11, 17, 32, 0.55) 50%, rgba(11, 17, 32, 0) 100%);
}

/* ============================================================
   PROFILE FORMAT TABS — single switch driving Rating History,
   Tournament History, and Head-to-Head together. Designed to
   read clearly as a navigation control, not subtle filter chips.
   ============================================================ */

.profile-format-tabs {
  display: flex;
  align-items: stretch;
  gap: 0;
  margin: 0 0 28px;
  padding: 0;
  border-bottom: 1px solid var(--border);
  position: relative;
  flex-wrap: wrap;
}

.profile-format-tab {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 12px 22px;
  margin-bottom: -1px; /* overlap the bottom border so active tab's underline replaces it */
  font-family: var(--font-data);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  text-decoration: none;
  border: 1px solid transparent;
  border-bottom: 2px solid transparent;
  background: transparent;
  cursor: pointer;
  transition: color 150ms ease, border-color 150ms ease, background 150ms ease;
}

.profile-format-tab:hover {
  color: var(--text-primary);
  background: var(--accent-wash);
  border-bottom-color: var(--text-tertiary);
}

.profile-format-tab--active {
  color: var(--accent);
  background: linear-gradient(180deg, var(--accent-subtle) 0%, var(--accent-wash) 100%);
  border-bottom-color: var(--accent);
  text-shadow: 0 0 12px var(--accent-glow);
}

.profile-format-tab--active::after {
  content: "";
  position: absolute;
  bottom: -2px;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent-glow);
}

/* Right-side hint that explains the tabs drive every section below.
   Pushed to the right with margin-left:auto so it stays out of the
   way of the tab row but stays informative. */
.profile-format-tabs__hint {
  margin-left: auto;
  align-self: center;
  padding: 0 6px 8px;
  font-family: var(--font-data);
  font-size: 10px;
  color: var(--text-tertiary);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

@media (max-width: 768px) {
  .profile-format-tab { padding: 10px 14px; font-size: 12px; }
  .profile-format-tabs__hint { display: none; }
}

/* ============================================================
   PAGINATION NAV — custom CSS, no Tailwind.
   ============================================================ */

.pagy-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin: 20px 0 8px;
  padding: 12px 0 0;
  font-family: var(--font-data);
}

.pagy-nav__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  padding: 0 10px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 5px;
  text-decoration: none;
  transition: border-color 150ms ease, color 150ms ease, background 150ms ease;
}

.pagy-nav__link:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.pagy-nav__link--current {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--bg);
  box-shadow: 0 0 10px var(--accent-glow);
}

.pagy-nav__link--arrow { padding: 0 12px; }

.pagy-nav__link--disabled,
.pagy-nav__link--disabled:hover {
  color: var(--text-tertiary);
  border-color: var(--border);
  background: transparent;
  cursor: not-allowed;
  box-shadow: none;
}

.pagy-nav__gap {
  color: var(--text-tertiary);
  padding: 0 4px;
}

/* "Showing X–Y of Z" sits centered on its own line below the page links.
   `flex-basis: 100%` forces a wrap so the hint never competes with the
   numbered controls for horizontal space. */
.pagy-nav__hint {
  flex-basis: 100%;
  text-align: center;
  margin-top: 8px;
  font-size: 11px;
  color: var(--text-tertiary);
  letter-spacing: 0.04em;
}

/* ============================================================
   H2H EMPTY STATE — terminal "no signal" blank slate.
   Direct copy, no emojis, sci-fi data terminal vibe.
   ============================================================ */

.h2h-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 36px 24px 40px;
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: 8px;
  text-align: center;
}

.h2h-empty__reticle {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-data);
  color: var(--text-tertiary);
  font-size: 13px;
  letter-spacing: 0.4em;
  text-transform: uppercase;
}

.h2h-empty__bracket {
  color: var(--accent);
  font-size: 18px;
  text-shadow: 0 0 6px var(--accent-glow);
}

.h2h-empty__core {
  position: relative;
}

.h2h-empty__core::after {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-left: 8px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent-glow);
  vertical-align: middle;
  animation: h2h-pulse 1.8s ease-in-out infinite;
}

@keyframes h2h-pulse {
  0%, 100% { opacity: 0.4; }
  50% { opacity: 1; }
}

.h2h-empty__copy {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-width: 480px;
}

.h2h-empty__headline {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 600;
  color: var(--text-primary);
}

.h2h-empty__sub {
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-tertiary);
  line-height: 1.5;
}

/* Profile hero: credible-interval ± width. Sits inline inside the caption
   row alongside the format label and confidence % — flex gap in the parent
   handles spacing, so no local margin needed. 12px matches .profile-hero__conf
   so neither signal dominates; confidence % is the more interpretable of
   the two and leads the caption via document order. */
.profile-hero__ci {
  font-family: var(--font-data);
  font-size: 12px;
  color: var(--text-tertiary);
  font-weight: 400;
}

/* Tournament history: expandable per-match audit trail */
.tourn-row-wrapper { display: block; }

.tourn-row { cursor: pointer; }
.tourn-row[aria-expanded="true"] { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }

/* Affordance chevron — sits to the left of every row, points right when
   collapsed and rotates to point down when the <details> is open. The
   native disclosure marker is suppressed so this is the only indicator. */
.tourn-row { list-style: none; }
.tourn-row::-webkit-details-marker { display: none; }

.tourn-row__chevron {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  flex-shrink: 0;
  margin-right: 8px;
  color: var(--text-tertiary);
  transition: transform 150ms ease, color 150ms ease;
}

.tourn-row:hover .tourn-row__chevron { color: var(--accent); }

details[open] > .tourn-row > .tourn-row__chevron,
details[open] > .h2h-row > .tourn-row__chevron {
  transform: rotate(90deg);
  color: var(--accent);
}

/* H2H rows reuse the tourn-row disclosure pattern so the chevron and
   expansion behave identically. The marker is suppressed, the summary
   takes the flex row layout from .rank-row, and the bottom radius
   opens up when the panel expands so the two read as one unit. */
.h2h-row { cursor: pointer; list-style: none; }
.h2h-row::-webkit-details-marker { display: none; }
.h2h-row:hover .tourn-row__chevron { color: var(--accent); }
details[open] > .h2h-row { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }

/* Header alignment column for the chevron — same width + margin as the
   chevron column so the Event header lines up with the event names. */
.th-chevron {
  width: 20px;
  flex-shrink: 0;
  margin-right: 8px;
}

/* Expansion panel — wraps the explainer + metric strip + matches grid so
   the audit info lives on the profile directly. Shares surface + border
   with the summary row so the two read as a single expanded unit. Flex
   column with a uniform gap between children controls vertical rhythm.
   All children sit at 20px inset matching the summary row's padding so
   columns and content align vertically from summary through expand. */
.tourn-expand {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  padding: var(--space-sm) 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: none;
  border-bottom-left-radius: 6px;
  border-bottom-right-radius: 6px;
  overflow: hidden;
}

.tourn-expand__meta {
  padding: 0;
}

/* Strip chrome off the matches grid and break it out to the panel's
   full width so the separator line runs edge-to-edge. The grid's own
   internal padding re-creates the 20px inset for its cells. */
.tourn-expand .tourn-matches {
  background: transparent;
  border: none;
  border-top: 1px solid var(--border);
  border-radius: 0;
  margin: 0 -20px;
}

/* Inline metric-strip modifier: kill the section-level bottom margin
   and tighten gaps since we're already inside a padded panel. */
.metric-strip--inline {
  margin: 0;
  padding: 0;
  gap: var(--space-xs) var(--space-xl);
}

/* After an open details row, give the next sibling a beat of space so
   the expand panel doesn't visually merge into the following row. The
   base table-container gap of 2px is right for collapsed rows but too
   tight when an expand panel sits above the next row. */
.tourn-row-wrapper[open],
.h2h-row-wrapper[open] {
  margin-bottom: var(--space-sm);
}

.tourn-matches {
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: none;
  border-bottom-left-radius: 6px;
  border-bottom-right-radius: 6px;
  padding: var(--space-sm) 20px;
  font-family: var(--font-data);
  font-size: 12px;
  color: var(--text-secondary);
  display: grid;
  grid-template-columns: 50px 64px 1fr 70px 60px 60px 70px;
  gap: 6px var(--space-sm);
  align-items: center;
}

.tourn-matches__header {
  display: contents;
  font-size: 10px;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}

.tourn-matches__header > span { padding-bottom: 6px; border-bottom: 1px solid var(--border); }

.tourn-match { display: contents; }
.tourn-match > span { padding: 4px 0; }

.tourn-match__result--win { color: var(--positive); }
.tourn-match__result--loss { color: var(--negative); }
.tourn-match__result--draw { color: var(--warning); }

.tourn-match__mult {
  color: var(--text-tertiary);
  font-size: 11px;
}

.tourn-match__opponent a {
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: 12px;
}

.tourn-match__hri {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Column alignment — shared by profile inline expansion and tournament breakdown.
   Columns: 1 Round (left) | 2 HRI (center) | 3 Opponent (left) |
            4 Result (center) | 5 Game W-L (right) | 6 Multiplier (right) | 7 Type (right) */
.tourn-matches__header > span:nth-child(2),
.tourn-matches__header > span:nth-child(4) {
  text-align: center;
}

.tourn-matches__header > span:nth-child(n+5) {
  text-align: right;
}

.tourn-match > span:nth-child(4) {
  text-align: center;
}

.tourn-match > span:nth-child(n+5) {
  text-align: right;
}

.tourn-match__hri-pill {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  font-family: var(--font-data);
  font-size: 11px;
  font-feature-settings: "tnum";
  color: var(--text-secondary);
  background: rgba(148, 163, 184, 0.06);
  border: 1px solid var(--border);
  border-radius: 10px;
  cursor: help;
  transition: border-color 150ms ease, color 150ms ease;
  white-space: nowrap;
}

.tourn-match__hri-pill:hover {
  color: var(--text-primary);
  border-color: var(--text-tertiary);
}

.tourn-match__hri--none {
  color: var(--text-tertiary);
  font-family: var(--font-data);
  font-size: 11px;
}

@media (max-width: 768px) {
  .tourn-matches {
    grid-template-columns: auto auto 1fr;
    gap: 4px 10px;
  }
  .tourn-matches__header { display: none; }
  .tourn-match > span { font-size: 11px; }
}

/* ============================================================
   FEEDBACK — modal + form + nav button + flash
   ============================================================ */

/* Nav-bar Feedback button: same visual weight as a nav link but styled
   as a button so a11y reads it as an action, not a destination. */
.nav-link--feedback {
  background: transparent;
  border: 1px solid var(--border);
  padding: 4px 12px;
  border-radius: 5px;
  cursor: pointer;
  transition: border-color 150ms ease, color 150ms ease, background 150ms ease;
}
.nav-link--feedback:hover {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--accent-wash);
}

/* Right-edge cluster in the sticky header: the section-jump nav plus the
   standalone Report Issue action. The action is NOT inside the <nav>, so
   screen-readers don't announce a modal trigger as a profile section. */
.profile-sticky__tail {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

/* Report Issue — deliberately different from the section-jump anchors so
   a keyboard tabber can tell an action from a jump. Ghost-button styling
   with a hairline border that activates on hover. */
.profile-sticky__report {
  font-family: var(--font-data);
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--text-tertiary);
  background: transparent;
  padding: 5px 10px;
  border: 1px solid var(--border);
  border-radius: 5px;
  cursor: pointer;
  transition: border-color 150ms ease, color 150ms ease;
}

.profile-sticky__report:hover,
.profile-sticky__report:focus-visible {
  color: var(--accent);
  border-color: var(--accent);
}

/* Modal — native <dialog> element. Uses the data-terminal aesthetic to
   match the rest of the site. ::backdrop blurs the page underneath.
   `inset: 0; margin: auto` centers horizontally + vertically (Chrome/Edge
   defaults handle this for un-styled <dialog> but we override `display`,
   so we set it explicitly). */
.feedback-modal[open] {
  display: block;
  position: fixed;
  inset: 0;
  margin: auto;
  padding: 0;
  width: min(540px, calc(100vw - 24px));
  max-height: calc(100vh - 48px);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text-primary);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5), 0 0 0 1px var(--accent-soft);
  overflow: hidden;
}

.feedback-modal::backdrop {
  background: rgba(11, 17, 32, 0.72);
  backdrop-filter: blur(4px);
}

.feedback-modal__inner {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 22px 24px 24px;
  max-height: calc(100vh - 48px);
  overflow-y: auto;
}

.feedback-modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.feedback-modal__close {
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 5px;
  font-size: 22px;
  line-height: 1;
  color: var(--text-tertiary);
  cursor: pointer;
  transition: border-color 150ms ease, color 150ms ease;
}
.feedback-modal__close:hover {
  color: var(--accent);
  border-color: var(--accent);
}

.feedback-modal__intro {
  margin: 0;
}

/* Form — also used standalone on /feedbacks/new. Tabular, dense, no fluff. */
.feedback-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.feedback-form__row {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.feedback-form__label {
  font-family: var(--font-data);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}

.feedback-form__hint {
  margin: 6px 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-tertiary);
}

.feedback-form__hint strong {
  color: var(--text-secondary);
  font-weight: 600;
}

.feedback-form__input,
.feedback-form__textarea {
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--text-primary);
  background: var(--input);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 9px 12px;
  width: 100%;
  transition: border-color 150ms ease, box-shadow 150ms ease;
}

/* Strip the native <select> appearance and draw our own chevron so the
   caret sits at consistent padding, matches the dark theme, and doesn't
   look squashed against the right edge. The SVG inlines a chevron-down. */
select.feedback-form__input {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 36px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'><path d='M1 1.5L6 6.5L11 1.5' stroke='%2394A3B8' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 14px center;
  cursor: pointer;
}

select.feedback-form__input:focus {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'><path d='M1 1.5L6 6.5L11 1.5' stroke='%230EA5E9' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>");
}

.feedback-form__textarea {
  resize: vertical;
  min-height: 120px;
  line-height: 1.5;
}

.feedback-form__input:focus,
.feedback-form__textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.feedback-form__actions {
  display: flex;
  justify-content: flex-end;
}

.feedback-form__errors {
  background: rgba(239, 68, 68, 0.08);
  border: 1px solid rgba(239, 68, 68, 0.4);
  color: var(--negative);
  border-radius: 5px;
  padding: 10px 12px;
  font-size: 13px;
}
.feedback-form__errors ul {
  list-style: disc;
  margin: 6px 0 0 18px;
  padding: 0;
}

/* Generic primary button used by the form submit + future actions. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 9px 18px;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 600;
  border-radius: 5px;
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
}

.btn--primary {
  background: var(--accent);
  color: var(--bg);
  border-color: var(--accent);
}
.btn--primary:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  color: var(--bg);
}

/* Toast-style flash anchored bottom-center. Auto-fades after 4s. */
.flash {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  z-index: 100;
  padding: 10px 18px;
  background: var(--surface);
  border: 1px solid var(--accent);
  border-radius: 5px;
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-primary);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.4), 0 0 0 1px var(--accent-soft);
  animation: flash-fade 4s ease forwards;
}
.flash--notice { color: var(--text-primary); }

@keyframes flash-fade {
  0%, 80% { opacity: 1; transform: translateX(-50%) translateY(0); }
  100%    { opacity: 0; transform: translateX(-50%) translateY(8px); pointer-events: none; }
}

/* ============================================================
   AUTH PAGES — Devise sign in / password reset.
   Centered card, dark theme, brand chrome. Reuses the existing
   .feedback-form__input + .btn primitives.
   ============================================================ */

.auth-page {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: calc(100vh - 120px);
  padding: 32px 16px;
}

.auth-card {
  position: relative;
  width: 100%;
  max-width: 420px;
  padding: 28px 32px 32px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.45), 0 0 0 1px var(--accent-soft);
}

/* Same accent edge-glow as the profile hero card. */
.auth-card::before {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: 8px;
  border: 1px solid transparent;
  background: linear-gradient(180deg, var(--accent-mid), transparent 50%) border-box;
  -webkit-mask: linear-gradient(#000 0 0) padding-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events: none;
}

.auth-card__brand {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 24px;
}

.auth-logo {
  height: 28px;
  width: auto;
}

.auth-card__chip {
  font-family: var(--font-data);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.2em;
  color: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 4px;
  padding: 2px 8px;
  background: var(--accent-subtle);
  text-shadow: 0 0 8px var(--accent-glow);
}

.auth-card__title {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 700;
  color: var(--text-primary);
  margin: 0 0 6px;
}

.auth-card__sub {
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-tertiary);
  margin: 0 0 20px;
}

.auth-form {
  /* Tighter than the feedback modal — shorter form, more breathing room. */
  gap: 16px;
}

.auth-actions {
  margin-top: 4px;
}

.auth-actions .btn {
  width: 100%;
  justify-content: center;
}

.auth-remember {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-tertiary);
  cursor: pointer;
}
.auth-remember input[type="checkbox"] {
  accent-color: var(--accent);
  width: 14px;
  height: 14px;
}

.auth-card__footer {
  margin: 18px 0 0;
  text-align: center;
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-tertiary);
}

/* Inline alert for Devise's flash messages (alert/notice). */
.auth-flash {
  margin: 0 0 14px;
  padding: 10px 12px;
  font-family: var(--font-body);
  font-size: 13px;
  border-radius: 5px;
  border: 1px solid var(--border);
  background: var(--input);
  color: var(--text-secondary);
}
.auth-flash--alert {
  color: var(--negative);
  border-color: rgba(239, 68, 68, 0.4);
  background: rgba(239, 68, 68, 0.08);
}
.auth-flash--notice {
  color: var(--accent);
  border-color: var(--accent-strong);
  background: var(--accent-subtle);
}


