:root {
  --font-sans: "Inter", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;

  --bg: #f5f6fa;
  --panel: #ffffff;
  --panel-alt: #f1f3f7;
  --border: #e2e6ed;
  --text: #12151c;
  --muted: #64748b;

  /* Primary colours, used sparingly as accents rather than as the base palette. */
  --blue: #0b5fd7;
  --blue-dim: #094aa8;
  --red: #dc2430;
  --red-dim: #b31b26;
  --yellow: #ffc60b;
  --header-bg: #7a1420;
  --header-bg-2: #55101a;
  --header-hover: rgba(255, 255, 255, 0.12);
  --header-active: rgba(255, 255, 255, 0.18);

  --good: #16a34a;
  --warn: #96590a;   /* readable amber text on white -- see --yellow for the bright badge fill */
  --bad: var(--red);

  /* Podium accents for top-3 rankings rows and competition tiers -- ties the table back to the
     target-rings motif in the favicon/wordmark without introducing an unrelated new colour. */
  --gold: #c9930a;
  --silver: #8a94a3;
  --bronze: #b06a35;

  /* Elevation + radius scale, applied consistently across every card-like surface (stat tiles,
     the rankings table, popovers, dropdowns) instead of one-off shadows per component. */
  --shadow-sm: 0 1px 2px rgba(18, 21, 28, 0.07);
  --shadow-md: 0 6px 18px rgba(18, 21, 28, 0.09);
  --shadow-lg: 0 18px 44px rgba(18, 21, 28, 0.16);
  --radius-sm: 7px;
  --radius-md: 11px;
  --radius-lg: 16px;
}

* { box-sizing: border-box; }

/* The `hidden` attribute's default display:none is a UA-stylesheet rule -- any author rule that
   sets display on the same element (e.g. .button-link's display:inline-flex, below) overrides it
   at equal specificity, since author styles always beat UA styles. Real bug hit in practice: the
   Export to Excel links stayed visibly flexed even while .hidden was correctly true in the DOM.
   This forces hidden to always win, for every element, regardless of what else sets display. */
[hidden] { display: none !important; }

body {
  margin: 0;
  font-family: var(--font-sans);
  line-height: 1.55;
  background: var(--bg);
  color: var(--text);
}

header {
  padding: 1.6rem 2rem 0;
  background:
    radial-gradient(circle at 92% -40%, rgba(255, 255, 255, 0.12) 0%, transparent 45%),
    linear-gradient(135deg, var(--header-bg) 0%, var(--header-bg-2) 100%);
  color: #fff;
  box-shadow: var(--shadow-lg);
}

.header-top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  margin-bottom: 1.35rem;
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  min-width: 0; /* lets the h1 truncate/wrap instead of forcing the flex row to overflow */
}

.brand-mark {
  flex-shrink: 0;
  display: block;
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.3));
}

header h1 {
  margin: 0;
  font-size: 1.75rem;
  font-weight: 800;
  font-style: italic;
  text-transform: uppercase;
  letter-spacing: 0.015em;
  line-height: 1.15;
  color: #fff;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
}

/* Two-tone logotype: the category word picks up the accent colour already used for the review
   badge/HPS highlights elsewhere, so the wordmark doesn't introduce a new colour of its own. */
.wordmark-accent { color: var(--yellow); }

.profile-menu { position: relative; flex-shrink: 0; }

.profile-btn {
  background: rgba(255, 255, 255, 0.14);
  border: none;
  color: #fff;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
  transition: background-color 0.15s ease, transform 0.15s ease;
}
.profile-btn:hover { background: rgba(255, 255, 255, 0.24); transform: scale(1.06); }
.profile-btn.logged-in { background: var(--good); }

.profile-popover {
  position: absolute;
  top: calc(100% + 0.6rem);
  right: 0;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  padding: 1rem;
  min-width: 220px;
  z-index: 20;
}

.login-form { display: flex; flex-direction: column; gap: 0.5rem; }
.login-form label { display: flex; flex-direction: column; gap: 0.25rem; color: var(--muted); font-size: 0.85rem; }
.login-error { color: var(--bad); font-size: 0.85rem; margin: 0.25rem 0 0; min-height: 1em; }

.login-status { display: flex; flex-direction: column; gap: 0.6rem; align-items: flex-start; }
.login-status p { margin: 0; font-size: 0.9rem; }

nav {
  display: flex;
  gap: 0.35rem;
  overflow-x: auto;
  /* Explicit, not the default `visible` -- per spec, a non-visible overflow-x paired with a
     left-as-visible overflow-y silently computes the latter to `auto` too (the same coupling
     documented on .table-wrap above). Any stray sub-pixel vertical overflow from flex/font-metric
     rounding (or an absolutely-positioned child like .tab-btn::after) then makes `nav` a
     scrollable container in its own right and draws a real, visible scrollbar for it -- this was
     the cause of a genuinely confusing stray scrollbar-with-arrows sitting on the header. Setting
     this explicitly clips any such overflow instead of scrolling it. */
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  border-bottom: 1px solid rgba(255, 255, 255, 0.14);
}

.tab-btn {
  position: relative;
  background: none;
  border: none;
  color: rgba(255, 255, 255, 0.72);
  padding: 0.75rem 1.05rem;
  cursor: pointer;
  font-size: 0.92rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  white-space: nowrap;
  flex-shrink: 0;
  transition: color 0.15s ease;
}

/* Underline-style active indicator (a thin podium-gold bar riding the header's own bottom
   border) reads as a modern scoreboard tab strip rather than the flat filled-rectangle look a
   plain background-color swap would give. bottom: 0, not -1px -- `nav` has overflow-x: auto,
   and per spec a non-visible overflow-x forces overflow-y to compute as auto too (the exact
   same coupling documented on .table-wrap above), so a pseudo-element poking even 1px below
   nav's own box was enough to make nav a scrollable container and draw a real, visible
   scrollbar for that sub-pixel overflow -- the "arrow thing" bug. Staying inside the box avoids
   creating any overflow at all. */
.tab-btn::after {
  content: "";
  position: absolute;
  left: 1.05rem;
  right: 1.05rem;
  bottom: 0;
  height: 3px;
  border-radius: 3px 3px 0 0;
  background: var(--yellow);
  opacity: 0;
  transform: translateY(2px);
  transition: opacity 0.15s ease, transform 0.15s ease;
}

.tab-btn:hover { color: #fff; }

.tab-btn.active { color: #fff; }
.tab-btn.active::after { opacity: 1; transform: translateY(0); }

.badge {
  background: var(--yellow);
  color: #1a1200;
  border-radius: 999px;
  padding: 0.05rem 0.55rem;
  font-size: 0.75rem;
  font-weight: 700;
  margin-left: 0.35rem;
}

main { padding: 2rem 2rem 3.5rem; max-width: 1120px; margin: 0 auto; }

.tab-panel { display: none; }
.tab-panel.active { display: block; }

.panel-header { display: flex; flex-wrap: wrap; gap: 0.75rem; justify-content: space-between; align-items: center; margin-bottom: 0.5rem; }

.table-wrap {
  /* Not overflow-x: auto here -- per spec, overflow-x/y can't independently mix visible with a
     non-visible value; setting overflow-x to anything but visible silently forces overflow-y to
     compute as auto too, which makes THIS the sticky containing block for the <th> elements
     below instead of the page, breaking the sticky header entirely (found live: rectTop stayed
     negative/scrolled-away instead of clamping to 0). Desktop tables comfortably fit without
     horizontal scroll, so leave this visible by default and only re-enable overflow-x in the
     mobile breakpoint below, where shifting columns into view matters more than a sticky header. */
  overflow-x: visible;
  -webkit-overflow-scrolling: touch;
  margin-top: 0.75rem;
}
.table-wrap table { margin-top: 0; min-width: 560px; }

h2 {
  font-size: 1.4rem;
  font-weight: 700;
  letter-spacing: -0.005em;
  line-height: 1.25;
  margin: 0 0 0.5rem;
}
/* Inside a flex .panel-header (heading + action buttons on one row), let the header's own
   margin-bottom carry the spacing instead -- an asymmetric margin on just the h2 would skew its
   vertical centering against the buttons sitting next to it (align-items: center centers each
   flex item's full margin box, not just its content). */
.panel-header h2 { margin: 0; }

h3 {
  font-weight: 700;
  line-height: 1.3;
}

.hint { color: var(--muted); font-size: 0.9rem; margin-top: -0.15rem; }

table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 0.75rem;
  background: var(--panel);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  font-variant-numeric: tabular-nums; /* scores/ranks/points line up vertically column to column */
}
/* Rounded corners on the bottom only, via the corner cells themselves rather than `overflow:
   hidden` on <table> -- that would make the table (a non-scrolling ancestor with non-visible
   overflow) the sticky containing block for the <th> elements below, breaking the sticky header
   entirely instead of letting it track the page's actual scroll. The top corners stay square:
   rounding the header cells' own background fill left it visibly out of step with the table's
   own straight-edged border around it (the border itself was never rounded to match, since
   border-radius was only ever applied to the cells, not <table>), so square reads cleaner than a
   mismatched pairing. */
tbody tr:last-child td:first-child { border-bottom-left-radius: var(--radius-lg); }
tbody tr:last-child td:last-child { border-bottom-right-radius: var(--radius-lg); }

th, td {
  text-align: left;
  padding: 0.7rem 0.9rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.9rem;
}

th {
  position: sticky;
  /* -1px, not 0, to kill a hairline seam above the stuck header. At a fractional
     devicePixelRatio (1.5 on a 150%-scaled Windows display) one CSS pixel isn't a whole device
     pixel, so the sticky row's own compositing layer snaps to the device grid while the rows
     scrolling behind it move continuously. When the rounding falls the wrong way, a sliver of
     the row underneath shows above the header and reads as a ~1px gap at the top of the
     viewport. Layout was never wrong -- getBoundingClientRect().top was exactly 0 -- so there
     is nothing to fix geometrically; parking the row 1px above the edge simply pushes the seam
     off-screen. The lost pixel is padding (0.7rem of it), so nothing is visibly clipped, and
     `top` has no effect at all until the row actually sticks. */
  top: -1px;
  z-index: 2;
  color: var(--muted);
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  background: var(--panel-alt);
  border-bottom: 2px solid var(--border);
}

tbody tr { transition: background-color 0.12s ease; }
tbody tr:nth-child(even) td { background: var(--panel-alt); }
tbody tr:hover td { background: rgba(122, 20, 32, 0.045); }

tr:last-child td { border-bottom: none; }

button, input, select {
  font-family: inherit;
  font-size: 0.9rem;
}

/* Plain text, not a button -- explicitly zeroes out every visual property the shared `button`
   rule below sets (shadow, radius, gradient), since `.sort-header` is a real <button> element
   under the hood and a class selector alone doesn't reset properties the element rule sets but
   this rule doesn't mention. Without this, the column titles picked up a faint pill/box outline
   from `button`'s box-shadow showing through the (correctly) transparent background. */
.sort-header {
  background: none;
  border: none;
  box-shadow: none;
  border-radius: 0;
  padding: 0;
  margin: 0;
  color: inherit;
  font: inherit;
  font-weight: 700;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}
.sort-header:hover, .sort-header:active { box-shadow: none; transform: none; background: none; }

.sort-header:hover { background: none; color: var(--text); }

.sort-arrows {
  display: inline-flex;
  flex-direction: column;
  gap: 0.17rem;
}

.sort-arrows .arrow {
  font-size: 0.6rem;
  line-height: 1;
  color: var(--muted);
  opacity: 0.5;
}

.sort-header:hover .arrow { opacity: 0.8; }
.sort-arrows .arrow.active { color: var(--blue); opacity: 1; }

button {
  background: var(--red);
  color: white;
  border: none;
  padding: 0.55rem 1.1rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-weight: 600;
  transition: background-color 0.12s ease;
}

button:hover { background: var(--red-dim); }

button.secondary {
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text);
}

button.secondary:hover { background: var(--panel-alt); }

button.small-btn {
  padding: 0.3rem 0.65rem;
  font-size: 0.85rem;
  border-radius: var(--radius-sm);
  margin-right: 0.3rem;
}

.button-link {
  display: inline-flex;
  align-items: center;
  background: var(--red);
  color: white;
  border: none;
  padding: 0.55rem 1.1rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 600;
  transition: background-color 0.12s ease;
}
.button-link:hover { background: var(--red-dim); }
.button-link.secondary {
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text);
}
.button-link.secondary:hover { background: var(--panel-alt); }

.panel-header-actions { display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap; }

form#ingest-form {
  display: grid;
  gap: 0.75rem;
  max-width: 480px;
  margin-top: 1rem;
}

form label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  color: var(--muted);
  font-size: 0.85rem;
}

input, select {
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 0.5rem 0.7rem;
  border-radius: var(--radius-sm);
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
input:focus, select:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(11, 95, 215, 0.15);
}

.rankings-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 0.75rem;
}
#rankings-search { flex: 1 1 260px; max-width: 320px; }
#rankings-country-filter { flex: 0 1 200px; }

.rankings-contact-link {
  display: flex;
  align-items: center;
  color: var(--muted);
  text-decoration: none;
  font-size: 0.9rem;
  border-bottom: 1px dashed transparent;
}
.rankings-contact-link:hover { color: var(--blue); border-bottom-color: var(--blue); }

/* Pagination under the rankings table. Flat and square to match the table itself -- these are
   navigation, not calls to action, so they deliberately don't inherit the red fill that bare
   `button` carries. */
.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: 0.9rem;
}
.pagination-summary { color: var(--muted); font-size: 0.85rem; }
.pagination-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem; }

.pagination-btn {
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.35rem 0.6rem;
  min-width: 2.15rem;
  font-size: 0.85rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums; /* page numbers keep an even width as the digits change */
}
.pagination-btn:hover:not(:disabled) { background: var(--panel-alt); border-color: var(--muted); }
.pagination-btn:disabled { opacity: 0.4; cursor: default; background: var(--panel); }

/* The current page reads as selected rather than clickable. */
.pagination-btn.current {
  background: var(--header-bg);
  border-color: var(--header-bg);
  color: #fff;
  cursor: default;
}
.pagination-btn.current:hover { background: var(--header-bg); border-color: var(--header-bg); }

.pagination-gap { color: var(--muted); padding: 0 0.15rem; user-select: none; }

.info-content { max-width: 680px; line-height: 1.55; }
.info-content h3 { margin-bottom: 0.35rem; }

.athlete-link {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px dashed var(--border);
  cursor: pointer;
}
.athlete-link:hover { color: var(--blue); border-bottom-color: var(--blue); }

/* Rankings table's Athlete column lost its "(ITRA000038)" ID suffix -- widen the name itself
   (tracking + a touch more size) to use the freed-up space rather than leaving it empty. */
.rankings-athlete-cell { letter-spacing: 0.04em; font-size: 0.95rem; }

.back-link {
  background: none;
  border: none;
  color: var(--blue);
  padding: 0;
  margin-bottom: 1rem;
  font-size: 0.9rem;
  cursor: pointer;
}
.back-link:hover { background: none; text-decoration: underline; }

/* Admin-only "master edit" on the athlete profile -- sits between the meta line and the stat
   tiles, hidden until the Edit button is pressed. */
.athlete-edit-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.75rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 0.9rem 1.1rem;
  margin: 1rem 0 0;
  box-shadow: var(--shadow-sm);
}
.athlete-edit-form label { flex: 1 1 200px; }
.athlete-edit-form input { width: 100%; }
.athlete-edit-actions { display: flex; gap: 0.5rem; }
.athlete-edit-form .login-error { flex-basis: 100%; margin: 0; }

.stat-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  margin: 1.25rem 0 1.75rem;
}

.stat-tile {
  background: var(--panel);
  border: 1px solid var(--border);
  border-top: 3px solid var(--header-bg);
  border-radius: var(--radius-md);
  padding: 0.8rem 1.15rem;
  min-width: 105px;
  box-shadow: var(--shadow-sm);
}
.stat-tile .stat-label {
  font-size: 0.7rem;
  color: var(--muted);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.stat-tile .stat-value {
  font-variant-numeric: tabular-nums;
  font-size: 1.55rem;
  font-weight: 800;
  line-height: 1.35;
  margin-top: 0.1rem;
}
.stat-tile .stat-value small { font-size: 0.7rem; font-weight: 600; margin-left: 0.15rem; }
.info-content p { margin-top: 0.35rem; }

.checkbox-label {
  flex-direction: row;
  align-items: center;
  gap: 0.5rem;
}
.checkbox-label input[type="checkbox"] { width: auto; flex-shrink: 0; }

.tier-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-left: 4px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.65rem 0.9rem;
  margin-bottom: 0.5rem;
  box-shadow: var(--shadow-sm);
}
/* Tier-to-podium colour mapping mirrors the rankings table's medal accents (gold/silver/bronze
   for ranks 1-3) -- Tier 1 is the most prestigious competitions, so it gets gold, and so on. */
.tier-card-1 { border-left-color: var(--gold); }
.tier-card-2 { border-left-color: var(--silver); }
.tier-card-3 { border-left-color: var(--bronze); }

code {
  background: var(--panel-alt);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.1rem 0.35rem;
  font-size: 0.85em;
}

.flag {
  height: 1.5em;
  width: auto;
  vertical-align: middle;
  margin-right: 0.35em;
  margin-top: -0.15em;
  border-radius: 2px;
  box-shadow: 0 0 0 0.5px rgba(0,0,0,0.18);
}

.rank-num {
  display: inline-block;
  min-width: 2em; /* fixed so 1/2/3-digit ranks don't shift where the arrow starts */
  text-align: right;
}

.move-up, .move-down, .move-none, .move-new {
  display: inline-block;
  font-size: 0.9em;
  margin-left: 0.35em;
  white-space: nowrap;
}
.move-up { color: var(--good); }
.move-down { color: var(--bad); }
.move-none { color: var(--muted); }
.move-new { color: var(--blue); font-weight: 600; }

.status-pill {
  display: inline-block;
  font-size: 0.82rem;
  font-weight: 600;
  padding: 0.15em 0.55em;
  border-radius: 999px;
}
.status-no_match { color: var(--bad); background: rgba(220, 36, 48, 0.1); }
.status-ambiguous { color: var(--warn); background: rgba(255, 198, 11, 0.18); }

#ingest-status { margin-top: 1rem; color: var(--muted); }

.resolution-row select, .resolution-row input { width: 100%; }

.trid-autocomplete { position: relative; margin-bottom: 0.3rem; }
.trid-suggestions {
  position: absolute;
  z-index: 10;
  left: 0;
  right: 0;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  margin-top: 0.2rem;
  max-height: 220px;
  overflow-y: auto;
  box-shadow: var(--shadow-lg);
}
.trid-suggestion { padding: 0.4rem 0.6rem; cursor: pointer; border-bottom: 1px solid var(--border); }
.trid-suggestion:last-child { border-bottom: none; }
.trid-suggestion:hover { background: var(--panel-alt); }
.trid-suggestion-name { display: block; }
.trid-suggestion-empty { padding: 0.4rem 0.6rem; }

@media (max-width: 640px) {
  header { padding: 1.1rem 1rem 0; }
  header h1 { font-size: 1.1rem; }
  .brand-mark { width: 22px; height: 22px; }
  main { padding: 1rem 1rem 2rem; }

  /* Larger touch targets -- the desktop sizing below this breakpoint runs a bit small for
     fingers rather than a mouse cursor. */
  button, input, select { font-size: 1rem; }
  button { padding: 0.65rem 1.1rem; }
  input, select { padding: 0.6rem 0.7rem; }
  th, td { padding: 0.5rem 0.6rem; }

  /* Re-enable horizontal scroll here, narrow viewports need it to shift columns into view --
     this does mean the sticky header (see .table-wrap above) stops sticking below this
     breakpoint, since that requires overflow-x to stay visible. Reasonable trade-off: shifting
     columns into view matters more on a phone than a sticky header does. */
  .table-wrap { overflow-x: auto; }

  #rankings-search, #rankings-country-filter { max-width: none; }
  /* flex-basis follows the main axis -- #rankings-search/#rankings-country-filter's desktop
     `flex: 1 1 260px` sets that 260px as a WIDTH hint under the default row layout, but once this
     rule flips the container to a column, the same flex-basis becomes a HEIGHT hint instead,
     stretching both controls to ~260px tall. Reset flex-basis (and flex-grow, so they don't also
     fight over the column's leftover vertical space) explicitly for column layout. Targeted by
     the same ID selectors as the desktop rule (not a class/descendant selector) so this actually
     wins the cascade -- an ID beats a class regardless of source order. */
  .rankings-filters { flex-direction: column; }
  #rankings-search, #rankings-country-filter { flex: none; }

  /* Stack the summary above the controls rather than letting space-between strand them at
     opposite edges of a narrow screen. */
  .pagination { justify-content: flex-start; }
  .pagination-summary { flex: 1 0 100%; }
}

/* Accepted validation issues -- collapsed by default when anything is still outstanding, so the
   list leads with what actually wants attention. */
.accepted-issues { margin-top: 1rem; }
.accepted-issues > summary {
  cursor: pointer;
  color: var(--muted);
  font-size: 0.85rem;
  font-weight: 600;
  padding: 0.35rem 0;
}
.accepted-issues > summary:hover { color: var(--text); }
.accepted-issues[open] > summary { margin-bottom: 0.25rem; }
