:root {
  --padding-root: 5px;
  --yellow: rgba(255, 220, 0, 1);
}

/* --font-color-base itself is already defined by global_dg.css
   (:root[color-mode="light"/"dark"], loaded by every page via
   main/header.html) - this used to redefine it again here with slightly
   different (harsher/pure black-white) values, competing with that one on
   an equal-specificity :root selector. removed so there's one source of
   truth. the real dark-mode gap on events pages wasn't this anyway - it was
   that nothing set a base text color on the page at all, so most content
   was silently inheriting Bootstrap's hardcoded #212529 instead of this
   variable, which happened to look fine on a light background and is
   nearly invisible on a dark one */
.page-body {
  color: var(--font-color-base);
}

/* small explanatory note under a section title - originally recent_form.html
   (SG view), now also used by skill_decomp.html */
.table-note {
  font-size: 10.5px;
  opacity: 0.7;
  margin-top: 3px;
  margin-bottom: 5px;
}

.table-note a {
  color: var(--blue);
}

/* popover body styling - originally live_model's shot-marker/win-prob
   tooltips (event_live_model.css), promoted here since recent_form.html's
   win-circle markers use the same hover-popover pattern. the arrow/border
   colors are already handled globally (global_dg.css, --pop-body-col) */
.popover-body {
  font: 10px Helvetica;
  padding-top: 4px;
  background-color: var(--pop-body-col);
  color: var(--font-color-base);
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

/* one marker per win, hover for the year/event - matches live_model's
   shot-circle marker sizing. 0.5-opacity fill + solid border by default
   (grey, same pairing TOUR_COLORS/MAJOR_COLORS use in recent_form.html/
   qualification.html) - anything not PGA/EURO/KFT/LIV or a major (eg. CHA)
   falls back to this rather than needing its own entry in TOUR_COLORS
   first. originally recent_form.css, promoted here since qualification.html's
   Wins column now uses the same marker/popover pattern */
.win-marker {
  display: inline-block;
  box-sizing: border-box;
  width: 9.5px;
  height: 9.5px;
  border-radius: 50%;
  border: 1px solid rgb(150, 150, 150);
  background-color: rgba(150, 150, 150, 0.5);
  margin: 0 1.5px;
  cursor: pointer;
}

.win-marker.win-square {
  border-radius: 1px;
}

/* generic numeric-column look - originally predictions.html, now also used
   by skill_decomp.html. position:relative so .prob-bar-outer (below) can
   anchor to whichever cell needs a bar */
.col-pct {
  position: relative;
  width: 90px;
  text-align: center;
}

/* positioning context for .paywall-overlay below */
.paywall-table-wrap {
  position: relative;
}

/* purely cosmetic - the real data behind these rows was never sent to the
   browser in the first place (see predictions()/skill_decomp() in
   events/routes.py), so there's nothing this blur is actually protecting
   on its own */
.paywall-blur-row {
  filter: blur(4px);
  pointer-events: none;
  user-select: none;
}

/* no background - the rows underneath stay visible (just blurred), not
   hidden behind a solid panel. top offset is set inline per-page (depends
   on that page's own free-rows count), so this sits right at the start of
   the blurred section */
.paywall-overlay {
  position: absolute;
  left: 0;
  right: 0;
  display: flex;
  justify-content: center;
  padding-top: 20px;
}

.paywall-message {
  max-width: 260px;
  background-color: var(--container-color-base);
  border: var(--container-border-base);
  border-radius: 2px;
  padding: 10px 14px;
  font-size: 11px;
  line-height: 1.4;
  text-align: center;
}

.paywall-message a {
  color: var(--olive);
  font-weight: 600;
}

.paywall-message .fa-lock {
  color: var(--red);
}

/* probability bar - originally live_model's Win% column, now shared since
   predictions.html uses the exact same treatment for its own probability
   columns. positioning is relative to the cell's padding box (not content
   box), so it fills the full cell regardless of that cell's own padding -
   the cell just needs position:relative and no fixed height assumptions */
.prob-bar-outer {
  position: absolute;
  left: 0px;
  top: 0px;
  width: 100%;
  height: 100%;
  border-left: var(--container-border-base);
  display: flex;
  align-items: center;
}

.prob-bar {
  position: absolute;
  left: 0px;
  height: 60%;
  border: 1px solid var(--olive);
  background-color: var(--olive-light);
  border-left: none;
  border-top-right-radius: 1px;
  border-bottom-right-radius: 1px;
}

/* text sits inside the bar once it's over half full, outside (to the right)
   otherwise - keeps it readable rather than getting swallowed by a short bar */
.prob-bar-text-inside, .prob-bar-text-outside {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  left: calc(100% + 2.5px);
  font-size: 9px;
  font-weight: 550;
}

.prob-bar-text-inside {
  left: unset;
  right: 1px;
}

.super-upper-div, .upper-div, .feed-div {
  position: relative;
  margin-left: -15px;
  width: calc(100% + 30px);
  padding: var(--padding-root);
}

.upper-div {
  display: flex;
  gap: 20px;
}

/* no gap here (unlike .upper-div above) - the divider border on
   .feed-div-right draws its own separation, and matching padding on both
   sides of it (below) rebuilds the spacing a flex gap would otherwise add.
   originally built for live_model.html only (.live-model-layout), now
   promoted here so every event page gets the same divider */
.feed-div {
  display: flex;
  gap: 0;
}

.upper-div-left { flex: 4; }
.upper-div-right { flex: 1; }

.feed-div-left {
  flex: 4;
  padding-right: 12px;
}

/* matches live_model's right pane (used to be its own override in
   event_live_model.css) - every other event page rides this default too now,
   including live_stats (its own narrower flex:1 override removed) */
.feed-div-right {
  flex: 1.5;
  border-left: var(--container-border-base);
  padding-left: 12px;
}

/* mobile-only toggle row (Info/Menu) and the panel each toggle reveals -
   hidden by default so nothing flashes on desktop; shown for real inside
   the mobile breakpoint further down this file */
.mobile-toggle-row, .mobile-menu-panel {
  display: none;
}

.live-feed-box {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  vertical-align: middle;
  font-size: 10px;
  background-color: rgba(61, 153, 112, 0.7);
  border: 1px solid var(--olive);
  padding: 1.5px;
  color: white;
  padding-left: 2.5px; padding-right: 2.5px;
  margin-right: 2.5px;
  text-decoration: none;
}

a.live-feed-box {
  cursor: pointer;
}

.live-feed-box-inactive {
  background-color: transparent;
  border: var(--container-border-base);
  color: var(--font-color-faint-2);
}

/* available-but-not-selected tabs are always rendered as <a>, unavailable ones
   as a plain <div> (see _base.html) - use that to make clickable tabs a bit
   more noticeable than ones with no page behind them yet, without going full
   olive - just a darker grey than the disabled state */
a.live-feed-box-inactive {
  border: 1px solid #888;
  color: var(--font-color-base);
}

a.live-feed-box-inactive:hover {
  background-color: rgba(150, 150, 150, 0.15);
}

/* Live Coverage gets its own always-on treatment (not the plain selected/
   inactive olive-vs-grey split every other tab uses) whenever it's actually
   available for this event - green outline instead of a solid fill, plus a
   red "on air" dot so it reads as live, not just another enabled tab */
.live-feed-box-live {
  background-color: transparent;
  border: 1px solid var(--olive);
  color: var(--olive);
}

a.live-feed-box-live:hover {
  background-color: rgba(61, 153, 112, 0.15);
}

.live-feed-dot {
  display: inline-block;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background-color: var(--red);
  margin-right: 4px;
}

.breadcrumbs {
  position: relative;
  margin-left: -15px;
  width: calc(100% + 30px);
  padding: 2px var(--padding-root);
  margin-top: 2px;
  font-size: 11px;
  color: var(--font-color-base);
}

.breadcrumbs a {
  text-decoration: none;
}

.breadcrumbs a:hover {
  text-decoration: underline;
}

.breadcrumb-sep {
  margin: 0 3px;
  opacity: 0.5;
}

.breadcrumb-current {
  opacity: 0.6;
}

.event-title {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  font-size: 20px;
  font-weight: bold;
}

/* mobile-only Info toggle sitting inline in the title - hidden by default so
   it doesn't show on desktop, revealed inside the mobile breakpoint below */
.event-title-info-toggle {
  display: none;
}

.event-infos {
  position: relative;
  font-size: 12px;
}

/* Field Strength's collapsed-by-default row (events/_base.html,
   field_strength_widget() in events/routes.py) - plain text (label, DGPs
   figure) then one bar with a dot marking this event's own position, all on
   one regular line. same label/value/track column widths as
   .field-strength-chart below, so the bar here and every comparison row's
   own bar line up exactly regardless of which rows are visible. "Compare"
   expands that chart into the full per-tour breakdown */
.field-strength-row {
  display: grid;
  grid-template-columns: 90px 65px 90px auto;
  align-items: center;
  column-gap: 0;
}

/* overrides .field-strength-chart-label's small/faint styling (meant for
   the tour names below) back to a normal .event-infos label, now that it's
   doing double duty for "Field Strength" on this row too - double-class
   selector so this wins regardless of source order relative to that rule */
.field-strength-row-label.field-strength-chart-label {
  font-size: 12px;
  opacity: 1;
}

.field-strength-value-text {
  grid-column: 2;
  font-size: 12px;
  white-space: nowrap;
}

.field-strength-default {
  grid-column: 3;
  position: relative;
  width: 90px;
  height: 6px;
  /* no margin-top for .field-strength-marker-tier's sake - this row stays
     level with every other .event-infos row (Course/Start/Field Size/Cut),
     the floating tier word above the dot just overlaps into the row above
     rather than pushing this one down to make room for it */
}

.field-strength-track {
  position: absolute;
  inset: 0;
  border-radius: 3px;
  background-color: rgba(150, 150, 150, 0.2);
}

.field-strength-marker-wrap {
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
}

.field-strength-marker-dot {
  display: block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background-color: var(--olive);
  border: 2px solid var(--black-base);
}

/* this event's tier (Elite/Strong/Average/Weak/Minor), colored on a
   continuous green-to-red scale by its own tier_color (field_strength_
   widget() in events/routes.py) rather than a fixed color per word - two
   "Strong" weeks on opposite ends of that tier's own range still read as
   subtly different shades instead of looking identical */
.field-strength-marker-tier {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-bottom: 1px;
  font-size: 8px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.2px;
  white-space: nowrap;
}

/* same Show/Hide toggle-link look weather.html's own .weather-leadin-toggle
   uses - text itself swaps between the two states, no separate icon */
.field-strength-toggle {
  justify-self: start;
  margin-left: 8px;
  font-size: 9px;
  font-weight: 600;
  color: #0074D9;
  cursor: pointer;
}

/* per-tour typical-range chart under the Field Strength line - a labeled
   row per tour (grid-row set inline per row, field_strength_widget()'s own
   tour order), all sharing one 0-28 scale so every row's % position means
   the same DG-points value. the current event's own tour row is bolded to
   stand out from the other 3 reference tours */
.field-strength-chart {
  display: grid;
  /* same 90px/65px/90px columns as .field-strength-row above (the middle
     column just sits empty here - no per-tour value text) - identical
     widths are what keep every bar lined up with the one on that row,
     rather than stretching to fill whatever space is left over */
  grid-template-columns: 90px 65px 90px;
  grid-template-rows: repeat(5, auto);
  row-gap: 0px;
  align-items: center;
  position: relative;
  margin-top: 4.5px;
}

.field-strength-chart-label {
  grid-column: 1;
  font-size: 9px;
  opacity: 0.7;
}

.field-strength-chart-label-current {
  font-weight: 700;
  opacity: 1;
}

.field-strength-chart-track {
  grid-column: 3;
  position: relative;
  height: 6px;
  border-radius: 3px;
  background-color: rgba(150, 150, 150, 0.15);
  /* keeps the Majors sliver's own min-width (.field-strength-chart-range-
     majors) from poking out past the track's right edge when its computed
     left position (near 100%) plus that minimum width would otherwise
     overflow it */
  overflow: hidden;
}

/* the box (p10-p90, a typical week) - solid and full track height, drawn
   on top of the whisker line below so the "common range" clearly reads as
   the dominant shape and the min/max spread as the secondary one */
.field-strength-chart-range {
  position: absolute;
  top: 0;
  height: 100%;
  border-radius: 3px;
  background-color: rgba(150, 150, 150, 0.5);
}

/* the whisker (min-max, the real outlier weeks that tour's own history
   hit) - a thin center line, same idea as a standard box-and-whisker plot
   laid on its side (just the line, no end-cap ticks). much thinner than the
   box above so it still reads as "behind" it rather than competing */
.field-strength-chart-whisker {
  position: absolute;
  top: 50%;
  height: 2px;
  opacity: 0.5;
  transform: translateY(-50%);
}

/* each tour gets its own fixed color rather than a shared grey - which row
   is the current event's own tour is marked by the bold label instead
   (.field-strength-chart-label-current) now that color means "which tour"
   rather than "is this the one" */
.field-strength-chart-range-pga,
.field-strength-chart-whisker-pga {
  background-color: var(--red);
}

.field-strength-chart-range-euro,
.field-strength-chart-whisker-euro {
  background-color: var(--blue);
}

.field-strength-chart-range-kft,
.field-strength-chart-whisker-kft {
  background-color: var(--olive);
}

.field-strength-chart-range-liv,
.field-strength-chart-whisker-liv {
  background-color: var(--font-color-base);
}

/* Majors isn't a real range (every major pays exactly the 28.0 scale max,
   no spread at all) - a gold tick right at the ceiling instead of a solid
   bar, same color the points-distribution table itself uses to call majors
   out. min-width keeps that 1-2% sliver from rounding away to nothing. no
   whisker either - majors really did pay out 28.0 exactly every time, so
   there's no min/max spread to show */
.field-strength-chart-range-majors {
  background-color: #ffd54f;
  min-width: 3px;
}

.field-strength-chart-whisker-majors {
  display: none;
}

/* compact current-conditions widget, events/_base.html's own shared
   e_data['current_weather'] - already part of the same leaderboard API
   response every event route already fetches for e_data itself, so this
   renders synchronously with the rest of the page, no extra request and
   no popping-in/layout-shift the way a client-side fetch would cause */
.event-current-weather {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: -14px;
  margin-bottom: -14px;
  color: inherit;
  text-decoration: none;
}

a.event-current-weather:hover {
  opacity: 0.75;
}

/* events.current_weather_icon (events/routes.py) - best-effort icon from
   weather_desc text, since this lighter field has no icon/code of its own */
.event-current-weather-icon {
  width: 72px;
  height: 72px;
  margin-left: -10px;
}

.event-current-weather-lines {
  display: flex;
  flex-direction: column;
  line-height: 1.3;
  font-size: 10px;
}

.event-current-weather-desc {
  font-size: 11px;
  font-weight: 700;
}

.event-current-weather-secondary {
  font-size: 9px;
  font-weight: 400;
  color: var(--font-color-faint-2);
}

/* dark mode: dial back everything except the bold label (Course, Start,
   etc.) - the label stays full-strength, the value next to it reads as
   secondary/reference info rather than competing with it */
:root[color-mode="dark"] .event-infos {
  color: var(--font-color-faint);
}

:root[color-mode="dark"] .event-infos strong {
  color: var(--font-color-base);
}

.feed-section-margin-top {
  margin-top: 10px;
}

.feed-section-title {
  font-size: 13px;
  font-weight: bold;
}

/* title + a small control (select, toggle, etc) on one line - promoted from
   course_fit.css once hole_stats.css needed it too */
.feed-section-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.view-option-list {
  display: flex;
  flex-direction: column;
  gap: 0;
  margin-top: 5px;
}

.view-option-item {
  font-size: 10.5px;
  padding: 2px 6px;
  text-decoration: none;
  color: var(--font-color-base);
  border-radius: 0;
}

/* _live_menu.html's own "LIVE" tag beside Cut Sweat - same red/bold/
   letter-spacing treatment as .event-status-live-tag above */
.cut-sweat-menu-live-tag {
  color: var(--red);
  font-weight: 700;
  font-size: 9px;
  letter-spacing: 0.3px;
}

.view-option-item:hover {
  background-color: rgba(150, 150, 150, 0.25);
}

/* Course History/Course Fit read as sub-pages of Skill Decomposition
   (events/_scratch_menu.html) - indented with a small dot rather than
   sitting flush with the rest of the menu's own top-level items */
.view-option-sub {
  padding-left: 22px;
  position: relative;
}

.view-option-sub::before {
  content: '';
  position: absolute;
  left: 9px;
  top: 50%;
  transform: translateY(-50%);
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background-color: var(--font-color-faint-2);
}

.view-option-selected {
  background-color: rgba(255, 220, 0, 0.15);
  color: var(--blue);
  font-weight: 600;
}

/* keep the selected tab's yellow bg on hover - :hover alone outranks the
   single .view-option-selected class on specificity, so without this the
   hover rule's olive tint would win and flash over the selected state */
.view-option-item.view-option-selected:hover {
  background-color: rgba(255, 220, 0, 0.15);
}

/* dark mode: a 15%-alpha yellow over a near-black background doesn't read as
   "yellow" - it just barely lifts the black toward a muddy olive-brown, since
   there isn't enough luminance underneath for the tint to show through.
   switched to a blue tint instead (matches the text color already used here)
   rather than just cranking the yellow's alpha up */
:root[color-mode="dark"] .view-option-selected,
:root[color-mode="dark"] .view-option-item.view-option-selected:hover {
  background-color: rgba(0, 116, 217, 0.2);
}

/* no page behind it yet - looks like a menu item but isn't clickable */
.view-option-disabled {
  opacity: 0.5;
  cursor: default;
}

.view-option-disabled:hover {
  background-color: transparent;
}

.view-option-divider {
  border-top: 1px solid rgba(150, 150, 150, 0.3);
  margin: 0;
}

/* Scratch Tools Menu access indicator - same green check the site banner
   (banner.css .banner-scratch-check) shows next to the user icon for an
   active Scratch member, red lock otherwise */
.scratch-auth-check {
  color: var(--olive);
  font-size: 8px;
  margin-left: 1px;
  vertical-align: middle;
}

.scratch-auth-lock {
  color: var(--red);
  font-size: 8px;
  margin-left: 1px;
  vertical-align: middle;
}

/* leaderboard stuff - shared base look only. page-specific columns/features
   (win probability, scorecards, SG/DG-points bars, rank-tier coloring, etc.)
   live in each page's own stylesheet: field_list.css / recent_form.css /
   event_live_model.css, loaded via that page's head_extra block */
.leaderboard {
  margin-top: 5px;
  margin-bottom: 15px;
  width: 100%;
  table-layout: fixed;
  border-collapse: separate;
  border-spacing: 0;
}

.leaderboard > thead > tr > th {
    position: sticky;
    top: 0;
    background: var(--black-base);
    z-index: 10;
    border-bottom: 1px solid var(--font-color-base);
}

.leaderboard tbody td {
  border-bottom: var(--container-border-base);
}

/* pos/neg strokes-gained bar, originally built for recent-form's SG columns,
   now shared with live-stats too - a bar-container div holds an axis line, the
   fill itself, and a text label, with .sg-bar-pos/.sg-bar-neg picking the color */
.col-sg {
  width: auto;
  text-align: center;
}

.col-sgcat {
  width: auto;
  text-align: center;
}

.sg-bar-container {
  position: relative;
  height: 14px;
}

.sg-axis {
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 1px;
  background-color: #666;
  z-index: 1;
}

.sg-bar {
  position: absolute;
  top: 1px;
  bottom: 1px;
  border-radius: 1px;
  opacity: 0.7;
  display: none;
}

.sg-bar-pos { background-color: var(--olive); border-top-left-radius: 0; border-bottom-left-radius: 0; }
.sg-bar-neg { background-color: #FF4136; border-top-right-radius: 0; border-bottom-right-radius: 0; }

.sg-bar-text {
  position: absolute;
  top: 0;
  line-height: 14px;
  font-size: 10px;
  white-space: nowrap;
}

/* sortable column headers - click state (cursor + ▲/▼ indicator), shared by
   every page with a data-sort click handler on its .leaderboard table */
.leaderboard > thead > tr > th[data-sort] {
  cursor: pointer;
  user-select: none;
}

.leaderboard > thead > tr > th[data-sort]::after {
  content: '';
  margin-left: 3px;
  font-size: 9px;
}

.leaderboard > thead > tr > th.sorted-asc::after { content: '\25B2'; }
.leaderboard > thead > tr > th.sorted-desc::after { content: '\25BC'; }

.leaderboard > thead > tr, .leaderboard > tbody > tr { height: 25px; }

.leaderboard > thead > tr > th { font-weight: 500; font-size: 11px; }

.leaderboard > tbody > tr > td { font-size: 11px; }

/* row hover, reusing live-model's existing blue - deliberately no cursor:pointer
   here since (unlike live-model's click-to-expand rows) these rows aren't
   themselves clickable, only the star/name links inside them are. live-model
   keeps its own .player-row:hover (event_live_model.css, loaded after this
   file) with the same color plus cursor:pointer and .expanded-state handling. */
.player-row:hover, .tt-row:hover {
  background-color: rgba(173, 216, 230, 0.3);
}

/* dark mode: the light-blue tint above reads as washed-out/muddy against a
   near-black background (it's a pastel, needs a light background to pop) -
   same fix live-model already uses on its own .player-row:hover
   (event_live_model.css), now applied here so every other page sharing this
   rule (field list, tee times, predictions, etc.) gets the same olive tint
   instead of just live-model */
:root[color-mode="dark"] .player-row:hover,
:root[color-mode="dark"] .tt-row:hover {
  background-color: var(--green-hover);
}

/* min/max alongside width doesn't actually cap this under table-layout:fixed
   (what every page using this ends up with) - confirmed in the browser: with
   no genuinely auto column left once col-pct goes fixed-px at mobile
   (predictions.css etc.), the fixed layout algorithm distributes the table's
   leftover width proportionally across every px-only column, .col-star
   included, regardless of its own max-width (browsers silently ignore
   min/max-width on table cells once the column width's already been
   resolved by the fixed-layout algorithm - this file still declares them, in
   case a future column scheme frees up a real auto column again). so instead
   of fighting the cell's own box, the icon is pinned to the cell's left edge
   - any extra width the algorithm hands this column becomes invisible
   trailing space after the star rather than a growing gap in front of the
   player name next to it */
.col-star {
  width: 20px;
  min-width: 20px;
  max-width: 20px;
  text-align: left;
  padding-left: 3px;
}

/* score coloring, originally built for live-model, now shared with live-stats
   too - over-par is intentionally left unstyled (default text color) */
.under-par { color: red; }
.even-par { color: green; }

/* shows a player's tee time in the thru column when they haven't started yet
   (thru == -9999) - smaller font since "H:MM" is wider than a plain number */
.leaderboard > tbody > tr > td.col-thru-teetime {
  font-size: 10px;
}

.fave-star {
  cursor: pointer;
  color: var(--olive);
  font-size: 11px;
  vertical-align: middle;
}

.favourites-header-star {
  color: var(--olive);
  font-size: 11px;
}

/* show/hide toggle next to the Favourites section title - collapsed by
   default so favourites don't take up space when the user doesn't want them */
.favourites-toggle {
  font-size: 10.5px;
  font-weight: normal;
  margin-left: 2px;
  color: var(--olive);
  text-decoration: none;
}

.favourites-toggle:hover {
  text-decoration: underline;
}

/* shown instead of a favourites table while it's empty - a plain div rather
   than a colspanned row, so it isn't squeezed by the table's own column widths */
.no-faves-message {
  font-size: 11px;
  color: var(--font-color-faint-2);
  text-align: center;
  padding: 8px;
  margin-top: 5px;
  border: 1px dashed rgba(150, 150, 150, 0.4);
}

.col-player {
  width: 40%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin: 0;
}

/* player column gets a fixed share of the table; the other (now width-less)
   data columns split whatever's left in table-layout: fixed */
.field-list-table .col-player {
  width: 30%;
}

.col-dgr, .col-owgr, .col-fec, .col-rtd, .col-age {
  width: 40px;
  text-align: center;
}

.col-player .last {
  font-weight: 600;
}

.col-player a {
  color: var(--font-color-base) !important;
}

.col-player img.player-flag {
  height: 14.5px;
  width: auto;
  vertical-align: middle;
}

.column-toggle {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    margin-right: 2.5px;
    font-size: 12px;
}

.column-toggle label {
    margin: 0;
    cursor: pointer;
}

.column-toggle input {
    margin: 0;
}

.column-toggle input[type="checkbox"] {
    width: 12px;
    height: 12px;
}

/* generic slider-switch toggle - moved here from event_live_model.css (where
   it was named .all-probs-toggle*, after the one feature it was first built
   for) since the same geometry was already being reimplemented under a
   different class name on nearly every other page with a toggle
   (hole_stats.css's Early vs Late, course_fit.html's Relative Importance,
   course_history/pressure_tool/etc.) - this is the version to reuse instead
   of adding yet another copy. class names kept as .all-probs-toggle* for
   now (live_model.html's markup uses them as-is) rather than a renaming
   pass across every page that would need one */
.all-probs-toggle-row {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  cursor: pointer;
  margin-left: auto;
  margin-right: 6px;
  /* .column-options' (event_live_model.css) align-items: center centers
     this against the select's full border+padding box, which sits a couple
     px lower than this row's own (shorter) content - nudge down to match */
  position: relative;
  top: 2px;
}

.all-probs-toggle {
  position: relative;
  display: inline-block;
  width: 18px;
  height: 11px;
}

.all-probs-toggle input {
  opacity: 0;
  width: 0;
  height: 0;
}

.all-probs-toggle-slider {
  position: absolute;
  inset: 0;
  background-color: var(--toggle-back-color);
  border-radius: 11px;
  cursor: pointer;
  transition: 0.15s;
}

.all-probs-toggle-slider:before {
  position: absolute;
  content: "";
  height: 7px;
  width: 7px;
  left: 2px;
  top: 2px;
  border-radius: 50%;
  background-color: var(--toggle-circle-color);
  transition: 0.15s;
}

.all-probs-toggle input:checked + .all-probs-toggle-slider {
  background-color: var(--olive);
}

.all-probs-toggle input:checked + .all-probs-toggle-slider:before {
  transform: translateX(7px);
}

/* mobile - the Age/DGR/OWGR/FEC column checkboxes and the All Probabilities
   switch both take up more room than they need once the page has shrunk
   this far, same breakpoint used throughout this file */
@media (max-width: 900px) {
  /* favourite star - moves into the scorecard itself (.scorecard-fave-star,
     same .fave-star class + dg-id, so it stays in sync for free) rather
     than just disappearing - the row no longer has a quick one-click
     favourite, but reclaims that width for the name, which needs it more.
     only the 3 pages with a scorecard to move it into (live_model/live_stats/
     final_results, each tagged with its own table class below) - every other
     page's .col-player also contains a .fave-star (tee_times inline, or via
     _player_name.html's {% call %} block) with nowhere else for it to go, so
     a bare ".col-player .fave-star" selector here would wrongly hide those
     too. .fave-star-wrap (live_stats.html/final_results.html) wraps the icon
     together with its own trailing &nbsp; so both disappear as one unit -
     hiding just the icon left that space rendering on its own as a stray
     gap before the flag. live_model.html's own star isn't wrapped (its
     JS-built markup never had the same trailing &nbsp; to begin with), so
     the plain .fave-star rule below still covers it directly */
  .live-model-table .fave-star,
  .live-stats-table .fave-star-wrap,
  .live-stats-table .fave-star,
  .final-results-table .fave-star-wrap,
  .final-results-table .fave-star {
    display: none;
  }

  .scorecard-fave-star {
    margin-right: 4px;
  }

  .column-toggle {
    font-size: 10.5px;
    gap: 1.5px;
    margin-right: 4px;
  }

  .column-toggle input[type="checkbox"] {
    width: 11px;
    height: 11px;
  }

  .all-probs-toggle-row {
    font-size: 10.5px;
    gap: 5px;
    /* 1px more than the desktop top:2px nudge above */
    top: 3px;
  }

  .all-probs-toggle {
    width: 16px;
    height: 10px;
  }

  .all-probs-toggle-slider:before {
    height: 6px;
    width: 6px;
  }

  .all-probs-toggle input:checked + .all-probs-toggle-slider:before {
    transform: translateX(6px);
  }
}

/* accent-color alone only recolors the checked fill - the box itself (border/
   background) still renders via the OS's light UI chrome by default, which
   is a stark white square against a dark page. color-scheme tells the native
   control to draw itself with dark chrome instead, scoped to just these
   inputs so it doesn't touch anything else (eg. the scrollbar, which already
   has its own hand-built dark theme in global_dg.css) */
:root[color-mode="dark"] .page-body input[type="checkbox"],
:root[color-mode="dark"] .page-body input[type="radio"] {
  color-scheme: dark;
}

.hidden-column {
    display: none;
}

/* shared DGR/OWGR/FEC rank-tier badge - field_list.css had its own copy of
   this (it still does, harmless duplicate, same specificity/loaded-after
   wins there); promoted here so live_model can use it too without a third
   copy, matching this session's usual "promote once 2+ pages need it" rule */
.rank-outer {
  display: inline-block;
  min-width: 32px;
  margin: 0 auto;
  padding: 3px 6px;
  border-radius: 1px;
  font-size: 10px;
  text-align: center;
}

.dg-100 { background-color: var(--olive-lighter); }
.dg-30 { background-color: var(--olive-light); }
.dg-10 { background-color: var(--olive); }
.dg-1 { background-color: var(--yellow); color: black; }

.owgr-100 { background-color: var(--container-color-base); }
.owgr-10 { background-color: rgb(180,180,180); color: black; }
.owgr-1 { background-color: rgba(255, 133, 27, 0.75); color: black; }

.pga-30, .pga-3000 { background-color: rgba(31, 202, 35, 0.5); }
.pga-50 { background-color: rgba(255, 133, 27, 0.55); }
.pga-70 { background-color: rgba(177, 13, 201, 0.55); }
.pga-125 { background-color: rgba(150,150,150, 0.55); }

/* RTD (Race to Dubai) equivalent of the pga-* tiers above - same 2 colors
   tour_standings.html already uses for this (.eur-10/.eur-125,
   tour_standings.css), reused here rather than invented fresh */
.eur-10 { background-color: rgba(92, 187, 124, 0.55); }
.eur-125 { background-color: rgba(231, 43, 101, 0.55); }

/* switch to "C. Young" once the player column itself gets tight, rather than at
   a page-level breakpoint - this tracks the column's actual rendered width, so
   it also kicks in from things like browser zoom, not just narrow screens.
   container-type has to go on a wrapper div, not the <td> itself - table cells
   are one of the "internal table" display types the containment spec excludes,
   so browsers just silently ignore container-type set directly on a td. */
.player-col-inner {
  container-type: inline-size;
  container-name: player-col;
  /* .col-player itself already has this (overflow/text-overflow/white-space
     below) but that only constrains .col-player's own inline content - it
     doesn't reach into a block-level child like this div, so a long name
     was wrapping or spilling out instead of truncating */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.col-player .short-first { display: none; }

@container player-col (max-width: 200px) {
  .col-player .full-first { display: none; }
  .col-player .short-first { display: inline; }
}

/* client-side player-name filter box, shared by field-list/recent-form/tee-times */
.table-search {
  font-family: inherit;
  font-size: 11px;
  padding: 2px 6px;
  border: 1px solid rgba(150, 150, 150, 0.4);
  border-radius: 1px;
  width: 200px;
  margin-top: 5px;
  margin-bottom: 5px;
  color: var(--font-color-base);
  background: transparent;
}

.table-search:focus {
  outline: none;
  border-color: var(--olive);
}

/* generic radio/checkbox-toggle row - originally built for recent-form's
   3/6/12/24-month window switcher, now shared with tee-times' round switcher */
.form-window-options {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 5px;
  margin-bottom: 2px;
}

.form-window-option {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  color: var(--font-color-base);
  cursor: pointer;
}

/* Tournament Progress widget (_tournament_progress.html) - shared by every
   "live" page (live_model.html, live_stats.html, hole_stats.html), filled in
   by render_round_progress() (static/tournament_progress.js). originally
   lived only in event_live_model.css */
/* shown page-wide whenever any round's own round_status is 'RUS' (same
   signal each round's own SUSPENDED tag below uses) - toggled by
   render_round_progress() itself, not a per-page thing, so every page
   that includes _tournament_progress.html picks it up for free */
.event-suspended-banner {
  margin-bottom: 8px;
  padding: 3px;
  background-color: rgba(250, 225, 0, 0.5);
  border: 1px solid #FAE100;
  border-radius: 4px;
  font-size: 10px;
  font-weight: 600;
  color: rgb(20, 20, 20);
  text-align: center;
}

/* light mode keeps the filled yellow box above - dark mode drops the fill
   and reads as just gold border + matching gold text instead, same
   treatment the round card's own SUSPENDED tag now uses there too */
:root[color-mode="dark"] .event-suspended-banner {
  background-color: transparent;
  color: #FAE100;
}

.event-status-outer {
  display: flex;
  gap: 2.5px;
}

.event-status {
  flex: 1;
  height: 50px;
  border: var(--container-border-base);
  box-sizing: border-box;
  padding: 3px 4px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 3px;
}

.event-status-title {
  font-size: 9px;
}

/* "Round N" (desktop) vs "RN" (mobile, below) - two spans toggled by the
   same breakpoint everything else in this file uses, not JS - the widget's
   JS (tournament_progress.js) only ever touches the bar/detail text, never
   this title, so there's nothing there to update for a text swap */
.event-status-round-label-mobile {
  display: none;
}

/* "Top 10 %" (desktop) vs "T10 %" (mobile, below) - same two-span pattern
   as the Tournament Progress round labels above, for the All Probs view's
   fixed Top 5/10/20/Make Cut column headers (live_model.html) */
.prob-col-label-mobile {
  display: none;
}

/* only shown while a round is in progress (0% < pct_complete < 100%) -
   toggled via .event-status-live (render_round_progress()) */
.event-status-live-tag {
  display: none;
  color: var(--red);
  font-weight: 700;
  letter-spacing: 0.3px;
}

.event-status-live .event-status-live-tag {
  display: inline;
}

/* shown once a round's start time is known but it hasn't teed off yet -
   toggled via .event-status-upcoming (render_round_progress()) */
.event-status-upcoming-tag {
  display: none;
  color: var(--olive);
  font-weight: 700;
  letter-spacing: 0.3px;
}

.event-status-upcoming .event-status-upcoming-tag {
  display: inline;
}

/* shown once a round's own round_status comes back 'RUS' (render_round_
   progress(), tournament_progress.js) - a distinct color from both LIVE
   (red) and UPCOMING (olive) so a suspended round doesn't read as either.
   just the tag itself carries the yellow now, as its own small badge - not
   the whole card's background the way an earlier pass tried */
.event-status-suspended-tag {
  display: none;
  background-color: rgba(250, 225, 0, 0.6);
  border-radius: 2px;
  padding: 1px 3px;
  color: rgb(20, 20, 20);
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.3px;
}

:root[color-mode="dark"] .event-status-suspended-tag {
  background-color: transparent;
  color: #FAE100;
}

.event-status-suspended .event-status-suspended-tag {
  display: inline;
}

.event-status-bar-outer {
  height: 6px;
  background-color: rgba(150, 150, 150, 0.25);
  border-radius: 1px;
  overflow: hidden;
}

.event-status-bar-fill {
  height: 100%;
  width: 0%;
  background-color: var(--olive);
}

/* round hasn't started yet - round_progress (leaderboard API) has no entry
   for it. bar stays empty; detail text shows a "starts in..." countdown
   once event.round_starts has a tee time for it (render_round_progress()),
   blank until then */
.event-status-pending .event-status-bar-fill {
  background-color: transparent;
}

.event-status-detail {
  font-size: 8px;
  opacity: 0.65;
}

.event-status-pending .event-status-detail {
  font-style: italic;
}

/* mobile - the fixed 50px height (above) leaves real dead space below the
   title/bar/detail lines once the surrounding page has already shrunk down
   (same breakpoint the scorecard/leaderboard columns use elsewhere in this
   file). auto lets each box size off its own content instead */
@media (max-width: 900px) {
  .event-status {
    height: auto;
    padding: 2px 4px;
    gap: 2px;
  }

  .event-status-title {
    font-size: 8px;
  }

  .event-status-round-label {
    display: none;
  }

  .event-status-round-label-mobile {
    display: inline;
  }

  .event-status-detail {
    font-size: 7px;
  }

  .prob-col-label-full {
    display: none;
  }

  .prob-col-label-mobile {
    display: inline;
  }
}

/* basic scorecard shell - promoted from event_live_model.css now that
   final_results.html needs the same click-to-expand table/row structure
   (its own scorecard is simpler - no shot markers/hole-detail-hover/
   sg-total-row, those stay live_model-specific) */
.scorecard-row {
    display: none;
}

.scorecard-row.open {
    display: table-row;
}

.scorecard-row td {
    padding: 0;
    border-bottom: none;
}

.scorecard-container {
    width: 100%;
    padding: 0px;
    box-sizing: border-box;
}

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

/* groups round-select + the Front/Back toggle (mobile only) together on the
   left, so the toggle sits right beside the round picker it's modifying
   instead of floating in the middle via .scorecard-header's own
   space-between - .scorecard-round-info stays the lone item on the right */
.scorecard-header-left {
    display: flex;
    align-items: center;
    gap: 6px;
}

.scorecard-round-info {
    font-size: 10px;
    opacity: 0.6;
}

.round-select {
    font-family: inherit;
    font-size: 10px;
    padding: 1px 2px;
    border: 1px solid rgba(150, 150, 150, 0.4);
    border-radius: 1px;
    background: transparent;
    color: var(--font-color-base);
    cursor: pointer;
}

/* the select box itself is styled above (transparent bg, theme-aware text/
   border), but the dropdown's own popup list is still native OS chrome -
   without this it stays light-themed (white bg, black text) even in dark
   mode, since color-scheme is what tells it which chrome to draw */
:root[color-mode="dark"] .round-select {
    color-scheme: dark;
}

.scorecard {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
}

.scorecard th,
.scorecard td {
    text-align: center;
    padding: 5px;
    font-size: 10px;
    white-space: nowrap;
    /* belt-and-suspenders against .scorecard-view-front/-back below - if a
       column ever ends up narrower than its own content (eg. Dist.'s 3-digit
       yardages squeezed into a column sized for Par's single digit), this
       clips it instead of letting it visually bleed into the next cell */
    overflow: hidden;
}

.scorecard th {
  font-weight: 600;
}

.scorecard .label {
    width: 75px;
    text-align: left;
    font-weight: 600;
    font-size: 10px !important;
    padding-left: 5px !important;
}

.scorecard .total {
    width: 35px;
    font-weight: 600;
    background: var(--container-color-base);
}

/* Front/Back scorecard toggle - mobile only. 18 hole columns + label + OUT/
   IN/TOT is too many to stay legible once .scorecard's own table-layout:fixed
   squeezes them into a phone-width viewport, so below this breakpoint the
   card shows just one 9-hole half at a time instead, switched via
   .scorecard-view-front/-back on .scorecard-container (bind_scorecard_view_
   toggle(), shared per-page JS - live_model.html/live_stats.html/
   final_results.html each have their own copy, same as the rest of the
   scorecard's build/fill logic). hidden entirely above the breakpoint - the
   full 18-hole view has room to breathe there already */
/* single link naming the OTHER half (the one not currently shown), not a
   two-button pair - "Back 9 »" while Front is open, flips to "« Front 9"
   once clicked. data-view holds which view clicking it switches TO (shared
   per-page JS swaps both the class and this element's own text/data-view
   together, so the link always names the hidden half) */
.scorecard-view-toggle {
  display: none;
  font-size: 10px;
  font-weight: 600;
  color: var(--olive);
  cursor: pointer;
  white-space: nowrap;
}

@media (max-width: 900px) {
  .scorecard-view-toggle {
    display: inline-block;
  }

  /* nth-child, not [data-hole] - cheaper to hold one column-index range than
     list out 9 individual hole numbers twice, and the column order (label,
     holes 1-9, OUT, holes 10-18, IN, TOT) is identical across every row.
     this block has to come after the plain .scorecard{table-layout:fixed}
     rule above (same specificity either way - a media query doesn't add any -
     so whichever comes LAST in the file wins the cascade, matched or not) */
  .scorecard-view-back .scorecard th:nth-child(n+2):nth-child(-n+11),
  .scorecard-view-back .scorecard td:nth-child(n+2):nth-child(-n+11) {
    display: none;
  }

  .scorecard-view-front .scorecard th:nth-child(n+12):nth-child(-n+21),
  .scorecard-view-front .scorecard td:nth-child(n+12):nth-child(-n+21) {
    display: none;
  }

  /* table-layout:fixed locks each column's width in from the full 22-column
     count up front - hiding 9 of them via display:none doesn't free their
     space back up for the rest to expand into, leaving a gap on the right
     instead of a full-width card. auto lets the remaining visible columns
     size off their own content, then stretch to fill the row (the standard
     table-width algorithm for auto layout + a specified width) */
  .scorecard {
    table-layout: auto;
  }

  /* auto layout still won't let the table grow past its own 100% width to
     fit a row's widest content (Dist.'s 3-digit yardages, chiefly) - it
     compresses every column instead, which is what was overflowing into
     neighboring cells before the overflow:hidden above started clipping it.
     tighter padding/font claws back real room so 3 digits actually fit
     without needing to clip at all */
  .scorecard th,
  .scorecard td {
    padding: 3px 1px;
    font-size: 9px;
  }

  /* everything else in the card shrinks a notch too, shared here (not
     per-page) so live_stats.html and any future scorecard page get the same
     treatment automatically instead of needing their own copy. .label/.total
     especially - at 75px+35px+35px those ate a third of a ~380px card on
     their own before even getting to the 9 hole columns */
  .scorecard .label {
    width: 50px;
    font-size: 9px !important;
    padding-left: 3px !important;
  }

  .scorecard .total {
    width: 28px;
  }

  .scorecard-header-left {
    gap: 4px;
  }

  .round-select {
    font-size: 9px;
    padding: 1px;
  }

  .scorecard-round-info {
    font-size: 9px;
  }

  .scorecard-view-toggle {
    font-size: 9px;
  }
}

.scorecard tr {
    border-bottom: var(--container-border-base);
}

.scorecard thead tr {
    border-top: 1px solid var(--olive);
}

.scorecard tbody tr:last-child {
    border-bottom: none;
}

.scorecard tr > td:last-child {
  border-right: none !important;
}

.scorecard tr.par-row > td {
  font-size: 9.5px;
  padding: 3px;
}

.scorecard tr.score-row > td {
  font-size: 11px;
  padding: 7px 5px;
}

.scorecard tr.status-row > td {
  font-size: 9.5px;
  padding: 3px;
}

.scorecard tr.sg-total-row > td {
  font-size: 9px;
  padding: 2px;
}

/* per-hole SG text is hidden until hovered, to cut down on clutter - the
   color-coded background still shows either way. OUT/IN/TOT stay visible. */
.scorecard tr.sg-total-row > td[data-hole] {
  color: transparent;
}

.scorecard tr.sg-total-row > td[data-hole]:hover {
  color: inherit;
}

.scorecard tr.score-row > td.score-eagle {
  background-color: #ffd54f;
}

/* the eagle fill is a solid opaque gold, unlike the other score colors which
   are translucent over the row's own background - dark mode's near-white
   default text (.page-body) is unreadable against it, needs to stay dark */
:root[color-mode="dark"] .scorecard tr.score-row > td.score-eagle {
  color: rgb(20, 20, 20);
}

.scorecard tr.score-row > td.score-birdie {
  background-color: rgba(61, 153, 112, 0.5);
}

.scorecard tr.score-row > td.score-bogey {
  background-color: rgba(255, 65, 54, 0.5);
}

.scorecard tr.score-row > td.score-double {
  background-color: rgba(255, 65, 54, 0.8);
}

/* mobile - .scorecard tr.score-row/.sg-total-row > td above are both more
   specific than the generic .scorecard th/td mobile shrink earlier in this
   file, so they still rendered at full desktop size there. has to come after
   those rules (same cascade-order reason as everywhere else in this file) to
   actually win */
@media (max-width: 900px) {
  /* hole number row - taller than the generic .scorecard th/td padding
     above, same reasoning as Score below (the two rows the thumb/eye
     actually anchors on - which hole, what score - get more room; Par/
     Status, read less often, give it back) */
  .scorecard thead th {
    padding: 6px 1px;
  }

  .scorecard tr.score-row > td {
    /* still the biggest text in the card - bigger than Par/Status's own 8px
       below and the 9px everything else here got shrunk to. just smaller
       than its own un-shrunk 11px desktop size */
    font-size: 10px;
    padding: 6px 1px;
  }

  .scorecard tr.par-row > td {
    font-size: 8px;
  }

  .scorecard tr.status-row > td {
    font-size: 8px;
  }

  .scorecard tr.sg-total-row > td {
    font-size: 9px;
  }
}

/* dot above whichever hole a round actually started on (eg. 10 for a
   back-nine start) - promoted from event_live_model.css alongside the rest
   of the scorecard shell, same reason */
.th-start-hole::before {
  content: '';
  display: block;
  width: 4px;
  height: 4px;
  margin: 0 auto 2px;
  border-radius: 50%;
  background-color: var(--olive);
}

/* mobile - the dot above the number (plus its own margin) makes that one
   <th> taller than the other 8 in the row, so the header row's own height
   depends on whether the start hole happens to land in whichever 9 is
   currently shown (.scorecard-view-front/-back). a background fill instead
   flags the same hole without adding any height of its own */
@media (max-width: 900px) {
  /* 10px between sections (Tournament Progress -> Favourites -> Leaderboard,
     etc.) read as too much once their own titles shrunk down - .feed-section
     is used site-wide, not just here, so this is scoped to the breakpoint
     rather than lowering the desktop default */
  .feed-section-margin-top {
    margin-top: 6px;
  }

  .th-start-hole::before {
    display: none;
  }

  .th-start-hole {
    background-color: var(--olive);
    color: white;
  }

  /* Score/Thru/Today/Win (event_live_model.css) all give up real width at
     this breakpoint - Player should pick some of it back up rather than
     stay pinned to its own desktop share. min-width, not width, same
     convention the existing 768px version of this rule already uses below */
  .col-player {
    min-width: 46%;
  }
}

/* two pre-built player-name layouts (_player_name.html's player_name_cell()
   macro, plus live_model.html's own JS-built leaderboard rows, which use the
   identical class names on purpose so they ride this same shared rule) -
   .player-name-mobile stacks flag+first name over a bolded last name,
   .player-name-desktop is the original single-line "flag F. Last" (the
   full-first/short-first @container toggle above still lives inside it,
   untouched). scoped to 900px here since it covers the "scorecard" pages
   (live_model/live_stats/final_results) that already use 900px for every
   other mobile adjustment on this table - field_list/tee_times/recent_form/
   predictions/course_fit/course_history/skill_decomp get their own 768px
   copy of this same rule further down, matching those pages' own existing
   mobile breakpoint instead */
.player-name-mobile {
  display: none;
}

@media (max-width: 900px) {
  .player-name-desktop {
    display: none;
  }

  .player-name-mobile {
    display: flex;
    flex-direction: column;
    line-height: 1.25;
    /* flex items default to min-width:auto, which keeps them from ever
       shrinking below their own text's full intrinsic width - without this,
       a long name just overflows its column instead of the ellipsis below
       ever having room to kick in. was on .player-name-link (the single <a>
       that used to wrap this whole 2-line stack) - .player-name-mobile is
       the thing actually sitting in .player-col-inner's flex row now that
       the flag/link split it into several pieces, so the shrink behavior
       moved here with it */
    flex: 1 1 auto;
    min-width: 0;
  }

  .player-name-mobile-top,
  .player-name-mobile-bottom {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
  }

  .player-name-mobile-top {
    font-size: 6.5px;
    opacity: 0.75;
    position: relative;
    top: 0.5px;
  }

  .player-name-mobile-bottom {
    font-weight: 600;
    font-size: 10px;
  }

  .player-name-mobile-bottom img.player-flag {
    height: 11px;
    margin-top: -1px;
    vertical-align: middle;
  }

  /* .player-name-mobile is display:flex (a block-level box) sitting next to
     whatever else is in .player-col-inner - fine on its own, but a page
     whose star sits as a sibling *before* it (tee_times.html) would
     otherwise get a block-level box forcing its own line next to inline
     content, stacking the star above the 2-line name instead of beside it.
     row-flex .player-col-inner itself so everything in here sits on one
     line instead. harmless on pages with nothing else in here (field_list
     etc) - a single flex item lays out the same as block would have */
  .player-col-inner {
    display: flex;
    align-items: center;
    gap: 2px;
  }
}

/* shared events-hub mobile breakpoint - kept at the very end of the file so
   it wins source order against every plain (non-media) rule above it (eg.
   .event-title, .leaderboard) at equal specificity. .upper-div/.feed-div go
   from a fixed-ratio side-by-side row to a stacked column below 768px
   (matches the site's existing Bootstrap md breakpoint). tables inside
   .feed-div-left still overflow their own width - this only fixes the outer
   layout and shared text sizing, not individual page tables */
@media (max-width: 768px) {
  /* amateur marker next to a player's name (_player_name.html's own
     player_name_cell() macro, used site-wide) - reads as more of a small
     footnote than real name text at this width */
  .amateur-tag {
    font-size: 9px;
    font-weight: normal;
    color: rgba(150, 150, 150, 0.8);
  }

  .upper-div, .feed-div {
    flex-direction: column;
  }

  .feed-div {
    gap: 12px;
  }

  .upper-div {
    gap: 0;
  }

  .upper-div-left, .upper-div-right, .feed-div-left, .feed-div-right {
    flex: none;
    width: 100%;
    padding-left: 0;
    padding-right: 0;
  }

  .feed-div-right {
    border-left: none;
    border-top: var(--container-border-base);
    padding-top: 12px;
  }

  .super-upper-div {
    padding-top: 2px;
    padding-bottom: 2px;
  }

  .live-feed-box {
    font-size: 9px;
    padding-left: 2px;
    padding-right: 2px;
    margin-right: 1px;
  }

  /* Course/Start/Field Size/Field Strength/Cut and Location/Event Time both
     collapse behind the Info toggle now - hidden until #event-info-toggle
     (events/_base.html) adds .open to both */
  .event-info-collapsible, .upper-div-right {
    display: none;
  }

  .event-info-collapsible.open {
    display: block;
  }

  /* Location/Event Time - low-value info that was eating a full stacked
     block on mobile (each on its own line, plus the checkbox row below).
     inline them onto one row instead */
  .upper-div-right.open {
    display: block;
  }

  .upper-div-right .event-infos {
    font-size: 10px;
  }

  .upper-div-right .column-toggle {
    width: 100%;
    font-size: 10px;
    margin-right: 0;
  }

  .upper-div-right .column-toggle input[type="checkbox"] {
    width: 10px;
    height: 10px;
  }

  .upper-div {
    padding-top: 1px;
  }

  .event-title {
    font-size: 16px;
    width: 100%;
    justify-content: space-between;
    align-items: center;
  }

  .event-title img {
    width: 20px;
    height: auto;
  }

  /* truncates with an ellipsis instead of pushing/overlapping the Info
     toggle sitting right after it - .event-title-text itself has no width
     constraint, so a long event name otherwise just grows past it. min-
     width:0 is needed alongside flex-shrink (the default 1 here, via
     .event-title's own inline-flex) since a flex item's natural minimum
     width is its unwrapped content's width, not 0, until this overrides it */
  .event-title-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
  }

  .rank-outer {
    min-width: 27px;
    padding: 2.5px 5px;
    font-size: 9.5px;
  }

  .fave-star, .favourites-header-star {
    font-size: 9px;
  }

  .fave-star {
    margin-right: -1px;
  }

  .table-search {
    font-size: 10px;
    padding: 2px 5px;
    width: 150px;
    margin-top: 3px;
    margin-bottom: 3px;
  }

  /* shared across every events-hub table (field list, tee times, live
     stats/model, hole stats, etc.) - guarantees the player name column
     doesn't get squeezed out by fixed-width rank/stat columns on narrow
     screens, regardless of how many of those columns a given page shows */
  .col-player {
    min-width: 30%;
  }

  .event-infos {
    font-size: 10.5px;
  }

  /* Field Strength's own label/value text (.field-strength-row, above) use
     explicit 12px rules that are more specific than .event-infos' own mobile
     override just above, so they kept rendering at full desktop size - the
     one row in the Info expansion visibly bigger than the rest */
  .field-strength-row-label.field-strength-chart-label,
  .field-strength-value-text {
    font-size: 10.5px;
  }

  .favourites-toggle {
    font-size: 9px;
  }

  .breadcrumbs {
    font-size: 10px;
    margin-top: 3px;
    padding-top: 0;
    padding-bottom: 0;
  }

  .feed-section-title {
    font-size: 11.5px;
  }

  .view-option-item {
    font-size: 10px;
    padding: 3px 6px;
  }

  /* the collapsed mobile menu is a secondary/utility panel, not primary
     content - can afford to run denser than the rest of the mobile page */
  .mobile-menu-panel .feed-section-title {
    font-size: 11px;
  }

  .mobile-menu-panel .view-option-item {
    font-size: 9.5px;
    padding: 2px 6px;
  }

  .mobile-menu-panel .view-option-list {
    margin-top: 3px;
  }

  .mobile-menu-panel .feed-section + .feed-section {
    margin-top: 8px;
  }

  .leaderboard > thead > tr, .leaderboard > tbody > tr {
    height: 25px;
  }

  .leaderboard > thead > tr > th, .leaderboard > tbody > tr > td {
    font-size: 10.5px;
  }

  /* this row should sit flush with the actual page content below it
     (Tournament Progress/.event-status-outer, Favourites, the leaderboard
     table - all plain .feed-section children, no bleed of their own), not
     with .breadcrumbs/.super-upper-div's deliberately-edge-to-edge bleed
     above it - those two live at different insets (5px apart on each side,
     confirmed directly against .feed-section's own rendered edges, same
     measured-not-derived approach as everything else on this row). -10px/
     +20px lands exactly on .feed-section's edges; the earlier -15px/+30px
     here was matching the wrong reference point entirely */
  .mobile-toggle-row {
    display: flex;
    gap: 14px;
    margin: 1px 0 1px -10px;
    padding-left: 9px;
    width: calc(100% + 20px);
  }

  /* plain text, not a button - just label + caret, no border/background/
     default button chrome. -webkit-tap-highlight-color kills mobile
     Safari/Chrome's default blue tap flash; :focus/:active get a plain gray
     background instead */
  .mobile-menu-toggle {
    -webkit-appearance: none;
    appearance: none;
    -webkit-tap-highlight-color: transparent;
    font-family: inherit;
    font-size: 11px;
    font-weight: normal;
    padding: 2px 4px;
    margin: 0 -4px;
    border: none;
    outline: none;
    background: transparent;
    box-shadow: none;
    border-radius: 2px;
    color: var(--font-color-base);
    cursor: pointer;
  }

  .mobile-menu-toggle:focus, .mobile-menu-toggle:active {
    background-color: rgba(150, 150, 150, 0.25);
    outline: none;
    box-shadow: none;
  }

  .event-title-info-toggle {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
    font-size: 10px;
    font-weight: normal;
  }

  .mobile-menu-caret {
    margin-left: 4px;
    transition: transform 150ms ease-out;
  }

  .mobile-menu-toggle.open .mobile-menu-caret {
    transform: rotate(180deg);
  }

  .mobile-menu-panel.open {
    display: block;
    box-sizing: border-box;
    margin: 4px 0 0 -10px;
    padding: 4px 9px 4px 9px;
    background: var(--container-color-base);
    border: 1px solid rgba(150, 150, 150, 0.3);
    border-radius: 2px;
  }

  /* the panel is .feed-div-right itself once JS relocates it - drop the
     side-by-side layout leftovers (flex sizing, divider) now that it's a
     standalone collapsed block instead of a column beside the table */
  .mobile-menu-panel .feed-div-right {
    border-top: none;
    padding-top: 0;
  }

  /* .mobile-ticker-row - the per-page sub-menu strip (_base.html gives it to
     whichever of #mobile-live-menu-row/#mobile-section-menu-row/#mobile-
     scratch-menu-row applies, via setup_mobile_section_menu()). same
     vertical .view-option-list markup every _*_menu.html partial already
     used, laid out as a horizontal scrolling strip instead - scrollbar
     hidden (still scrollable via touch/trackpad, same as iOS/most native
     apps' own tab strips) rather than a visible bar */
  .mobile-ticker-row {
    /* bleeds to the true viewport edge, flush with .breadcrumbs/.upper-div/
       .super-upper-div above and below it - #mobile-toggle-row's own -15px
       margin + 9px padding-left only gets partway there on its own (measured
       directly against .breadcrumbs' own rendered edges rather than derived,
       since the parent's own box model makes the math easy to get wrong) */
    width: calc(100% + 24px);
    margin-left: -9px;
    overflow-x: auto;
    scrollbar-width: none;
    -ms-overflow-style: none;
    /* no border here - each cell already carries its own top/bottom border
       (.view-option-item below), and together those read as one continuous
       line across the row. a second border here on top of that doubled the
       line's apparent thickness instead of reinforcing it */
  }

  .mobile-ticker-row::-webkit-scrollbar {
    display: none;
  }

  .mobile-ticker-row .feed-section-title {
    /* redundant once this reads as a row of tabs rather than a titled
       sidebar section */
    display: none;
  }

  .mobile-ticker-row .view-option-list {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    gap: 0;
    /* its own normal 5px margin-top (spacing below .feed-section-title in
       the vertical sidebar list) left a gap above the cells even with that
       title hidden - zeroed out so the cells sit flush against the row's
       own top border instead */
    margin-top: 0;
  }

  /* a grid of bordered cells, not pills with gaps between them - each tab
     is its own rectangle, sitting flush against its neighbors and against
     the row's own top/bottom border. no left border on any of them -
     between two adjacent cells, that would double up with the previous
     cell's own right border, and on the first cell it would read as a
     stray edge the row itself doesn't otherwise have */
  /* flex-grow (not "none") so a short list of tabs stretches to fill the
     full row width instead of stopping short and leaving bare space to the
     right - shrink stays 0 so a long/overflowing list still just scrolls
     at each tab's natural content width rather than squeezing text. text
     centered since a grown tab's content no longer fills its own width */
  .mobile-ticker-row .view-option-item {
    flex: 1 0 auto;
    white-space: nowrap;
    font-size: 9px;
    padding: 3px 5px;
    text-align: center;
    border: 1px solid rgba(150, 150, 150, 0.4);
    border-left: none;
  }

  /* no closing edge either - this strip scrolls, so there's no real "last"
     cell to cap off, same reasoning as the first cell's missing left border */
  .mobile-ticker-row .view-option-item:last-child {
    border-right: none;
  }

  /* .view-option-sub's indentation (Player Stats/Course Stats/Cut Sweat,
     normally nested under Live Model in the vertical sidebar list - Course
     History/Course Fit under Skill Decomposition in the Scratch Tools one)
     doesn't carry any meaning in a wrapping row of sibling tabs - every tab
     reads the same here regardless of that grouping */
  .mobile-ticker-row .view-option-item.view-option-sub {
    padding-left: 8px;
  }

  /* the dot marker (.view-option-sub::before) marks that same indentation -
     meaningless once there's no indentation left to mark */
  .mobile-ticker-row .view-option-sub::before {
    display: none;
  }

  /* same yellow .view-option-selected already uses in the desktop sidebar
     list (live_feeds.css, above) - dark mode gets the same blue-tint swap
     that rule gets there too, for the same reason (yellow at low alpha
     barely reads against near-black) */
  .mobile-ticker-row .view-option-selected {
    background-color: rgba(255, 220, 0, 0.15);
    color: var(--blue);
    font-weight: 600;
  }

  :root[color-mode="dark"] .mobile-ticker-row .view-option-selected {
    background-color: rgba(0, 116, 217, 0.2);
  }

  /* color, not opacity - the base .view-option-disabled rule (live_feeds.css,
     above) uses opacity, which fades the border right along with the text,
     undermining the bordered-rectangle look the rest of this row relies on
     for every other cell - explicitly reset back to 1 to cancel that out */
  .mobile-ticker-row .view-option-disabled {
    opacity: 1;
    color: rgba(150, 150, 150, 0.7);
  }

  /* 768px twin of the 900px player-name rule above - same macro output, this
     is just the breakpoint field_list/tee_times/recent_form/predictions/
     course_fit/course_history/skill_decomp already use for every other
     mobile adjustment on their own tables */
  .player-name-desktop {
    display: none;
  }

  .player-name-mobile {
    display: flex;
    flex-direction: column;
    line-height: 1.25;
    /* was on .player-name-link (the single <a> that used to wrap this
       whole 2-line stack) - .player-name-mobile is the thing actually
       sitting in .player-col-inner's flex row now that the flag/link split
       it into several pieces, so the shrink behavior moved here with it */
    flex: 1 1 auto;
    min-width: 0;
  }

  .player-name-mobile-top,
  .player-name-mobile-bottom {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
  }

  .player-name-mobile-top {
    font-size: 6.5px;
    opacity: 0.75;
    position: relative;
    top: 0.5px;
  }

  .player-name-mobile-bottom {
    font-weight: 600;
    font-size: 10px;
  }

  .player-name-mobile-bottom img.player-flag {
    height: 11px;
    margin-top: -1px;
    vertical-align: middle;
  }

  .player-col-inner {
    display: flex;
    align-items: center;
    gap: 2px;
  }
}
