/* ================================================================
   ShowRing — Apple-inspired Design System
   ================================================================ */

:root {
  /* Tell the UA we render correctly in both modes — fixes flash of
     wrong-theme native form controls (scrollbars, inputs, datepicker)
     on first paint and lets light-dark() resolve correctly anywhere
     we use it later. */
  color-scheme: light dark;

  --font: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Inter', system-ui, sans-serif;
  --font-display: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Inter', system-ui, sans-serif;
  --mono: 'SF Mono', SFMono-Regular, ui-monospace, Menlo, monospace;

  /* Fluid type scale — Utopia-style clamp() tokens that interpolate
     smoothly between a 360px viewport min and a 1280px viewport max.
     Scale ratio 1.25 (major third). Use these for new components
     instead of hardcoded font sizes; existing component styles will
     migrate gradually. Reference: https://utopia.fyi/type/calculator */
  --step--1: clamp(0.78rem, 0.74rem + 0.20vw, 0.89rem);  /* small label */
  --step-0:  clamp(0.94rem, 0.88rem + 0.31vw, 1.13rem);  /* body */
  --step-1:  clamp(1.13rem, 1.04rem + 0.45vw, 1.41rem);
  --step-2:  clamp(1.35rem, 1.22rem + 0.65vw, 1.76rem);
  --step-3:  clamp(1.62rem, 1.43rem + 0.93vw, 2.20rem);
  --step-4:  clamp(1.94rem, 1.66rem + 1.32vw, 2.75rem);  /* page-title */
  --step-5:  clamp(2.33rem, 1.93rem + 1.86vw, 3.43rem);

  --bg: #ffffff;
  --bg-secondary: #f5f5f7;
  --bg-tertiary: #e8e8ed;
  --surface: #ffffff;
  --surface-hover: #f9f9fb;
  --surface-active: #f0f0f2;

  --text: #1d1d1f;
  --text-secondary: #6e6e73;
  --text-tertiary: #86868b;

  --border: rgba(0,0,0,0.06);
  --border-strong: rgba(0,0,0,0.1);
  --divider: rgba(0,0,0,0.06);

  --accent: #1B4D72;
  --accent-light: #2A6A9E;
  --accent-hover: #164060;

  --green: #34c759;
  --green-soft: rgba(52,199,89,0.1);
  --orange: #ff9500;
  --orange-soft: rgba(255,149,0,0.1);
  --red: #ff3b30;
  --red-soft: rgba(255,59,48,0.1);
  --blue: #007aff;
  --blue-soft: rgba(0,122,255,0.1);
  --blue-bg: rgba(0, 122, 255, 0.1);
  --accent-faint: rgba(0, 113, 227, 0.12);  /* sits behind small badges */

  /* Standard US horse-show ribbon palette (places 1–6). Single source
   * of truth for every results listing on the web; matches iOS
   * PlaceRibbon (.blue / .red / .yellow / .white / .pink / .green).
   * --ribbon-4 is pure white, so anywhere it's used the surface needs
   * --ribbon-4-border to stay visible on light backgrounds. */
  --ribbon-1: #007AFF;          /* blue   — first  */
  --ribbon-2: #FF3B30;          /* red    — second */
  --ribbon-3: #FFD60A;          /* yellow — third  */
  --ribbon-4: #FFFFFF;          /* white  — fourth */
  --ribbon-5: #FF2D55;          /* pink   — fifth  */
  --ribbon-6: #34C759;          /* green  — sixth  */
  --ribbon-default: #D1D1D6;
  --ribbon-4-border: rgba(0,0,0,0.18);

  --radius-sm: 10px;
  --radius-md: 14px;
  --radius-lg: 18px;
  --radius-xl: 22px;
  --radius-full: 980px;

  --shadow-sm: 0 1px 3px rgba(0,0,0,0.04);
  --shadow-md: 0 2px 12px rgba(0,0,0,0.06);
  --shadow-lg: 0 8px 30px rgba(0,0,0,0.08);
  --shadow-xl: 0 16px 48px rgba(0,0,0,0.12);

  /* Phase 1 chrome tokens. The full Utopia/OKLCH/light-dark() token
     layer lands in Phase 5; these are the variables Phase 1 needs to
     stand on its own. */
  --top-bar-h: 48px;
  --sidebar-w: 240px;
  --drawer-z: 70;        /* mobile drawer + backdrop */
  --top-bar-z: 100;      /* top app bar — sits above the drawer so the
                            morphing ☰ ↔ × toggle stays in one
                            physical place when the drawer is open */

  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-t: env(safe-area-inset-top, 0px);

  --div-asb: #8B0000;
  --div-morgan: #1B4D72;
  --div-hackney: #2E7D32;
  --div-roadster: #E65100;
  --div-academy: #6A1B9A;
  --div-arabian: #00695C;
  --div-carriage: #4E342E;
  --div-friesian: #1A237E;
  --div-walktrot: #C2185B;
}

/* ---- Dark Mode ---- */
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #000000;
    --bg-secondary: #1c1c1e;
    --bg-tertiary: #2c2c2e;
    --surface: #1c1c1e;
    --surface-hover: #2c2c2e;
    --surface-active: #3a3a3c;

    --text: #f5f5f7;
    --text-secondary: #a1a1a6;
    --text-tertiary: #6e6e73;

    --border: rgba(255,255,255,0.08);
    --border-strong: rgba(255,255,255,0.14);
    --divider: rgba(255,255,255,0.06);

    --accent: #5ba3d9;
    --accent-light: #7db8e3;
    --accent-hover: #4a8fc5;

    --green: #30d158;
    --green-soft: rgba(48,209,88,0.15);
    --orange: #ff9f0a;
    --orange-soft: rgba(255,159,10,0.15);
    --red: #ff453a;
    --red-soft: rgba(255,69,58,0.15);
    --blue: #0a84ff;
    --blue-soft: rgba(10,132,255,0.15);
    /* Bigger alpha than light mode so the tinted surface reads on
       a dark background — the brand blue gets ~lost otherwise. */
    --blue-bg: rgba(10, 132, 255, 0.20);
    --accent-faint: rgba(91, 163, 217, 0.22);  /* matches dark-mode --accent */

    --shadow-sm: 0 1px 2px rgba(0,0,0,0.3);
    --shadow-md: 0 2px 8px rgba(0,0,0,0.3);
    --shadow-lg: 0 8px 32px rgba(0,0,0,0.4);
    --shadow-xl: 0 16px 48px rgba(0,0,0,0.5);
  }
}

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

html {
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.47;
  color: var(--text);
  background: var(--bg-secondary);
  overscroll-behavior-y: none;
  -webkit-tap-highlight-color: transparent;
  padding-top: var(--safe-t);
  /* Block flow at every viewport. Mobile: chrome stacks vertically
     (top bar → banners → #app). Desktop (≥900px): the sidebar is
     position: fixed in column 1, and body gets padding-left so its
     other children flow in the right canvas. position: fixed for the
     sidebar dodges the grid-row span gotcha (where `1 / -1` won't
     span implicit rows) and keeps the sidebar visible during page
     scroll without needing to compute row counts. */
}

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

button {
  font-family: inherit;
  border: none;
  background: none;
  cursor: pointer;
  -webkit-appearance: none;
  color: inherit;
}

input, select, textarea {
  font-family: inherit;
  font-size: 17px;
  border: none;
  outline: none;
  -webkit-appearance: none;
  color: var(--text);
}

ul, ol { list-style: none; }
img { max-width: 100%; display: block; }

/* ---- App Layout ---- */
#app {
  min-height: 100dvh;
  /* No bottom tab bar in the new chrome — content just needs to clear
     the iOS home indicator. Sticky/fixed elements that touch the
     bottom edge add their own safe-area padding via max(). */
  padding-bottom: calc(var(--safe-b) + 16px);
}

/* ---- Top App Bar ----
   Persistent bar at the top of the show app. Layout (left → right):
     [☰ menu]  [Home logo + wordmark]  [...spacer...]  [Profile chip]
   The hamburger and the home logo both render at <900px; at ≥900px
   the sidebar takes over (which has its own brand link), so the
   hamburger and the top-bar home shortcut are hidden — the sidebar's
   ShowRing brand is the upper-left of the visible chrome. */
.top-app-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  min-height: var(--top-bar-h);
  z-index: var(--top-bar-z);
  /* Sticky so the home/menu/profile chrome stays in view as the
     user scrolls past the (now in-flow) store banner, and so the
     full-width drawer at compact widths can sit beneath the top bar
     without covering the morphing menu/close button. */
  position: sticky;
  top: 0;
}

.top-app-bar__menu {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  margin-left: -6px;
  border-radius: 8px;
  color: var(--text);
  background: transparent;
  flex: 0 0 auto;
  position: relative;  /* containing block for stacked icons */
}
.top-app-bar__menu:hover {
  background: var(--bg-secondary, rgba(120, 120, 128, 0.08));
}

/* ☰ ↔ × cross-fade. Both icons share the same physical center so the
   tap target doesn't shift between states. The ☰ icon lifts and
   rotates as it fades out; the × icon rotates in. Native CSS
   transitions only — no JS, no animation library. */
.top-app-bar__menu-icon {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 22px;
  height: 22px;
  transition: opacity 0.18s ease, transform 0.22s ease;
  transform-origin: 50% 50%;
}
.top-app-bar__menu-icon--close {
  opacity: 0;
  transform: rotate(-90deg);
}
body[data-drawer="open"] .top-app-bar__menu-icon--menu {
  opacity: 0;
  transform: rotate(90deg);
}
body[data-drawer="open"] .top-app-bar__menu-icon--close {
  opacity: 1;
  transform: rotate(0deg);
}

.top-app-bar__home {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  color: inherit;
  font-weight: 600;
  font-size: 15px;
  letter-spacing: -0.01em;
  padding: 4px 6px;
  margin: -4px -6px;
  border-radius: 8px;
  transition: opacity 0.18s ease;
}

/* When the full-width drawer is open at compact widths, fade out the
   home link and the profile chip so the only visible top-bar control
   is the × button — matching apple.com's mobile menu behavior. */
body[data-drawer="open"] .top-app-bar__home,
body[data-drawer="open"] .top-app-bar__profile {
  opacity: 0;
  pointer-events: none;
}
.top-app-bar__home:hover {
  background: var(--bg-secondary, rgba(120, 120, 128, 0.08));
  text-decoration: none;
}
.top-app-bar__mark {
  display: block;
  border-radius: 6px;
  flex: 0 0 auto;
}
.top-app-bar__wordmark {
  color: var(--text);
}

.top-app-bar__spacer {
  flex: 1 1 auto;
}

.top-app-bar__profile {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  border-radius: 999px;
  padding: 2px;
  transition: background 0.15s ease;
}
.top-app-bar__profile[hidden] { display: none; }
.top-app-bar__profile:hover {
  background: var(--bg-secondary, rgba(120, 120, 128, 0.08));
}

/* Compact-viewport sign-in chip — sits in the same slot as the profile
   avatar but only appears when the visitor has no session. Pill button
   styled to read as a clear CTA without screaming for attention. */
.top-app-bar__signin {
  display: inline-flex;
  align-items: center;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
  padding: 6px 12px;
  border-radius: 999px;
  background: var(--blue-bg);
  transition: background 0.15s ease;
  -webkit-tap-highlight-color: transparent;
}
.top-app-bar__signin[hidden] { display: none; }
.top-app-bar__signin:hover {
  background: color-mix(in srgb, var(--blue-bg) 80%, var(--accent) 20%);
  text-decoration: none;
}
/* Hide the sign-in chip when the drawer is open, same as the profile
   chip — keeps the upper-right reserved for the close (×) button. */
body[data-drawer="open"] .top-app-bar__signin {
  opacity: 0;
  pointer-events: none;
}
.top-app-bar__avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--blue-bg);
  color: var(--accent);
  font-weight: 700;
  font-size: 13px;
  letter-spacing: -0.02em;
}

/* ---- Live Status Strip ----
   One-line "what's happening live right now" summary. Sticks just
   below the sticky top app bar. Subtle translucent surface with a
   backdrop blur so the page beneath shows through faintly — that's
   the visual cue that this is companion chrome, not page content.
   The element is an <a> so the whole strip is a single tap target
   landing on #live; we render it via innerHTML in renderLiveStatusStrip. */
.live-status-strip {
  /* Sticky directly under the top app bar. The top bar is at top:0
     (sticky, z 100), so this sits at top: var(--top-bar-h). */
  position: sticky;
  top: var(--top-bar-h);
  z-index: 90;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 16px;
  font-size: 13px;
  line-height: 1.3;
  color: var(--text);
  text-decoration: none;
  background: color-mix(in srgb, var(--bg) 84%, transparent);
  border-bottom: 1px solid var(--border);
  -webkit-tap-highlight-color: transparent;
  /* Smooth in/out — when the live state appears or disappears the
     strip's hidden attribute toggles; the @starting-style isn't yet
     interoperable enough to rely on, so we just transition the
     visible state. */
  transition: background 0.18s ease;
}
@supports (backdrop-filter: blur(8px)) {
  .live-status-strip {
    backdrop-filter: blur(8px) saturate(180%);
    -webkit-backdrop-filter: blur(8px) saturate(180%);
  }
}
.live-status-strip[hidden] { display: none; }
.live-status-strip:hover {
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  text-decoration: none;
}

.live-status-strip__pulse {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 60%, transparent);
  animation: live-status-strip__pulse 1.6s ease-out infinite;
}
.live-status-strip__pulse--paused {
  background: var(--orange);
  animation: none;
  box-shadow: none;
}

@keyframes live-status-strip__pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 65%, transparent); }
  70%  { box-shadow: 0 0 0 8px color-mix(in srgb, var(--green) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 0%, transparent); }
}

.live-status-strip__text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: 6px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.live-status-strip__text strong {
  font-weight: 600;
  color: var(--text);
}
.live-status-strip__sep {
  color: var(--text-tertiary);
}
.live-status-strip__name {
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.live-status-strip__badge {
  display: inline-block;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: 999px;
  background: var(--accent-faint, rgba(0, 113, 227, 0.12));
  color: var(--accent);
  margin-left: 4px;
}
.live-status-strip__more {
  flex: 0 0 auto;
  font-size: 12px;
  color: var(--text-tertiary);
}
.live-status-strip__chev {
  flex: 0 0 auto;
  color: var(--text-tertiary);
  font-size: 18px;
  line-height: 1;
}

/* ---- Primary Nav (sidebar at ≥900px / drawer at <900px) ----
   One <nav> element, two presentations. At <900px it slides in from
   the left when [data-drawer="open"] is set on <body>. At ≥900px it
   becomes a sticky left rail and the drawer machinery is irrelevant
   — see the @media (min-width: 900px) block further down for the
   desktop overrides. */
.primary-nav {
  /* Full-width drawer at compact widths — sits below the sticky top
     bar so the morphing × button stays in its physical place above
     the menu. When the live-status-strip is also visible, --strip-h
     is published with its measured height so the drawer offsets
     below it too — without this, the strip (z 90) would cover the
     drawer's first nav item. --strip-h is 0 when no strip is showing.
     Slides up from offscreen via translateY when closed, down into
     view when open. The opacity transition prevents a stray visible
     flash before the transform kicks in. */
  position: fixed;
  top: calc(var(--top-bar-h) + var(--strip-h, 0px));
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  max-width: none;
  padding: 12px 0 calc(var(--safe-b) + 12px);
  background: var(--bg);
  border-right: 1px solid var(--border);
  z-index: var(--drawer-z);
  transform: translateY(-8px);
  opacity: 0;
  transition: transform 0.22s ease, opacity 0.18s ease, visibility 0s linear 0.22s;
  overflow-y: auto;
  overscroll-behavior: contain;
  visibility: hidden;
  display: flex;
  flex-direction: column;
}
body[data-drawer="open"] .primary-nav {
  transform: translateY(0);
  opacity: 1;
  visibility: visible;
  transition: transform 0.22s ease, opacity 0.18s ease, visibility 0s linear 0s;
}

.primary-nav__brand {
  /* Hidden at compact widths — at that size the morphing × in the
     top app bar is the visible chrome; a second ShowRing logo at the
     top of the drawer would be redundant. Re-shown at desktop in the
     @media (min-width: 900px) block as the sidebar's header. */
  display: none;
  align-items: center;
  gap: 10px;
  padding: 8px 16px 16px;
  text-decoration: none;
  color: inherit;
  font-weight: 700;
  font-size: 17px;
  letter-spacing: -0.015em;
  border-bottom: 1px solid var(--border);
  margin-bottom: 8px;
}
.primary-nav__brand img {
  display: block;
  border-radius: 7px;
}

.primary-nav__list {
  list-style: none;
  margin: 0;
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.primary-nav__item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border-radius: 8px;
  text-decoration: none;
  color: var(--text-secondary);
  font-weight: 500;
  font-size: 15px;
  transition: background 0.12s ease, color 0.12s ease;
}
.primary-nav__item:hover {
  background: var(--bg-secondary);
  color: var(--text);
  text-decoration: none;
}
.primary-nav__item.is-active {
  background: var(--blue-bg, rgba(0, 122, 255, 0.1));
  color: var(--accent);
}
.primary-nav__item.hidden { display: none; }

/* Sidebar profile chip is desktop-only; the top-app-bar's chip
   handles the compact case. At <900px the @media-revealed
   display: flex isn't applied, but the bare element would still
   render via the UA default for <a> once JS clears [hidden] — so
   we explicitly hide it here. The desktop block overrides this. */
.primary-nav__profile {
  display: none;
}

/* Backdrop scrim that captures outside-clicks while the drawer is
   open at <900px. At ≥900px the backdrop is permanently hidden. */
.nav-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: calc(var(--drawer-z) - 1);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.22s ease;
}
body[data-drawer="open"] .nav-backdrop {
  opacity: 1;
  pointer-events: auto;
}
.nav-backdrop[hidden] { display: block; }  /* override the [hidden] default — visibility is opacity-driven */

/* Lock body scroll while the full-width drawer is open so the page
   underneath doesn't scroll independently. At desktop the
   data-drawer attribute is never set (the toggle is hidden), so this
   rule is a no-op there — no media query needed. */
body[data-drawer="open"] {
  overflow: hidden;
}

/* ---- Focus-visible rings on the new chrome ----
   `:focus-visible` only applies for keyboard navigation (not mouse
   clicks), so the ring shows for accessibility users without
   distracting click-and-drag mouse interactions. Outline follows the
   element's border-radius automatically in evergreen browsers. */
.top-app-bar__menu:focus-visible,
.top-app-bar__home:focus-visible,
.top-app-bar__profile:focus-visible,
.primary-nav__brand:focus-visible,
.primary-nav__item:focus-visible,
.primary-nav__profile:focus-visible,
.live-status-strip:focus-visible,
#nav-drawer-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.view {
  display: none;
  max-width: 680px;
  margin: 0 auto;
  padding: 0 20px 32px;
  animation: fadeUp 0.25s ease;
  /* Make .view a queryable container so child layouts (Live's
     hero/sidebar grid, Info's auto-fit info-groups, etc.) can respond
     to the *canvas* width — not the viewport. iPad portrait without
     a sidebar gets the same two-column live treatment as a desktop
     window with a sidebar, because its canvas is similarly wide. */
  container-type: inline-size;
  container-name: view;
}

.view.active { display: block; }

@keyframes fadeUp {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

/* ---- Top Store Banner (iOS non-Safari / macOS) ----
   Sits in regular block flow as the first <body> child so it scrolls
   off with the page on first scroll, mirroring how iOS Safari treats
   the native Smart App Banner. No position: fixed → no body padding
   compensation, no z-index conflicts with the sidebar at desktop.
   At ≥900px the body's padding-left already constrains it to the
   canvas — no extra positioning needed. */
:root {
  --store-banner-h: 60px;
}

.store-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 14px;
  min-height: var(--store-banner-h);
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  animation: fadeDown 0.3s ease-out;
}

.store-banner.hidden { display: none; }

.store-banner-dismiss {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.store-banner-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
  line-height: 1.25;
}

.store-banner-text strong {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
}

.store-banner-text span {
  font-size: 12px;
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.store-banner-cta {
  flex-shrink: 0;
  padding: 6px 16px;
  border-radius: var(--radius-full);
  background: var(--blue);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

.store-banner-cta:hover,
.store-banner-cta:active {
  filter: brightness(0.95);
}

/* The banner is in document flow now, so no extra body padding or
   #app min-height adjustment is needed when it's shown — it just
   takes its natural space at the top of the page. */

@keyframes fadeDown {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---- Android Install Banner (PWA) ---- */
.install-banner {
  position: fixed;
  bottom: max(12px, calc(env(safe-area-inset-bottom, 0) + 12px));
  left: 12px;
  right: 12px;
  z-index: 200;
  animation: fadeUp 0.3s ease-out;
}

.install-banner.hidden { display: none; }

.install-banner-content {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  background: var(--bg);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
}

.install-banner-text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 14px;
  line-height: 1.3;
}

.install-banner-text span {
  font-size: 13px;
  color: var(--text-secondary);
}

.install-btn {
  padding: 8px 20px;
  border: none;
  border-radius: 980px;
  background: var(--blue);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}

.install-dismiss {
  padding: 4px 8px;
  border: none;
  background: none;
  font-size: 20px;
  color: var(--text-secondary);
  cursor: pointer;
  line-height: 1;
}

/* ---- Push Notification CTA Banner (PWA only) ----
   Sits above the bottom tab bar when the app is installed as a PWA
   and notification permission is still 'default'. Mirrors the install
   banner pattern so they render consistently if both ever show.
   Visibility logic lives in initPushCta() / refreshPushCta(). */
.push-cta-banner {
  position: fixed;
  /* Stack above the install banner if both are present (rare — install
     banner only shows pre-install, this one only shows post-install). */
  bottom: max(12px, calc(env(safe-area-inset-bottom, 0) + 12px));
  left: 12px;
  right: 12px;
  z-index: 200;
  animation: fadeUp 0.3s ease-out;
}

.push-cta-banner.hidden { display: none; }

.push-cta-banner-content {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  background: var(--bg);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
}

.push-cta-banner-icon {
  font-size: 24px;
  line-height: 1;
}

.push-cta-banner-text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 14px;
  line-height: 1.3;
}

.push-cta-banner-text span {
  font-size: 13px;
  color: var(--text-secondary);
}

.push-cta-enable {
  padding: 8px 18px;
  border: none;
  border-radius: 980px;
  background: var(--blue);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}

.push-cta-enable:disabled {
  opacity: 0.6;
  cursor: progress;
}

.push-cta-dismiss {
  padding: 4px 8px;
  border: none;
  background: none;
  font-size: 20px;
  color: var(--text-secondary);
  cursor: pointer;
  line-height: 1;
}

.install-instructions {
  margin-top: 8px;
  padding: 12px 16px;
  background: var(--bg);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-secondary);
}

.install-instructions.hidden { display: none; }

.install-instructions ol {
  margin: 0;
  padding-left: 20px;
}

.install-instructions li {
  margin-bottom: 4px;
}

.install-instructions strong {
  color: var(--text);
}

/* (Bottom tab bar retired in the chrome rework — primary nav now
    lives in #primary-nav as a sidebar at ≥900px and a slide-in
    drawer below that. See the "Primary Nav" block above.) */

/* ---- Page Title ---- */
.page-title {
  font-family: var(--font-display);
  /* Fluid clamp() — scales from ~31px at 360w to ~44px at 1280w.
     Replaces the prior fixed 34px so iPhone SE → desktop is one
     smooth ramp, not a sudden jump at a media-query threshold.
     The legacy 360px override below stays as a clamp-floor safety
     net for very narrow phones. */
  font-size: var(--step-4);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.08;
  padding: 20px 0 6px;
}

.page-subtitle {
  font-size: 15px;
  color: var(--text-secondary);
  margin-bottom: 24px;
}

/* ---- Section ---- */
.section-label {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--text);
  padding: 28px 0 12px;
}

/* ---- Cards ---- */
.card {
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: 18px;
  margin-bottom: 10px;
  box-shadow: var(--shadow-sm);
  transition: transform 0.15s, box-shadow 0.15s;
}

.card.interactive { cursor: pointer; }
.card.interactive:hover { box-shadow: var(--shadow-md); }
.card.interactive:active { transform: scale(0.98); }

/* ---- In-Ring Hero ---- */
.hero {
  background: var(--surface);
  border-radius: var(--radius-xl);
  padding: 28px;
  margin-bottom: 14px;
  position: relative;
  overflow: hidden;
  box-shadow: var(--shadow-md);
}

.hero::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: var(--green);
}

.hero.delayed::before { background: var(--orange); }
.hero.break::before { background: var(--text-tertiary); }

.hero .label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--green);
  margin-bottom: 14px;
}

.hero.delayed .label { color: var(--orange); }

/* Audience-facing delay block on the Live tab. Mirror of the iOS
 * LiveNowView delayDetails: status (eyebrow + countdown) on the left,
 * duration estimate on the right. The eyebrow flips to "Past
 * estimate · over by" once the admin's estimate is exceeded so a
 * stuck-at-0:00 timer never reads as "back any second now". */
.audience-delay-block {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px;
  margin: 8px 0 10px;
  background: rgba(255, 149, 0, 0.10);
  border-radius: 10px;
}
.audience-delay-status { display: flex; flex-direction: column; gap: 2px; }
.audience-delay-eyebrow {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-secondary);
}
.audience-delay-time {
  font-size: 28px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--orange);
  font-family: ui-rounded, -apple-system, system-ui, sans-serif;
}
.audience-delay-meta {
  font-size: 13px;
  color: var(--text-secondary);
  text-align: right;
}

.hero .pulse {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--green);
  animation: pulse 2s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.3; transform: scale(0.85); }
}

/* ============================================================
   Inline live video player (Live tab hero)
   Sits at the top of .live-hero above the title. The <video>
   fills a 16:9 frame; a LIVE badge floats top-left and an
   unmute affordance bottom-right (until the viewer unmutes).
   ============================================================ */
.live-video {
  position: relative;
  width: 100%;
  margin-bottom: 16px;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: #000;
  box-shadow: var(--shadow-md);
  aspect-ratio: 16 / 9;
}
.live-video__el {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
}

/* Tap-to-start poster — shown until the viewer opts in. No HLS is pulled
   while idle, so a live ring costs zero delivery for non-watchers. */
.live-video__start {
  position: absolute;
  inset: 0;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  height: 100%;
  border: 0;
  cursor: pointer;
  color: #fff;
  font: inherit;
  background: rgba(0, 0, 0, 0.55);
}
.live-video.is-idle .live-video__start { display: flex; }
.live-video.is-idle .live-video__el { visibility: hidden; }
.live-video.is-idle .live-video__unmute { display: none; }
.live-video__start:hover { background: rgba(0, 0, 0, 0.66); }
.live-video__start-label { font-weight: 600; font-size: 15px; letter-spacing: 0.01em; }

/* LIVE badge — reuses the green pulsing-dot language from the
   live status strip, on a dark scrim so it reads over video. */
.live-badge {
  position: absolute;
  top: 10px;
  left: 10px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 9px;
  border-radius: var(--radius-full);
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  pointer-events: none;
}
.live-badge__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--red);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--red) 60%, transparent);
  animation: live-badge-pulse 1.6s ease-out infinite;
}
.live-badge__hint {
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: none;
  opacity: 0.85;
}
@keyframes live-badge-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--red) 65%, transparent); }
  70%  { box-shadow: 0 0 0 7px color-mix(in srgb, var(--red) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--red) 0%, transparent); }
}

/* DEGRADED — amber dot, no pulse, "Reconnecting…" hint shown. */
.live-video.is-degraded .live-badge { background: rgba(0, 0, 0, 0.6); }
.live-video.is-degraded .live-badge__dot {
  background: var(--orange);
  animation: none;
  box-shadow: none;
}

/* Unmute affordance — hidden once the viewer unmutes. */
.live-video__unmute {
  position: absolute;
  bottom: 10px;
  right: 10px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border: none;
  border-radius: var(--radius-full);
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, opacity 0.2s ease;
}
.live-video__unmute:hover { background: rgba(0, 0, 0, 0.72); }
.live-video__unmute svg { flex: 0 0 auto; }
.live-video.is-unmuted .live-video__unmute { display: none; }

@media (prefers-reduced-motion: reduce) {
  .live-badge__dot { animation: none; }
}

.hero .number {
  font-family: var(--font-display);
  font-size: 56px;
  font-weight: 800;
  letter-spacing: -0.04em;
  line-height: 1;
  color: var(--text);
}

.hero .name {
  font-size: 21px;
  font-weight: 600;
  margin-top: 6px;
  color: var(--text);
  line-height: 1.3;
}

.hero .timer {
  font-family: var(--mono);
  font-size: 32px;
  font-weight: 500;
  color: var(--text-tertiary);
  margin-top: 20px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.hero-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 14px;
}

.hero-header .label {
  margin-bottom: 0;
}

.hero-actions {
  display: flex;
  gap: 4px;
}

.hero-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-top: 8px;
}

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

/* ---- Class row (Schedule + Live tab body) ----
 * Three typography tiers: primary = name (15/17px), leading # (22/28px
 * bold accent), meta (12/13px tertiary). State conveyed by the dot
 * colour on the leading edge + a short label in the right column.
 * See docs/specs/2026-04-23-class-row-redesign-design.md.
 */
.class-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: var(--surface);
  border-radius: var(--radius-md);
  margin-bottom: 8px;
  cursor: pointer;
  transition: background 0.15s, transform 0.15s;
  box-shadow: var(--shadow-sm);
}
.class-row:hover { background: var(--surface-hover); }
.class-row:active { transform: scale(0.985); background: var(--surface-active); }

.break-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  background: var(--surface);
  border-radius: var(--radius-md);
  margin-bottom: 2px;
  color: var(--text-secondary);
}

.break-icon { font-size: 18px; }
.break-label { font-weight: 600; font-size: 14px; }
.break-notes { font-size: 13px; color: var(--text-tertiary); }
.break-time { margin-left: auto; font-size: 13px; color: var(--text-tertiary); font-variant-numeric: tabular-nums; }

/* Leading-edge cluster: status dot hugged to the class number. Acts as
 * a single visual unit on the row's leading side. No fixed width — the
 * cluster hugs content so 2- and 3-digit numbers don't reserve dead space. */
.class-lead {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
/* The dot is only emitted for states where its color carries information
 * (IN_RING / LINE_UP / DELAYED / ON_DECK). Default fill is intentionally
 * loud — if you ever see a gray dot, it means the renderer added the
 * .class-dot div without a state modifier and that's a bug to surface,
 * not silently render. */
.class-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: magenta;
  flex-shrink: 0;
}
.class-dot--in-ring  { background: #22c55e; }
.class-dot--line-up  { background: #3b82f6; }
.class-dot--delayed  { background: #f59e0b; }
.class-dot--on-deck  { background: #fbbf24; }

.class-num {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.class-num--scratched {
  color: var(--text-secondary);
  text-decoration: line-through;
}

.class-info {
  flex: 1;
  min-width: 0;
}
.class-name {
  font-size: 15px;
  font-weight: 500;
  color: var(--text);
  line-height: 1.35;
  overflow-wrap: break-word;
}
.class-name--scratched { text-decoration: line-through; }

/* Meta line: division pill + interpunct-separated text tokens. The
 * division pill carries color; the text tokens are quiet tertiary gray. */
.class-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 8px;
  font-size: 12px;
  color: var(--text-tertiary);
  margin-top: 4px;
  line-height: 1.4;
}
.class-meta .meta-text { display: inline; }
.class-meta .sep { color: var(--text-tertiary); margin: 0 5px; }
.class-meta .drift { color: #f59e0b; }
.class-meta .trophy { margin-left: 2px; }

/* Delay line: third row, amber quiet. */
.class-delay {
  font-size: 12px;
  color: #f59e0b;
  margin-top: 4px;
  line-height: 1.4;
}
.class-delay .countdown {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* Scratched / Completed rows dim the whole row body. */
.class-row--dim { opacity: 0.55; }

/* Split-parent rows render as a header for the section group below.
 * The class itself holds no entries post-split; visually we soften it
 * just enough that the eye reads "label for the indented rows below"
 * without losing the operator's ability to tap into the row (the
 * class-detail page is where Merge lives, plus shows status / qualifier
 * graph). Bottom margin collapses so the children visually clamp on. */
.class-row--split-parent {
  background: var(--surface-hover, var(--surface));
  margin-bottom: 0;
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}
.class-row--split-parent .class-name {
  font-weight: 600;
}
.class-row--split-parent .split-summary {
  font-weight: 600;
  color: var(--text-secondary);
}

/* Child section rows indent and gain a left accent stripe so the
 * grouping reads at a glance. The accent uses the accent color so
 * it visually anchors to the parent header above. The 302A display
 * number (driven by classDisplayNumber()) does the rest of the work
 * of identifying the section. */
.class-row--split-section {
  margin-left: 16px;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
  margin-top: 0;
  margin-bottom: 4px;
  border-left: 3px solid var(--accent);
  padding-left: 12px;
}
.class-row--split-section + .class-row--split-section {
  margin-top: 2px;
}
/* Once the last section ends, restore the normal 8px bottom margin
 * so the next unrelated row breathes. The :not selector ensures we
 * only apply the bigger gap when no further section follows. */
.class-row--split-section:not(:has(+ .class-row--split-section)) {
  margin-bottom: 8px;
}

/* Live tab's right column at desktop ("On Deck", "Coming Up",
   "Announcements"). Declared as a container so the .class-row and
   .announcement-row inside it can adapt to the column's width — at
   desktop the sidebar is roughly half the canvas, so its rows get a
   narrower presentation than the same components in the full-width
   schedule list. */
.live-sidebar {
  container-type: inline-size;
}

/* Below ~22rem of available width inside the live-sidebar column we
   shed the lower-priority meta tokens (drift "X min late", trophy
   indicator) to keep each row scannable at a glance. The status
   token + entry count + division pill remain. */
@container (max-width: 22rem) {
  .live-sidebar .class-meta .drift,
  .live-sidebar .class-meta .trophy {
    display: none;
  }
}

/* Admin-only class-history panel — post-mortem timeline shown on the
 * class detail page for completed / scratched classes. Visible only
 * when the viewer is authenticated as a show admin. */
.class-history {
  margin: 20px 0;
  padding: 14px 16px;
  background: var(--surface-secondary, #f7f7f8);
  border-radius: 12px;
  border: 1px solid var(--border, rgba(0,0,0,0.08));
}
.class-history__header {
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  color: var(--text-secondary);
  margin-bottom: 8px;
}
.class-history__summary {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-bottom: 10px;
  margin-bottom: 10px;
  border-bottom: 1px dashed var(--border, rgba(0,0,0,0.08));
}
.class-history__summary-row {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
}
.class-history__summary-row .dl { color: var(--text-secondary); }
.class-history__summary-row .dv { font-variant-numeric: tabular-nums; }
.class-history__duration {
  font-weight: 600;
}
.class-history__events {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.class-history__event {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 13px;
}
.class-history__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  color: var(--text-secondary);
}
.class-history__event--started .class-history__icon,
.class-history__event--show_started .class-history__icon,
.class-history__event--completed .class-history__icon,
.class-history__event--break_ended .class-history__icon,
.class-history__event--delay_resolved .class-history__icon {
  color: #1a7f37;
}
.class-history__event--scratched .class-history__icon { color: #c41e3a; }
.class-history__event--delay_started .class-history__icon { color: #b86e00; }
.class-history__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.class-history__note { color: var(--text-primary); }
.class-history__meta {
  font-size: 11px;
  color: var(--text-tertiary);
}
.class-history__empty,
.class-history__loading,
.class-history__error {
  font-size: 13px;
  color: var(--text-tertiary);
  padding: 4px 0;
}
.class-history__error { color: #c41e3a; }
.class-history__footer {
  margin-top: 12px;
  font-size: 11px;
  color: var(--text-tertiary);
  border-top: 1px dashed var(--border, rgba(0,0,0,0.08));
  padding-top: 8px;
}

/* Pacing-engine explainer footnote — frames the numbers as estimates
 * so a first-time viewer doesn't read them as commitments. Small,
 * secondary color, gently separated from the list below. */
.prediction-explainer {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 0 10px;
  font-size: 12px;
  color: var(--text-tertiary);
  line-height: 1.4;
}
.prediction-explainer__icon {
  font-size: 14px;
  line-height: 1;
  color: var(--text-tertiary);
}

.follow-reasons {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 4px;
}

.follow-reason {
  font-size: 11px;
  font-weight: 600;
  color: var(--blue);
  background: var(--blue-bg);
  padding: 2px 6px;
  border-radius: 4px;
}

/* ---- Following entity list (Schedule → Following tab) ---- */
.following-entity-list {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-radius: var(--radius-md);
  overflow: hidden;
  margin-bottom: 8px;
}

.following-entity-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
}

.following-entity-row:last-child { border-bottom: none; }

.following-entity-icon {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  flex-shrink: 0;
  background: var(--bg-secondary);
}

.following-entity-icon-horse { background: color-mix(in srgb, #8d6e63 18%, transparent); }
.following-entity-icon-person { background: color-mix(in srgb, var(--blue) 15%, transparent); }
.following-entity-icon-section { background: color-mix(in srgb, #9c27b0 15%, transparent); }
.following-entity-icon-class { background: color-mix(in srgb, var(--orange) 15%, transparent); color: var(--orange); font-weight: 700; }

.following-entity-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.following-entity-name {
  font-size: 15px;
  font-weight: 500;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.following-entity-meta {
  font-size: 12px;
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  gap: 6px;
}

.following-entity-meta .dot { color: var(--text-tertiary); }

/* State token rendered inline inside .class-meta as the first text token.
 * Color matches the leading-cluster dot for the same status. */
.class-meta .state { font-weight: 500; }
.class-meta .state--in-ring  { color: #22c55e; }
.class-meta .state--line-up  { color: #3b82f6; }
.class-meta .state--delayed  { color: #f59e0b; }
.class-meta .state--muted    { color: var(--text-secondary); }

/* Regular width — iPad, wide web, landscape. More breathing room and
 * slightly larger type. Only the size-sensitive properties change. */
@media (min-width: 600px) {
  .class-row { padding: 14px 16px; gap: 14px; }
  .class-lead { gap: 8px; }
  .class-dot { width: 10px; height: 10px; }
  .class-num { font-size: 22px; }
  .class-name { font-size: 17px; }
  .class-meta { font-size: 13px; margin-top: 5px; }
  .class-delay { font-size: 13px; margin-top: 5px; }
}

/* ---- Division Badge ---- */
.div-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: var(--radius-full);
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
}

/* ---- Status Badge ---- */
.status {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border-radius: var(--radius-full);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.status-in-ring { background: var(--green-soft); color: var(--green); }
.status-on-deck { background: var(--blue-soft); color: var(--blue); }
.status-scheduled { background: var(--bg-secondary); color: var(--text-tertiary); }
.status-completed { background: var(--bg-secondary); color: var(--text-secondary); }
.status-scratched { background: var(--red-soft); color: var(--red); text-decoration: line-through; }
.status-delayed { background: var(--orange-soft); color: var(--orange); }

/* ---- Progress ---- */
.progress-track {
  width: 100%;
  height: 4px;
  background: var(--bg-tertiary);
  border-radius: 2px;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 2px;
  transition: width 0.6s ease;
}

.progress-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 6px;
  font-size: 13px;
  color: var(--text-tertiary);
}

.timing-ahead { color: var(--green); }
.timing-behind { color: var(--orange); }

/* ---- Show status banner ---- */
/* Parity with iOS ShowStatusBanner: surfaces the show-wide display state
   (pre-show, day-of pending, active, on break, day ended, show ended) so
   attendees know at a glance what's happening. */
.show-status-banner {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 12px 0 8px;
  padding: 10px 14px;
  border-radius: 12px;
  border: 1px solid rgba(0, 0, 0, 0.1);
}

.show-status-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.8px;
  text-transform: uppercase;
}

.show-status-summary {
  font-size: 14px;
  font-weight: 500;
  color: var(--text-primary);
}

.show-status-pre_show {
  background: rgba(0, 122, 255, 0.12);
  border-color: rgba(0, 122, 255, 0.25);
}
.show-status-pre_show .show-status-label { color: #007AFF; }

.show-status-day_of_pending {
  background: rgba(255, 149, 0, 0.12);
  border-color: rgba(255, 149, 0, 0.25);
}
.show-status-day_of_pending .show-status-label { color: #FF9500; }

.show-status-active {
  background: rgba(52, 199, 89, 0.12);
  border-color: rgba(52, 199, 89, 0.25);
}
.show-status-active .show-status-label { color: #34C759; }

.show-status-on_break {
  background: rgba(255, 204, 0, 0.18);
  border-color: rgba(255, 204, 0, 0.35);
}
.show-status-on_break .show-status-label { color: #B8860B; }

.show-status-day_ended {
  background: rgba(88, 86, 214, 0.12);
  border-color: rgba(88, 86, 214, 0.25);
}
.show-status-day_ended .show-status-label { color: #5856D6; }

.show-status-show_ended {
  background: rgba(175, 82, 222, 0.12);
  border-color: rgba(175, 82, 222, 0.25);
}
.show-status-show_ended .show-status-label { color: #AF52DE; }

/* ---- Schedule: Liquid-Glass-inspired layered layout ----
 * Chrome (.schedule-chrome) is sticky at top with a translucent blur —
 * the closest cross-browser analog to Liquid Glass. Page content
 * (.schedule-body) scrolls underneath. Everything meta about the day
 * (branding, banner, explainer, weather forecast) lives in .schedule-body
 * so it scrolls away naturally; only filter commands live in chrome.
 * See docs/specs/2026-04-23-class-row-redesign-design.md.
 */
.schedule-view {
  /* Own a positioning context for the sticky chrome, and let the body
   * scroll freely under it. */
  position: relative;
}
.schedule-chrome {
  position: sticky;
  /* Stack below the sticky chrome above us. At compact widths that's
     the top app bar (always sticky) plus the live-status-strip when
     it's visible; at desktop the top app bar is hidden so only the
     strip contributes. --strip-h is published by renderLiveStatusStrip
     and is 0 when the strip isn't showing, so the math works in every
     state without per-tab JS. */
  top: calc(var(--top-bar-h) + var(--strip-h, 0px));
  z-index: 20;
  margin: 0 calc(var(--view-pad, 16px) * -1);  /* bleed to view edges */
  padding: 10px 16px 8px;
  background: color-mix(in oklab, var(--surface) 74%, transparent);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  border-bottom: 1px solid color-mix(in oklab, var(--text-tertiary) 15%, transparent);
}

/* At desktop the top app bar is display:none, so don't reserve space
   for it — only the strip contributes to the sticky stack offset. */
@media (min-width: 900px) {
  .schedule-chrome {
    top: var(--strip-h, 0px);
  }
}
.schedule-chrome__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.schedule-chrome__top .page-title {
  margin: 0;
  font-size: 22px;
  font-weight: 700;
  line-height: 1.2;
}
.schedule-chrome__actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
.schedule-chrome__sub {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 10px;
}
.schedule-chrome__sub .filter-mode-toggle { margin: 0; flex-shrink: 0; }
.schedule-chrome__sub .day-tabs {
  margin: 0;
  padding: 0;
  flex: 1;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.schedule-chrome__sub .day-tabs::-webkit-scrollbar { display: none; }

.schedule-body {
  padding-top: 8px;
  padding-bottom: 80px;  /* room for tab bar */
}

/* Schedule chrome Filter button — opens the unified filter sheet.
 * Fills with accent when any non-default filter is active; badge
 * shows active filter count. Follows Apple Mail's "one filter entry
 * point" pattern. */
.schedule-filter-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  border-radius: 18px;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  color: var(--text-primary);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.schedule-filter-btn:hover { background: var(--surface-hover); }
.schedule-filter-btn.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.schedule-filter-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: rgba(255,255,255,0.25);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
}
.schedule-filter-btn:not(.active) .schedule-filter-badge {
  background: var(--accent);
  color: #fff;
}

/* Filter sheet — modal, slides up from bottom on narrow widths;
 * centers on wide. Mirrors iOS half-sheet presentation. */
.schedule-filter-overlay {
  position: fixed;
  inset: 0;
  background: color-mix(in oklab, #000 40%, transparent);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  z-index: 200;
  animation: sfOverlayIn 0.15s ease-out;
}
@keyframes sfOverlayIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
.schedule-filter-sheet {
  width: 100%;
  max-width: 540px;
  max-height: 85vh;
  background: var(--surface);
  border-radius: 16px 16px 0 0;
  box-shadow: 0 -12px 40px rgba(0,0,0,0.25);
  display: flex;
  flex-direction: column;
  animation: sfSheetIn 0.22s cubic-bezier(0.2, 0.9, 0.3, 1);
}
@keyframes sfSheetIn {
  from { transform: translateY(100%); }
  to { transform: translateY(0); }
}
.schedule-filter-sheet__grabber {
  width: 36px;
  height: 5px;
  background: var(--text-tertiary);
  border-radius: 999px;
  margin: 8px auto 0;
  opacity: 0.5;
}
.schedule-filter-sheet__header {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 12px 16px 8px;
  gap: 12px;
}
.schedule-filter-sheet__header h2 {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  text-align: center;
}
.schedule-filter-sheet__reset,
.schedule-filter-sheet__done {
  background: transparent;
  border: 0;
  color: var(--accent);
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
  padding: 6px 4px;
}
.schedule-filter-sheet__reset { justify-self: start; }
.schedule-filter-sheet__reset:disabled { color: var(--text-tertiary); cursor: default; }
.schedule-filter-sheet__done { justify-self: end; font-weight: 600; }
.schedule-filter-sheet__body {
  overflow-y: auto;
  padding: 8px 0 24px;
}
.schedule-filter-section {
  padding: 0 16px;
  margin-bottom: 16px;
}
.schedule-filter-section h3 {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin: 12px 4px 6px;
}
.schedule-filter-option {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-radius: 10px;
  cursor: pointer;
}
.schedule-filter-option:hover { background: var(--surface-hover); }
.schedule-filter-option input[type="radio"] {
  accent-color: var(--accent);
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}
.schedule-filter-option .schedule-filter-swatch {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}

/* Legacy .schedule-filter-menu dropdown (dead after Filter sheet
 * rollout; kept around in case callers still reference it). */
.schedule-filter-menu {
  position: relative;
}
.schedule-filter-menu summary {
  list-style: none;
  cursor: pointer;
}
.schedule-filter-menu summary::-webkit-details-marker { display: none; }
.schedule-filter-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  border-radius: 18px;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  color: var(--text-primary);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}
.schedule-filter-btn:hover { background: var(--surface-hover); }
.schedule-filter-btn.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.schedule-filter-icon {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}
.schedule-filter-label { max-width: 10em; overflow: hidden; text-overflow: ellipsis; }

.schedule-filter-menu__popover {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 240px;
  max-height: 60vh;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 12px 32px rgba(0,0,0,0.18);
  padding: 6px;
  z-index: 30;
}
.schedule-filter-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 10px;
  background: transparent;
  border: 0;
  border-radius: 8px;
  font-size: 14px;
  color: var(--text);
  text-align: left;
  cursor: pointer;
}
.schedule-filter-item:hover { background: var(--surface-hover); }
.schedule-filter-item.active { color: var(--accent); font-weight: 600; }
.schedule-filter-check {
  width: 16px;
  text-align: center;
  color: var(--accent);
  flex-shrink: 0;
}
.schedule-filter-swatch {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}
.schedule-filter-abbr {
  font-weight: 600;
  min-width: 2.5em;
}
.schedule-filter-fullname {
  color: var(--text-tertiary);
  font-size: 12px;
  margin-left: auto;
  text-align: right;
}
.schedule-filter-sep {
  height: 1px;
  background: var(--border);
  margin: 4px 2px;
}

/* Regular width: a touch more breathing room in the chrome. */
@media (min-width: 600px) {
  .schedule-chrome {
    padding: 14px 20px 10px;
  }
  .schedule-chrome__top .page-title { font-size: 28px; }
  .schedule-filter-menu__popover { min-width: 280px; }
}

/* ---- Schedule break editor (admin) ---- */
.schedule-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}
.schedule-edit-toggle {
  background: var(--bg-secondary);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 14px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.schedule-edit-toggle.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.schedule-row-wrapper {
  display: flex;
  align-items: center;
  gap: 10px;
}
.schedule-row-wrapper > :first-child {
  flex: 1;
  min-width: 0;
}
.schedule-break-btn {
  flex-shrink: 0;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  color: var(--text-primary);
  white-space: nowrap;
}
.schedule-break-btn.add {
  color: var(--accent);
  border-color: var(--accent);
}
.schedule-break-btn.edit {
  color: #B8860B;
  border-color: rgba(184, 134, 11, 0.4);
  background: rgba(255, 204, 0, 0.08);
}

/* ---- Schedule edit menu (admin-only) ----
 * Native <details>/<summary> popover anchored to the chrome's actions
 * row. Two mutually-exclusive admin modes: Edit Breaks + Reorder
 * Classes. Hidden behind a single Edit menu so non-admin users see no
 * chrome and admins only see the active mode at a glance. */
.schedule-edit-menu {
  position: relative;
}
.schedule-edit-menu > summary {
  list-style: none;
  cursor: pointer;
}
.schedule-edit-menu > summary::-webkit-details-marker { display: none; }
.schedule-edit-menu__body {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  min-width: 200px;
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.12);
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  z-index: 20;
}
.schedule-edit-menu__item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: transparent;
  border: 0;
  border-radius: 8px;
  font-size: 14px;
  color: var(--text-primary);
  cursor: pointer;
  text-align: left;
}
.schedule-edit-menu__item:hover {
  background: var(--bg-secondary, rgba(120, 120, 128, 0.10));
}
.schedule-edit-menu__item.selected {
  color: var(--accent);
  font-weight: 600;
}
.schedule-edit-menu__icon {
  width: 20px;
  text-align: center;
  font-size: 15px;
}

/* ============================================================
   Scoring Sheet — full-screen modal for entering / editing class
   results. Mirrors the iOS ScoringSheet: variable-depth slot strip,
   filterable entry list, autosave + Publish flow. Lives in its own
   overlay with full-height layout (vs. the bottom-sheet `.sheet`
   used by other dialogs) because the entry list needs vertical room.
   ============================================================ */

.overlay.scoring-overlay {
  align-items: stretch;
  /* Anchor to viewport bounds so the sheet's max-height math doesn't
     fight the overlay's flex centering. */
  padding: 0;
}

.scoring-sheet {
  width: 100%;
  max-width: 720px;
  margin: auto;
  height: 100dvh;
  max-height: 100dvh;
  background: var(--bg-primary);
  display: flex;
  flex-direction: column;
  animation: scoringSheetUp 0.32s cubic-bezier(0.21, 1.02, 0.73, 1);
}
@media (min-width: 768px) {
  .scoring-sheet {
    height: 92dvh;
    max-height: 92dvh;
    margin: auto;
    border-radius: var(--radius-xl);
    overflow: hidden;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.25);
  }
}
.overlay.scoring-overlay.out .scoring-sheet {
  animation: scoringSheetDown 0.2s ease forwards;
}
@keyframes scoringSheetUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
@keyframes scoringSheetDown { from { transform: translateY(0); opacity: 1; } to { transform: translateY(20px); opacity: 0; } }

.scoring-sheet__header {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--divider);
  background: var(--surface);
  flex-shrink: 0;
}
.scoring-sheet__close {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-active);
  color: var(--text-secondary);
  border: 0;
  font-size: 14px;
  cursor: pointer;
  flex-shrink: 0;
  transition: background-color 0.15s ease;
}
.scoring-sheet__close:hover { background: var(--divider); color: var(--text); }
.scoring-sheet__title-block { flex: 1; min-width: 0; }
.scoring-sheet__eyebrow {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 2px;
}
.scoring-sheet__title {
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.scoring-sheet__count {
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 700;
  color: var(--text-secondary);
  background: var(--surface-active);
  padding: 4px 10px;
  border-radius: 999px;
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}

/* Slot strip — horizontally scrollable, fixed-width tiles */
.scoring-sheet__strip-wrap {
  background: var(--surface);
  border-bottom: 1px solid var(--divider);
  flex-shrink: 0;
}
.scoring-sheet__strip {
  display: flex;
  gap: 6px;
  padding: 12px 14px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.scoring-sheet__strip::-webkit-scrollbar { display: none; }

.scoring-slot {
  flex-shrink: 0;
  width: 64px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 8px 4px;
  background: var(--surface-active);
  border: 2px solid transparent;
  border-radius: 10px;
  cursor: pointer;
  transition: border-color 0.15s ease, background-color 0.15s ease, transform 0.1s ease;
  font-family: inherit;
}
.scoring-slot:hover { background: var(--divider); }
.scoring-slot:active { transform: scale(0.97); }
.scoring-slot--active {
  border-color: var(--accent);
  background: rgba(91, 163, 217, 0.12);
}
.scoring-slot--filled .scoring-slot__num {
  font-family: var(--mono);
  color: var(--text);
}
.scoring-slot__ribbon {
  width: 100%;
  height: 4px;
  border-radius: 2px;
  background: #D1D1D6;
}
.scoring-slot__ribbon--1 { background: var(--ribbon-1); }
.scoring-slot__ribbon--2 { background: var(--ribbon-2); }
.scoring-slot__ribbon--3 { background: var(--ribbon-3); }
.scoring-slot__ribbon--4 { background: var(--ribbon-4); box-shadow: inset 0 0 0 1px var(--ribbon-4-border); }
.scoring-slot__ribbon--5 { background: var(--ribbon-5); }
.scoring-slot__ribbon--6 { background: var(--ribbon-6); }
.scoring-slot__num {
  font-size: 18px;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}
.scoring-slot--filled .scoring-slot__num { color: var(--text); font-size: 15px; }
.scoring-slot__ord {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.scoring-slot--add, .scoring-slot--remove {
  background: transparent;
  border: 2px dashed var(--divider);
}
.scoring-slot--add .scoring-slot__num { color: var(--accent); }
.scoring-slot--remove .scoring-slot__num { color: var(--text-secondary); }

/* Filter input */
.scoring-sheet__filter {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  background: var(--surface-active);
  border-bottom: 1px solid var(--divider);
  flex-shrink: 0;
}
.scoring-sheet__filter-icon {
  font-family: var(--mono);
  font-weight: 700;
  color: var(--text-tertiary);
}
.scoring-sheet__filter-input {
  flex: 1;
  background: transparent;
  border: 0;
  outline: 0;
  font-family: var(--mono);
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  padding: 4px 0;
}
.scoring-sheet__filter-input::placeholder { color: var(--text-tertiary); font-weight: 500; }
.scoring-sheet__filter-clear {
  background: transparent;
  border: 0;
  color: var(--text-tertiary);
  cursor: pointer;
  font-size: 14px;
  padding: 4px;
}
.scoring-sheet__filter-clear:hover { color: var(--text); }

/* Instruction banner */
.scoring-sheet__instruction {
  padding: 10px 16px;
  font-size: 13.5px;
  color: var(--text-secondary);
  background: var(--surface);
  border-bottom: 1px solid var(--divider);
  flex-shrink: 0;
}
.scoring-sheet__instruction strong { color: var(--accent); font-weight: 700; }

/* "+ Add entry" toggle next to the back-number filter */
.scoring-sheet__add-toggle {
  margin-left: 8px;
  padding: 6px 12px;
  background: transparent;
  color: var(--accent);
  border: 1px solid var(--accent-faint);
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.scoring-sheet__add-toggle:hover { background: var(--accent-faint); }

/* Inline add-entry form. Sits between the filter row and the entries
 * list. Stays in the document flow so the entries scroll naturally
 * below it; operator's eye doesn't have to chase a popover. */
.scoring-sheet__add-entry {
  background: var(--bg-elev-1, var(--bg-primary));
  border-bottom: 1px solid var(--divider);
  padding: 12px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex-shrink: 0;
}
.scoring-sheet__add-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.scoring-sheet__add-icon {
  font-weight: 700;
  color: var(--text-muted, #888);
}
.scoring-sheet__add-input {
  padding: 8px 10px;
  border: 1px solid var(--divider);
  border-radius: 8px;
  background: var(--bg-primary);
  color: inherit;
  font-size: 15px;
  width: 100%;
  box-sizing: border-box;
}
.scoring-sheet__add-input--back {
  max-width: 160px;
  font-feature-settings: 'tnum';
}
.scoring-sheet__add-match,
.scoring-sheet__add-create {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.scoring-sheet__add-match-summary {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 8px 10px;
  background: rgba(0, 122, 255, 0.08);
  border-radius: 8px;
}
.scoring-sheet__add-match-back {
  font-weight: 700;
  font-feature-settings: 'tnum';
  color: var(--accent);
}
.scoring-sheet__add-match-name {
  font-weight: 600;
}
.scoring-sheet__add-create-help {
  font-size: 13px;
  color: var(--text-muted, #888);
}
.scoring-sheet__add-error {
  color: #c33;
  font-size: 13px;
}

/* Status-agnostic "+ Add Entry to Class" button on class detail. */
.class-detail__add-entry-btn {
  margin: 16px 0 8px 0;
}

/* Standalone "+ Add Entry to Class" dialog — used from class detail
 * for any class status. Visually mirrors the scoring sheet's
 * inline add form, just hosted in a dedicated overlay so the
 * operator can drop in an entry on a SCHEDULED / SCRATCHED /
 * COMPLETED class where the scoring sheet isn't reachable. */
.add-entry-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 4000;
  animation: add-entry-in 180ms ease-out;
}
.add-entry-overlay.out {
  animation: add-entry-out 160ms ease-in forwards;
}
@keyframes add-entry-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes add-entry-out {
  from { opacity: 1; }
  to   { opacity: 0; }
}
.add-entry-dialog {
  background: var(--bg-primary);
  color: inherit;
  width: min(440px, 92vw);
  max-height: 80vh;
  border-radius: 14px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
}
.add-entry-dialog__header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--divider);
}
.add-entry-dialog__close {
  background: transparent;
  border: none;
  font-size: 18px;
  cursor: pointer;
  color: var(--text-muted, #888);
  padding: 4px 8px;
}
.add-entry-dialog__title-block {
  flex: 1;
}
.add-entry-dialog__eyebrow {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted, #888);
}
.add-entry-dialog__title {
  margin: 2px 0 0 0;
  font-size: 18px;
  font-weight: 700;
}
.add-entry-dialog__body {
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.add-entry-dialog__row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.add-entry-dialog__icon {
  font-weight: 700;
  color: var(--text-muted, #888);
  font-size: 18px;
}
.add-entry-dialog__input {
  padding: 10px 12px;
  border: 1px solid var(--divider);
  border-radius: 8px;
  background: var(--bg-elev-1, var(--bg-primary));
  color: inherit;
  font-size: 16px;
  width: 100%;
  box-sizing: border-box;
}
.add-entry-dialog__input--back {
  font-feature-settings: 'tnum';
  max-width: 200px;
}
.add-entry-dialog__match,
.add-entry-dialog__create {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.add-entry-dialog__match-summary {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 10px 12px;
  background: rgba(0, 122, 255, 0.08);
  border-radius: 8px;
}
.add-entry-dialog__match-back {
  font-weight: 700;
  font-feature-settings: 'tnum';
  color: var(--accent);
}
.add-entry-dialog__match-name { font-weight: 600; }
.add-entry-dialog__create-help {
  font-size: 13px;
  color: var(--text-muted, #888);
}
.add-entry-dialog__error {
  color: #c33;
  font-size: 13px;
}

/* Tools → Entries admin tool — class picker + per-class entry list. */
.entries-admin-pane {
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 320px;
}
.entries-admin__picker-row {
  display: flex;
  align-items: center;
  gap: 12px;
}
.entries-admin__picker-label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted, #888);
}
.entries-admin__picker {
  flex: 1;
  padding: 8px 10px;
  font-size: 15px;
  border: 1px solid var(--divider);
  border-radius: 8px;
  background: var(--bg-elev-1, var(--bg-primary));
  color: inherit;
}
.entries-admin__list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.entries-admin__add-btn {
  align-self: flex-start;
  margin-bottom: 4px;
}
.entries-admin__rows {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.entries-admin__row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  background: var(--bg-elev-1, var(--bg-primary));
  border: 1px solid var(--divider);
  border-radius: 10px;
}
.entries-admin__row--scratched {
  opacity: 0.55;
}
.entries-admin__back {
  font-weight: 700;
  font-feature-settings: 'tnum';
  font-size: 16px;
  min-width: 56px;
  color: var(--accent);
}
.entries-admin__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.entries-admin__horse {
  font-weight: 600;
  font-size: 14px;
}
.entries-admin__rider {
  font-size: 12px;
  color: var(--text-muted, #888);
}
.entries-admin__status-pill {
  display: inline-block;
  align-self: flex-start;
  margin-top: 2px;
  padding: 1px 7px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: rgba(255, 0, 0, 0.1);
  color: #c33;
  border-radius: 4px;
}
.entries-admin__actions {
  display: flex;
  gap: 6px;
}
.entries-admin__empty,
.entries-admin__loading,
.entries-admin__error {
  padding: 24px 12px;
  text-align: center;
  color: var(--text-muted, #888);
  font-size: 14px;
}
.entries-admin__error { color: #c33; }
.btn-sm {
  padding: 4px 10px !important;
  font-size: 13px !important;
}
.btn-danger {
  background: #c33;
  color: white;
  border: none;
}

/* Entry list */
.scoring-sheet__entries {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 8px;
  background: var(--bg-primary);
}
.scoring-sheet__empty {
  padding: 32px 20px;
  text-align: center;
  color: var(--text-tertiary);
  font-size: 14px;
  font-style: italic;
}
.scoring-entry {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px 14px;
  margin-bottom: 4px;
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: 10px;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  transition: border-color 0.15s ease, background-color 0.15s ease, transform 0.1s ease;
}
.scoring-entry:hover { border-color: var(--accent-faint); }
.scoring-entry:active { transform: scale(0.99); }
.scoring-entry--assigned { opacity: 0.55; }
.scoring-entry__back {
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 800;
  color: var(--accent);
  background: var(--accent-faint);
  padding: 4px 9px;
  border-radius: 999px;
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.scoring-entry__body { flex: 1; min-width: 0; }
.scoring-entry__horse {
  font-size: 14.5px;
  font-weight: 700;
  color: var(--text);
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.scoring-entry__rider {
  font-size: 13px;
  color: var(--text-secondary);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.scoring-entry__assigned {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
  background: var(--accent-faint);
  padding: 4px 9px;
  border-radius: 999px;
  flex-shrink: 0;
}

/* Footer with save status + Publish */
.scoring-sheet__footer {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
  background: var(--surface);
  border-top: 1px solid var(--divider);
  flex-shrink: 0;
}
.scoring-sheet__save-status {
  flex: 1;
  font-size: 12.5px;
  color: var(--text-secondary);
}
.scoring-sheet__save-status .scoring-saving { color: var(--text-secondary); }
.scoring-sheet__save-status .scoring-unsaved { color: var(--accent); }
.scoring-sheet__save-status .scoring-saved { color: var(--text-tertiary); }
.scoring-sheet__save-status .scoring-error-inline { color: #FF3B30; }
.scoring-sheet__publish {
  min-width: 160px;
  font-weight: 700;
}

.scoring-loading, .scoring-error {
  padding: 80px 24px;
  text-align: center;
  color: var(--text-secondary);
}

/* Scoring launch button on class detail (Phase 5 entry point) */
.scoring-launch-btn {
  margin: 4px 0 16px;
  font-weight: 700;
}

/* ---- Per-class admin kebab menu ----
 * Inline kebab `⋯` on every schedule row for OWNER / SHOW_MANAGER.
 * Opens a popover with the Set Status… submenu and (when this is the
 * ring's live class) Skip & Reschedule. Mirrors the iOS row context
 * menu so admin actions feel the same on both platforms. */
.class-admin-menu {
  position: relative;
  flex-shrink: 0;
}
.class-admin-menu > summary {
  list-style: none;
  cursor: pointer;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  letter-spacing: -2px;
  color: var(--text-secondary);
  -webkit-tap-highlight-color: transparent;
  transition: background-color 0.15s ease;
}
.class-admin-menu > summary::-webkit-details-marker { display: none; }
.class-admin-menu > summary:hover,
.class-admin-menu[open] > summary {
  background: var(--bg-secondary, rgba(120, 120, 128, 0.12));
  color: var(--text-primary);
}
.class-admin-menu__body {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  min-width: 220px;
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.16);
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 1px;
  z-index: 30;
}
.class-admin-menu__item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  background: transparent;
  border: 0;
  border-radius: 8px;
  font-size: 14px;
  color: var(--text-primary);
  cursor: pointer;
  text-align: left;
  width: 100%;
}
.class-admin-menu__item:hover {
  background: var(--bg-secondary, rgba(120, 120, 128, 0.10));
}
.class-admin-menu__item--strong {
  font-weight: 600;
  color: var(--accent);
}
.class-admin-menu__icon {
  width: 18px;
  text-align: center;
  font-size: 14px;
  color: var(--text-tertiary);
  flex-shrink: 0;
}
.class-admin-menu__item--strong .class-admin-menu__icon {
  color: var(--accent);
}
.class-admin-menu__divider {
  height: 1px;
  background: var(--border);
  margin: 4px 8px;
}
.class-admin-menu__section {
  padding: 6px 12px 4px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}

/* ---- Scoring format picker sheet (#164) ----
 * Web parity with iOS ScoringFormatPickerSheet. Renders 5 radio
 * options + a rounds stepper inside the standard .sheet/.overlay
 * pattern used elsewhere (confirmSkipClass, edit sponsor, etc).
 * Each option is a row that highlights when selected. */
.scoring-format-opts {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.scoring-format-opt {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--border-default, rgba(0,0,0,0.1));
  border-radius: 8px;
  cursor: pointer;
  transition: background-color 0.15s, border-color 0.15s;
}
.scoring-format-opt:hover {
  background-color: var(--bg-elevated, rgba(0,0,0,0.04));
}
.scoring-format-opt--selected {
  background-color: var(--accent-bg, rgba(0,122,255,0.08));
  border-color: var(--accent, #007aff);
}
.scoring-format-opt input[type="radio"] {
  margin-top: 2px;
  accent-color: var(--accent, #007aff);
}
.scoring-format-opt__text { display: flex; flex-direction: column; gap: 2px; flex: 1; }
.scoring-format-opt__label { font-size: 14px; font-weight: 600; color: var(--text-primary); }
.scoring-format-opt__hint { font-size: 12px; color: var(--text-secondary); line-height: 1.35; }
.scoring-format-rounds {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 14px;
  padding: 10px 12px;
  border: 1px solid var(--border-default, rgba(0,0,0,0.1));
  border-radius: 8px;
  flex-wrap: wrap;
}
.scoring-format-rounds label { font-size: 14px; font-weight: 600; color: var(--text-primary); }
.scoring-format-rounds input[type="number"] {
  width: 64px;
  padding: 6px 8px;
  border: 1px solid var(--border-default, rgba(0,0,0,0.15));
  border-radius: 6px;
  font-size: 14px;
}
.scoring-format-rounds__hint {
  font-size: 12px;
  color: var(--text-secondary);
  flex: 1 1 100%;
}

/* ---- Schedule reorder mode ----
 * Each class row gets a leading drag handle and a draggable wrapper
 * when the admin is in Reorder Classes mode. The handle itself is
 * decorative — the entire row is draggable — but it visually
 * communicates the affordance. */
.schedule-row-wrapper--draggable {
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
}
.schedule-row-wrapper--draggable:active { cursor: grabbing; }
.schedule-drag-handle {
  flex-shrink: 0;
  font-size: 18px;
  color: var(--text-tertiary);
  padding: 0 6px;
  letter-spacing: -2px;
}
.schedule-row-wrapper--dragging {
  opacity: 0.4;
}
.schedule-row-wrapper--drop-target {
  /* Top-edge bar so the user can see exactly where the dragged row
   * will land before they release. */
  box-shadow: inset 0 3px 0 var(--accent);
}

/* ---- App Notice (platform-admin force-upgrade / soft-suggestion) ---- */
.app-notice-banner {
  position: fixed;
  top: env(safe-area-inset-top, 0);
  left: 0;
  right: 0;
  z-index: 1000;
  background: var(--accent);
  color: #fff;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  font-size: 13px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.app-notice-banner__icon { font-size: 18px; flex-shrink: 0; }
.app-notice-banner__text { flex: 1; min-width: 0; }
.app-notice-banner__title { font-weight: 700; line-height: 1.2; }
.app-notice-banner__message {
  font-size: 12px;
  opacity: 0.92;
  margin-top: 2px;
  line-height: 1.3;
  /* Two-line clamp so a chatty admin doesn't blow out the chrome. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.app-notice-banner__cta {
  background: rgba(255, 255, 255, 0.18);
  border: 0;
  color: #fff;
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
  flex-shrink: 0;
}
.app-notice-banner__cta:hover { background: rgba(255, 255, 255, 0.28); }
.app-notice-banner__dismiss {
  background: transparent;
  border: 0;
  color: #fff;
  font-size: 18px;
  cursor: pointer;
  padding: 4px 8px;
  flex-shrink: 0;
}

.app-notice-modal {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2000;
  padding: 24px;
  animation: fadeIn 200ms ease-out;
}
.app-notice-modal__card {
  max-width: 420px;
  width: 100%;
  background: var(--surface, #fff);
  border-radius: 18px;
  padding: 28px 24px;
  text-align: center;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.30);
}
.app-notice-modal__icon {
  font-size: 56px;
  color: var(--accent);
  line-height: 1;
  margin-bottom: 12px;
}
.app-notice-modal__title {
  margin: 0 0 12px;
  font-size: 22px;
  font-weight: 700;
  color: var(--text-primary);
}
.app-notice-modal__message {
  margin: 0 0 20px;
  font-size: 15px;
  color: var(--text-secondary);
  line-height: 1.45;
}
.app-notice-modal__note {
  margin: 16px 0 0;
  font-size: 11px;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Generic modal overlay used by the break editor. */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  padding: 16px;
}
.modal-card {
  background: var(--surface);
  color: var(--text);
  border-radius: 14px;
  max-width: 440px;
  width: 100%;
  max-height: 90vh;
  overflow-y: auto;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
}
.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
}
.modal-header h2 {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
}
.modal-close {
  background: none;
  border: none;
  font-size: 24px;
  cursor: pointer;
  color: var(--text-secondary);
  padding: 0;
  line-height: 1;
}
.modal-body {
  padding: 16px 20px;
}
.modal-context {
  padding: 10px 12px;
  background: var(--bg-secondary);
  border-radius: 8px;
  font-size: 14px;
  color: var(--text-secondary);
  margin-bottom: 16px;
}
.modal-field {
  display: block;
  margin-bottom: 14px;
}
.modal-field > span {
  display: block;
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 6px;
  color: var(--text-secondary);
}
.modal-field input,
.modal-field textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 15px;
  background: var(--bg-primary);
  color: var(--text-primary);
  font-family: inherit;
  box-sizing: border-box;
}
.modal-error {
  color: var(--red, #FF3B30);
  font-size: 13px;
  padding: 8px 12px;
  background: rgba(255, 59, 48, 0.1);
  border-radius: 6px;
  margin-top: 8px;
}
.modal-footer {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 14px 20px;
  border-top: 1px solid var(--border);
}
.modal-footer-spacer { flex: 1; }
.modal-footer .btn {
  padding: 8px 16px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  border: 1px solid var(--border);
  cursor: pointer;
}
.modal-footer .btn-primary {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.modal-footer .btn-secondary {
  background: var(--bg-secondary);
  color: var(--text-primary);
}
.modal-footer .btn-danger {
  background: rgba(255, 59, 48, 0.1);
  color: #FF3B30;
  border-color: rgba(255, 59, 48, 0.3);
}

/* ---- Upcoming break row (Live tab Coming Up terminal) ---- */
/* Breaks are real schedule events, not filler — give them the same visual
   weight as a class row with an "UP NEXT" eyebrow so attendees don't skim
   past them. */
.upcoming-break-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px;
  border-radius: 12px;
  background: rgba(255, 204, 0, 0.08);
  border: 1px solid rgba(255, 204, 0, 0.25);
  margin-top: 10px;
}
.upcoming-break-day_end {
  background: rgba(88, 86, 214, 0.08);
  border-color: rgba(88, 86, 214, 0.25);
}
.upcoming-break-show_end {
  background: rgba(175, 82, 222, 0.08);
  border-color: rgba(175, 82, 222, 0.25);
}
.upcoming-break-icon-wrap {
  width: 48px;
  height: 48px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 204, 0, 0.18);
  flex-shrink: 0;
}
.upcoming-break-day_end .upcoming-break-icon-wrap { background: rgba(88, 86, 214, 0.18); }
.upcoming-break-show_end .upcoming-break-icon-wrap { background: rgba(175, 82, 222, 0.18); }
.upcoming-break-icon {
  font-size: 22px;
  line-height: 1;
}
.upcoming-break-info {
  flex: 1;
  min-width: 0;
}
.upcoming-break-eyebrow {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.8px;
  color: #B8860B;
  margin-bottom: 2px;
}
.upcoming-break-day_end .upcoming-break-eyebrow { color: #5856D6; }
.upcoming-break-show_end .upcoming-break-eyebrow { color: #AF52DE; }
.upcoming-break-label {
  font-size: 16px;
  font-weight: 700;
  color: var(--text-primary);
}
.upcoming-break-subtitle {
  font-size: 13px;
  color: var(--text-secondary);
  margin-top: 3px;
}

/* ---- Show state full-body hero ---- */
/* Parity with iOS ShowStateHero: full-screen takeover on Live + Schedule
   tabs when the show isn't actively running. Kept visually distinct from
   the compact banner so the state feels intentional and emphasised.
   Rendered as a direct child of #app (outside .view) so it can use
   `position: fixed` without inheriting .view's `fadeUp` translateY
   transform — which would otherwise reparent the fixed hero to .view
   for the duration of the keyframe and snap it to viewport center
   when the keyframe ends. See renderLiveContent for the why. */
.show-state-hero {
  position: fixed;
  /* A fixed element ignores body's padding-left, so to keep the hero
     centered in the AVAILABLE space we inset its left edge ourselves.
     In compact mode there is no sidebar, so left is just the safe area;
     the >=900px sidebar offset is added in the media query below.
     IMPORTANT: --sidebar-w stays 240px at ALL widths (it is NOT reset to
     0 in compact mode), so applying it here would shove the centered hero
     ~240px right. Top/bottom stay at 0 to preserve vertical centering. */
  top: 0;
  bottom: 0;
  left: var(--safe-l, 0px);
  right: var(--safe-r, 0px);
  padding: 48px 32px calc(88px + env(safe-area-inset-bottom));
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  background: linear-gradient(180deg, var(--hero-bg, rgba(0,122,255,0.12)), rgba(0,0,0,0) 80%), var(--bg-primary);
  z-index: 1;
  /* Avoid layout reflow propagating into the rest of the page —
     the hero owns its viewport-sized box and nothing inside should
     ever need to influence siblings. */
  contain: layout paint;
  /* Single calm fade — no translation, so a `position: fixed` child
     never gets reparented mid-animation. The previous `.view fadeUp`
     translation was the source of the "tries to center itself" glitch
     when the hero used to live inside .view. */
  animation: heroFadeIn 0.22s ease-out;
}

/* Only inset for the sidebar where it actually exists (>=900px). Below
   that the sidebar is an off-canvas drawer and the content area is the
   full viewport, so the hero centers edge-to-edge like the sponsor band. */
@media (min-width: 900px) {
  .show-state-hero { left: calc(var(--sidebar-w) + var(--safe-l, 0px)); }
}

@keyframes heroFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.show-state-hero-inner {
  max-width: 520px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}

.show-state-hero-icon {
  width: 88px;
  height: 88px;
  color: var(--hero-tint, #007AFF);
}

.show-state-hero-icon svg {
  width: 100%;
  height: 100%;
}

.show-state-hero-headline {
  font-size: 30px;
  font-weight: 800;
  letter-spacing: 1.5px;
  color: var(--hero-tint, #007AFF);
  text-transform: uppercase;
}

.show-state-hero-summary {
  font-size: 20px;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.3;
}

.show-state-hero-subline {
  font-size: 15px;
  color: var(--text-secondary);
  line-height: 1.4;
  max-width: 420px;
}

/* Per-state tinting via CSS variables. */
.show-state-pre_show        { --hero-tint: #007AFF; --hero-bg: rgba(0,122,255,0.12); }
.show-state-day_of_pending  { --hero-tint: #FF9500; --hero-bg: rgba(255,149,0,0.12); }
.show-state-active          { --hero-tint: #34C759; --hero-bg: rgba(52,199,89,0.12); }
.show-state-on_break        { --hero-tint: #B8860B; --hero-bg: rgba(255,204,0,0.18); }
.show-state-day_ended       { --hero-tint: #5856D6; --hero-bg: rgba(88,86,214,0.12); }
.show-state-show_ended      { --hero-tint: #AF52DE; --hero-bg: rgba(175,82,222,0.12); }

/* ---- Empty State ---- */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 64px 32px;
  text-align: center;
}

.empty-icon {
  width: 48px;
  height: 48px;
  color: var(--text-tertiary);
  opacity: 0.4;
  margin-bottom: 16px;
}

.empty h3 {
  font-size: 20px;
  font-weight: 600;
  margin-bottom: 4px;
}

.empty p {
  font-size: 15px;
  color: var(--text-secondary);
  max-width: 260px;
}

/* ---- Day Tabs ----
   Calendar-strip style: each day is a self-sized pill stacking the
   weekday name above the day-of-month number. No segmented background
   — pills sit directly on the schedule-chrome's translucent surface
   and the active state earns its weight with an accent fill. */
.day-tabs {
  display: flex;
  gap: 4px;
  background: transparent;
  padding: 0;
  margin: 0;
}

.day-tab {
  flex: 0 0 auto;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-width: 56px;
  padding: 6px 14px 8px;
  border-radius: 12px;
  background: transparent;
  color: var(--text-secondary);
  font-family: inherit;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}

.day-tab:hover {
  background: var(--surface-hover);
  color: var(--text);
}
.day-tab:active { opacity: 0.7; }

.day-tab__day {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.75;
}
.day-tab__num {
  font-size: 18px;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.day-tab.active {
  background: var(--blue-bg);
  color: var(--accent);
}
.day-tab.active .day-tab__day {
  opacity: 1;
}

/* ---- Division Chips ---- */
.chips {
  display: flex;
  gap: 8px;
  padding: 0 0 14px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.chips::-webkit-scrollbar { display: none; }

.chip {
  flex-shrink: 0;
  padding: 7px 16px;
  border-radius: var(--radius-full);
  font-size: 13px;
  font-weight: 600;
  border: 1.5px solid var(--border-strong);
  color: var(--text-secondary);
  background: var(--surface);
  transition: all 0.2s;
}

.chip:active { transform: scale(0.94); }

.chip.active {
  background: var(--text);
  color: var(--bg);
  border-color: var(--text);
}

/* ---- Search ---- */
.search-input {
  width: 100%;
  height: 44px;
  padding: 0 16px 0 42px;
  border-radius: var(--radius-md);
  background: var(--surface);
  border: 1px solid transparent;
  font-size: 15px;
  color: var(--text);
  margin-bottom: 16px;
  transition: border-color 0.2s, box-shadow 0.2s;
  box-shadow: var(--shadow-sm);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%2386868b' stroke-width='2'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='M21 21l-4.35-4.35'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: 14px center;
}

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

.search-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 15%, transparent);
  background-color: var(--surface);
}

/* ---- Alerts ---- */
.alert-item {
  padding: 16px;
  background: var(--surface);
  border-radius: var(--radius-md);
  margin-bottom: 8px;
  box-shadow: var(--shadow-sm);
}

.alert-message {
  font-size: 15px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--text);
}

.alert-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  font-size: 13px;
  color: var(--text-tertiary);
}

.alert-sender { font-weight: 600; color: var(--text-secondary); }

/* ---- Info Section ---- */
/* The info groups flow into a fluid grid: as many columns as fit at
   ~22rem each, single column on phones, two-or-three on wider canvas.
   No @media queries — `auto-fit` + `minmax(min(100%, …), 1fr)` is the
   canonical CSS Grid pattern that responds to the grid's own width.
   `min(100%, 22rem)` ensures the minimum column width never exceeds
   the container, so we don't overflow on very narrow phones. */
.info-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
  gap: 20px 20px;
  align-items: start;
}

.info-group {
  margin-bottom: 0;          /* gap handles vertical rhythm now */
  /* Container-query host. When this group lives in a narrow grid
     column (info-grid at desktop), it can adapt its inner content to
     the column width — see the @container rule below. Inline-size
     containment so vertical content height isn't constrained. */
  container-type: inline-size;
}

/* In narrow info-grid columns the `.info-row` padding eats into a
   noticeable share of the visible width; tighten it so labels and
   values stay legible. The threshold (22rem ≈ 352px) matches the
   `.info-grid` minmax floor — when a group is as narrow as a column
   in a multi-column layout, this rule kicks in. */
@container (max-width: 22rem) {
  .info-row {
    padding: 10px 14px;
  }
}

/* Wide-content groups (Venue with map; "Stay in the Loop" contact
   form) span the full grid so their content has room. Phone is
   already single-column so the `1 / -1` is a no-op there. */
.info-group--span {
  grid-column: 1 / -1;
}

.info-group-title {
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
  padding: 0 4px 8px;
}

.info-list {
  background: var(--surface);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}

.info-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 13px 16px;
  border-bottom: 0.5px solid var(--divider);
  font-size: 15px;
}

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

.info-label { color: var(--text); font-weight: 500; }

.info-value {
  color: var(--text-secondary);
  text-align: right;
  max-width: 55%;
  line-height: 1.3;
}

.info-link { color: var(--accent); font-weight: 500; }

.info-row.interactive { cursor: pointer; }
.info-row.interactive:active { background: var(--surface-active); }

/* Sponsor row — info tab. Logo when uploaded, tier emoji otherwise. */
.sponsor-row__logo {
  width: 44px;
  height: 44px;
  border-radius: 8px;
  object-fit: contain;
  background: var(--surface);
  border: 1px solid var(--divider);
  flex-shrink: 0;
}
.sponsor-row__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  font-size: 22px;
}

/* Sponsors admin modal */
.sponsors-admin {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.sponsors-admin--busy { opacity: 0.6; pointer-events: none; }
.sponsors-admin__empty {
  text-align: center;
  padding: 24px;
  color: var(--text-secondary);
}
.sponsors-admin__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.sponsors-admin__row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: 10px;
  cursor: grab;
}
.sponsors-admin__row[draggable="true"]:hover { background: var(--surface-active); }
.sponsors-admin__row--dragging { opacity: 0.4; }
.sponsors-admin__row--drop-target { outline: 2px dashed var(--accent); }
.sponsors-admin__row--editing {
  cursor: default;
  flex-direction: column;
  align-items: stretch;
  padding: 14px;
}
.sponsors-admin__handle {
  font-size: 14px;
  color: var(--text-tertiary);
  flex-shrink: 0;
  cursor: grab;
}
.sponsors-admin__logo {
  width: 44px;
  height: 44px;
  border-radius: 8px;
  object-fit: contain;
  background: var(--surface);
  border: 1px solid var(--divider);
  flex-shrink: 0;
}
.sponsors-admin__logo--empty {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  color: var(--text-secondary);
}
.sponsors-admin__meta { flex: 1; min-width: 0; }
.sponsors-admin__name { font-weight: 600; color: var(--text); }
.sponsors-admin__tier {
  font-size: 12px;
  color: var(--text-secondary);
  text-transform: capitalize;
}
.sponsors-admin__url {
  text-transform: none;
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 11px;
  word-break: break-all;
}
.sponsors-admin__form { display: flex; flex-direction: column; gap: 10px; }
.sponsors-admin__form-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.sponsors-admin__form-row label {
  flex: 1;
  min-width: 160px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--text-secondary);
}
.sponsors-admin__form-row input,
.sponsors-admin__form-row select {
  padding: 8px 10px;
  border: 1px solid var(--divider);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text);
  font-size: 14px;
}
.sponsors-admin__logo-controls {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 10px;
  background: var(--surface);
  border-radius: 8px;
}
.sponsors-admin__logo-preview {
  width: 64px;
  height: 64px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.sponsors-admin__logo-preview img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.sponsors-admin__logo-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.sponsors-admin__form-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  flex-wrap: wrap;
}
.sponsors-admin__add { align-self: flex-start; }
.sponsors-admin__footer { padding-top: 4px; }
.btn-sm { padding: 6px 10px; font-size: 13px; }
.btn-danger { background: #dc2626; color: white; }
.btn-danger:hover { background: #b91c1c; }

/* ---- Social Events admin (modal, mirrors .sponsors-admin) ---- */
.social-events-admin {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.social-events-admin--busy { opacity: 0.6; pointer-events: none; }
.social-events-admin__empty {
  text-align: center;
  padding: 24px;
  color: var(--text-secondary);
}
.social-events-admin__day { display: flex; flex-direction: column; gap: 8px; }
.social-events-admin__day-header {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--accent);
  padding: 0 2px;
}
.social-events-admin__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.social-events-admin__row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: 10px;
  cursor: grab;
}
.social-events-admin__row[draggable="true"]:hover { background: var(--surface-active); }
.social-events-admin__row--dragging { opacity: 0.4; }
.social-events-admin__row--drop-target { outline: 2px dashed var(--accent); }
.social-events-admin__row--editing {
  cursor: default;
  flex-direction: column;
  align-items: stretch;
  padding: 14px;
}
.social-events-admin__handle {
  font-size: 14px;
  color: var(--text-tertiary);
  flex-shrink: 0;
  cursor: grab;
}
.social-events-admin__meta { flex: 1; min-width: 0; }
.social-events-admin__name { font-weight: 600; color: var(--text); }
.social-events-admin__sub {
  font-size: 12px;
  color: var(--text-secondary);
}
.social-events-admin__form { display: flex; flex-direction: column; gap: 10px; }
.social-events-admin__form-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.social-events-admin__form-row label {
  flex: 1;
  min-width: 160px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--text-secondary);
}
.social-events-admin__form-row input,
.social-events-admin__form-row textarea {
  padding: 8px 10px;
  border: 1px solid var(--divider);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text);
  font-size: 14px;
  font-family: inherit;
}
.social-events-admin__form-row textarea { resize: vertical; }
.social-events-admin__form-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  flex-wrap: wrap;
}
.social-events-admin__add { align-self: flex-start; }
.social-events-admin__footer { padding-top: 4px; }

/* ---- Buttons ---- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 50px;
  padding: 0 28px;
  border-radius: var(--radius-md);
  font-size: 17px;
  font-weight: 600;
  transition: all 0.12s;
  -webkit-user-select: none;
  user-select: none;
}

.btn:active { transform: scale(0.97); }
.btn:disabled { opacity: 0.4; pointer-events: none; }

.btn-primary {
  background: var(--accent);
  color: #ffffff;
}

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

.btn-green { background: var(--green); color: #ffffff; }
.btn-orange { background: var(--orange); color: #ffffff; }
.btn-red { background: var(--red); color: #ffffff; }

.btn-secondary {
  background: transparent;
  color: var(--accent);
  border: 1.5px solid var(--border-strong);
}

.btn-secondary:hover { background: var(--surface-hover); }

.btn-outline {
  background: none;
  border: 1px solid var(--border);
  color: var(--text);
}
.btn-outline:active {
  background: var(--surface);
}

.btn-ghost {
  background: transparent;
  color: var(--accent);
  height: 36px;
  padding: 0 12px;
  font-size: 15px;
}

.btn-block { width: 100%; }

.btn-sm {
  height: 36px;
  padding: 0 16px;
  font-size: 14px;
  border-radius: var(--radius-sm);
}

/* ---- Star Button ---- */
.star-btn {
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: 22px;
  color: var(--text-tertiary);
  border-radius: var(--radius-sm);
  transition: all 0.2s;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  background: none;
  border: none;
  padding: 0;
}

.star-btn:active { transform: scale(0.85); }
.star-btn.active,
.star-btn.followed { color: var(--orange); }

/* ---- Form ---- */
.form-group {
  margin-bottom: 16px;
}

.form-label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 6px;
}

.form-input {
  width: 100%;
  height: 50px;
  padding: 0 16px;
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  border: 1px solid transparent;
  font-size: 17px;
  color: var(--text);
  transition: border-color 0.2s, box-shadow 0.2s;
}

.form-input::placeholder { color: var(--text-tertiary); }

.form-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 15%, transparent);
  background: var(--surface);
}

.form-textarea {
  width: 100%;
  min-height: 120px;
  padding: 14px 16px;
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  border: 1px solid transparent;
  font-size: 17px;
  color: var(--text);
  resize: vertical;
  line-height: 1.4;
  transition: border-color 0.2s, box-shadow 0.2s;
}

.form-textarea::placeholder { color: var(--text-tertiary); }

.form-textarea:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 15%, transparent);
  background: var(--surface);
}

.form-select {
  width: 100%;
  padding: 12px 16px;
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  font-size: 16px;
  color: var(--text);
  -webkit-appearance: none;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23999' stroke-width='2'%3E%3Cpath d='M2 4l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
}

.form-select:focus {
  border-color: var(--accent);
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 15%, transparent);
}

.show-pick-row.active {
  background: var(--surface);
}

.form-error {
  font-size: 14px;
  color: var(--red);
  margin-top: 8px;
}

/* ---- Login ---- */
.login-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: calc(100dvh - var(--top-bar-h) - var(--safe-b) - var(--safe-t) - 40px);
  padding: 24px 0;
}

.login-card {
  width: 100%;
  max-width: 380px;
  text-align: center;
}

.login-logo {
  width: 64px;
  height: 64px;
  margin: 0 auto 24px;
  border-radius: var(--radius-lg);
  background: var(--bg-secondary);
  display: flex;
  align-items: center;
  justify-content: center;
}

.login-logo svg {
  width: 32px;
  height: 32px;
  color: var(--accent);
}

.login-title {
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-bottom: 4px;
}

.login-sub {
  font-size: 15px;
  color: var(--text-secondary);
  margin-bottom: 32px;
}

.admin-current {
  background: var(--surface);
  border-radius: var(--radius-xl);
  padding: 28px;
  text-align: center;
  margin-bottom: 16px;
  position: relative;
  box-shadow: var(--shadow-md);
}

.admin-current .ring-label {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
  margin-bottom: 12px;
}

/* Hero class number — 48pt to match iOS system(size: 48, weight: .bold) */
.admin-current .class-num-xl {
  font-family: var(--font-display);
  font-size: 48px;
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
}

/* Class name — title3 equivalent (~18pt) */
.admin-current .class-name-lg {
  font-size: 18px;
  font-weight: 500;
  margin-top: 6px;
  color: var(--text);
  line-height: 1.3;
}

/* Elapsed timer — title3 bold monospaced (iOS ~16pt) */
.admin-current .timer-lg {
  font-family: var(--mono);
  font-size: 18px;
  font-weight: 700;
  color: var(--text-secondary);
  margin-top: 14px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.on-deck-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 18px;
  background: var(--surface);
  border-radius: var(--radius-md);
  margin-bottom: 16px;
  font-size: 14px;
  box-shadow: var(--shadow-sm);
}

.on-deck-label {
  font-weight: 600;
  color: var(--text-tertiary);
  text-transform: uppercase;
  font-size: 11px;
  letter-spacing: 0.04em;
  flex-shrink: 0;
}

.on-deck-name {
  flex: 1;
  font-weight: 600;
  color: var(--text);
  line-height: 1.3;
}

.admin-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.admin-actions .row {
  display: flex;
  gap: 8px;
}

.admin-actions .row > * { flex: 1; }

.action-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  height: 56px;
  border-radius: var(--radius-md);
  font-size: 16px;
  font-weight: 700;
  color: #fff;
  transition: transform 0.12s, opacity 0.12s;
  -webkit-user-select: none;
  user-select: none;
  letter-spacing: 0.01em;
}

.action-btn:active { transform: scale(0.97); opacity: 0.85; }
.action-btn:disabled { opacity: 0.35; pointer-events: none; }

.action-advance { background: var(--green); height: 64px; font-size: 17px; }
.action-advance-ready { box-shadow: 0 0 0 3px rgba(52, 199, 89, 0.35); animation: action-pulse 1.8s ease-in-out infinite; }
.action-start { background: var(--accent); height: 64px; font-size: 17px; }
.action-delay { background: var(--orange); }
/* Line up: yellow with checkered flag. White text + white monochrome flag
   to match the visual treatment of DELAY and CLASS COMPLETE buttons. */
.action-lineup { background: #ffcc00; color: #fff; }
.action-lineup .flag-icon {
  filter: brightness(0) invert(1);
  display: inline-block;
}
.action-scratch { background: var(--red); }
.action-reset { background: var(--text-tertiary); }

@keyframes action-pulse {
  0%, 100% { box-shadow: 0 0 0 3px rgba(52, 199, 89, 0.25); }
  50% { box-shadow: 0 0 0 6px rgba(52, 199, 89, 0.15); }
}

/* ---- Admin toolbar (v2 parity) ---- */
/* Top-of-admin row: leading Tools menu + dynamic Undo button, trailing
 * read-only state pill. Replaces the legacy h1 + ⋯ menu + segment picker
 * stripped in the v2 parity work. Mirrors iOS AdminView's NavigationStack
 * toolbar layout. */
.admin-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  margin-bottom: 8px;
  border-bottom: 1px solid var(--border);
  background: var(--bg);
  position: sticky;
  top: 0;
  z-index: 5;
}
.admin-toolbar__spacer { flex: 1; }
.admin-toolbar__tools-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 10px;
  background: var(--bg-secondary, rgba(120,120,128,.08));
  border: 0;
  color: var(--text-primary);
  cursor: pointer;
  transition: background 0.15s ease;
  flex: 0 0 auto;
}
.admin-toolbar__tools-btn:hover {
  background: var(--bg-secondary-hover, rgba(120,120,128,.16));
}
.admin-toolbar__tools-btn:active { transform: scale(0.96); }

.admin-toolbar__undo-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px;
  border-radius: 999px;
  background: rgba(0, 122, 255, 0.12);
  color: var(--accent, #007aff);
  border: 0;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  min-width: 0;
  transition: background 0.15s ease, transform 0.12s ease;
  flex: 0 1 auto;
}
.admin-toolbar__undo-btn:hover {
  background: rgba(0, 122, 255, 0.20);
}
.admin-toolbar__undo-btn:active { transform: scale(0.97); }
.admin-toolbar__undo-btn.hidden { display: none; }
.admin-toolbar__undo-label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 200px;
}

.admin-toolbar__state-pill {
  display: inline-block;
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  flex: 0 0 auto;
}
.admin-toolbar__state-pill--live   { background: rgba(52, 199, 89, 0.15);  color: #1f8a3e; }
.admin-toolbar__state-pill--lineup { background: rgba(255, 204, 0, 0.18);  color: #b38f00; }
.admin-toolbar__state-pill--warn   { background: rgba(255, 149, 0, 0.18);  color: var(--orange); }
.admin-toolbar__state-pill--idle   { background: rgba(120, 120, 128, 0.16); color: var(--text-secondary); }

@media (prefers-color-scheme: dark) {
  .admin-toolbar__state-pill--live   { background: rgba(52, 199, 89, 0.18);  color: #4cd964; }
  .admin-toolbar__state-pill--lineup { background: rgba(255, 204, 0, 0.22);  color: #ffd60a; }
  .admin-toolbar__state-pill--warn   { background: rgba(255, 149, 0, 0.22);  color: #ff9f0a; }
  .admin-toolbar__state-pill--idle   { background: rgba(160, 160, 170, 0.18); color: #b3b3b8; }
}

@media (max-width: 360px) {
  .admin-toolbar__undo-label { max-width: 130px; }
  .admin-toolbar__state-pill { padding: 4px 8px; font-size: 10px; }
}

/* ---- Tools menu popup ---- */
/* Anchored under the Tools button in the admin toolbar. Reuses the
 * legacy .admin-menu positioning (popup card with shadow + rounded
 * corners) but with its own selector so we can delete .admin-menu in
 * Task 5 without breaking this. */
.admin-tools-menu {
  position: absolute;
  top: 52px;
  left: 12px;
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.12);
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 200px;
  z-index: 10;
}
.admin-tools-menu.hidden { display: none; }
.admin-tools-menu__item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  background: transparent;
  border: 0;
  border-radius: 8px;
  font-size: 14px;
  color: var(--text-primary);
  cursor: pointer;
  text-align: left;
}
.admin-tools-menu__item:hover {
  background: var(--bg-secondary, rgba(120,120,128,.10));
}
.admin-tools-menu__icon { font-size: 16px; }
.admin-tools-menu__label { flex: 1; }
.admin-tools-menu__divider {
  height: 1px;
  background: var(--border);
  margin: 4px 4px;
}
.admin-tools-menu__section-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  padding: 4px 12px 2px;
}

/* ---- Show-state override: pill becomes a tappable button + popup menu
 * (mirror of iOS ShowStateOverrideMenu). The pill --button modifier
 * just turns the span/button into something clickable; the menu reuses
 * the tools-menu visual language but anchors right (the pill sits at
 * the trailing edge of the toolbar). */
.admin-toolbar__state-pill--button {
  border: 0;
  cursor: pointer;
  font-family: inherit;
  -webkit-appearance: none;
  appearance: none;
}
.admin-toolbar__state-pill--button:hover { filter: brightness(1.05); }
.admin-toolbar__state-pill--button:active { transform: scale(0.97); }

.admin-state-menu {
  position: absolute;
  top: 52px;
  right: 12px;
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.12);
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 240px;
  z-index: 10;
}
.admin-state-menu.hidden { display: none; }
.admin-state-menu__item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  background: transparent;
  border: 0;
  border-radius: 8px;
  font-size: 14px;
  color: var(--text-primary);
  cursor: pointer;
  text-align: left;
}
.admin-state-menu__item:hover {
  background: var(--bg-secondary, rgba(120, 120, 128, 0.10));
}
.admin-state-menu__icon { font-size: 16px; width: 20px; text-align: center; }
.admin-state-menu__label { flex: 1; }
.admin-state-menu__divider {
  height: 1px;
  background: var(--border);
  margin: 4px 6px;
}

/* ---- Break sheet: Duration / Resume Time mode toggle ---- */
.break-mode-toggle {
  display: flex;
  background: rgba(120, 120, 128, 0.12);
  border-radius: 8px;
  padding: 3px;
  margin-bottom: 12px;
}
.break-mode-btn {
  flex: 1;
  padding: 8px 12px;
  background: transparent;
  border: 0;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary);
  cursor: pointer;
  transition: background 120ms ease;
}
.break-mode-btn.selected {
  background: var(--surface, #fff);
  color: var(--text-primary);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
@media (prefers-color-scheme: dark) {
  .break-mode-btn.selected { background: rgba(255, 255, 255, 0.08); }
}
.break-mode-panel.hidden { display: none; }

/* Admin hero card — colored status badge above class number, matches iOS */
.admin-hero-badge {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 8px;
}
.admin-hero-badge.badge-in-ring { color: var(--green); }
.admin-hero-badge.badge-lineup { color: #b38f00; }
.admin-hero-badge.badge-delayed { color: var(--orange); }

/* Dark mode: boost yellow text legibility */
@media (prefers-color-scheme: dark) {
  .action-lineup { background: #ffd60a; color: #fff; }
  .admin-hero-badge.badge-lineup { color: #ffd60a; }
}

/* ---- Pacing admin modal ---- */
/* Mirrors iOS PacingSheet (Views/Admin/PacingSheet.swift):
 * Three sections (Status, Visibility, What the algorithm is doing)
 * inside the standard admin tool modal. Platform admins only. */
.pacing-modal {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.pacing-modal__empty {
  font-size: 13px;
  color: var(--text-tertiary);
  text-align: center;
  padding: 24px;
}
.pacing-modal__section {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.pacing-modal__section-header {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}
.pacing-modal__status {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  background: var(--bg-secondary, rgba(120, 120, 128, 0.08));
  border-radius: 10px;
  padding: 10px 12px;
}
.pacing-modal__status--good { color: var(--green); }
.pacing-modal__status--warn { color: var(--orange); }
.pacing-modal__status-icon {
  font-size: 18px;
  line-height: 1;
  padding-top: 2px;
}
.pacing-modal__status-text { flex: 1; min-width: 0; }
.pacing-modal__status-title {
  font-size: 14px;
  font-weight: 600;
}
.pacing-modal__status-detail {
  font-size: 12px;
  color: var(--text-tertiary);
  line-height: 1.4;
  margin-top: 2px;
}
.pacing-modal__spinner {
  width: 14px;
  height: 14px;
  border: 2px solid rgba(0, 122, 255, 0.25);
  border-top-color: #007aff;
  border-radius: 50%;
  animation: pacing-spin 0.8s linear infinite;
}
.pacing-modal__spinner.hidden { display: none; }
@keyframes pacing-spin { to { transform: rotate(360deg); } }
.pacing-modal__toggle {
  display: flex;
  align-items: center;
  gap: 12px;
  cursor: pointer;
}
.pacing-modal__toggle-text { flex: 1; min-width: 0; }
.pacing-modal__toggle-label { font-size: 14px; }
.pacing-modal__toggle-sub {
  font-size: 12px;
  color: var(--text-tertiary);
  margin-top: 2px;
  line-height: 1.4;
}
.pacing-modal__accuracy {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
}
.pacing-modal__accuracy-icon {
  font-weight: 700;
}
.pacing-modal__accuracy-label { flex: 1; }
.pacing-modal__accuracy-tier {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.05em;
  padding: 2px 8px;
  border-radius: 999px;
  background: currentColor;
  color: var(--surface, #fff);
}
.pacing-modal__accuracy--good  { color: var(--green); }
.pacing-modal__accuracy--warn  { color: var(--orange); }
.pacing-modal__accuracy--bad   { color: var(--red); }
.pacing-modal__accuracy--muted { color: var(--text-tertiary); }
.pacing-modal__footnote {
  font-size: 12px;
  color: var(--text-tertiary);
  line-height: 1.4;
}
.pacing-modal__algo-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.pacing-modal__algo-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}
.pacing-modal__algo-icon {
  width: 22px;
  flex: 0 0 22px;
  text-align: center;
  font-size: 14px;
  padding-top: 2px;
  color: var(--accent, #0071e3);
}
.pacing-modal__algo-text { flex: 1; min-width: 0; }
.pacing-modal__algo-title {
  font-size: 13px;
  font-weight: 500;
  line-height: 1.35;
}
.pacing-modal__algo-detail {
  font-size: 12px;
  color: var(--text-tertiary);
  line-height: 1.4;
  margin-top: 2px;
}
.pacing-error {
  font-size: 12px;
  color: var(--red);
  margin-top: 4px;
}
.pacing-error.hidden { display: none; }

/* ---- Live scoring card on Ring dashboard ---- */
/* Mirrors iOS LiveScoringCard (Views/Admin/LiveScoringCard.swift):
 * 6 (or up to 8) place rows with colored ribbons, tappable to open the
 * scoring editor. Empty places render as em-dash; populated rows fade
 * in via the animation on insertion. */
.live-scoring-card {
  background: var(--bg-secondary, rgba(120, 120, 128, 0.08));
  border-radius: 14px;
  padding: 12px 14px;
  margin-bottom: 12px;
  cursor: pointer;
  transition: background 0.18s ease, transform 0.12s ease;
}
.live-scoring-card:hover { background: var(--bg-secondary-hover, rgba(120, 120, 128, 0.12)); }
.live-scoring-card:active { transform: scale(0.99); }
.live-scoring-card__header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 6px;
}
.live-scoring-card__title {
  font-size: 15px;
  font-weight: 600;
  flex: 1;
}
.live-scoring-card__badge {
  font-size: 11px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.live-scoring-card__badge--pub   { background: rgba(52, 199, 89, 0.15); color: var(--green); }
.live-scoring-card__badge--draft { background: rgba(255, 149, 0, 0.15); color: var(--orange); }
.live-scoring-card__edit {
  font-size: 13px;
  font-weight: 500;
  color: var(--accent);
  margin-left: auto;
}
.live-scoring-card__rows {
  display: flex;
  flex-direction: column;
}
.live-scoring-card__divider {
  height: 1px;
  background: var(--border);
  opacity: 0.4;
  margin: 0 4px;
}
.live-scoring-card__row {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  padding: 6px 0;
}
/* PlaceRibbon — short colored tag that mirrors iOS PlaceRibbon. All
 * four web ribbon surfaces (.scoring-slot__ribbon, this one,
 * .announcer-rank-ribbon, .ribbon-N) draw from the canonical
 * --ribbon-* tokens in :root so the palette stays in lockstep. */
.live-scoring-card__ribbon {
  width: 6px;
  height: 28px;
  border-radius: 3px;
  background: var(--text-tertiary);
  flex: 0 0 auto;
}
.live-scoring-card__ribbon[data-place="1"] { background: var(--ribbon-1); }
.live-scoring-card__ribbon[data-place="2"] { background: var(--ribbon-2); }
.live-scoring-card__ribbon[data-place="3"] { background: var(--ribbon-3); }
.live-scoring-card__ribbon[data-place="4"] { background: var(--ribbon-4); box-shadow: inset 0 0 0 1px var(--ribbon-4-border); }
.live-scoring-card__ribbon[data-place="5"] { background: var(--ribbon-5); }
.live-scoring-card__ribbon[data-place="6"] { background: var(--ribbon-6); }
.live-scoring-card__place {
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  width: 32px;
  flex: 0 0 auto;
}
.live-scoring-card__place--empty { color: var(--text-tertiary); }
.live-scoring-card__back {
  font-family: ui-monospace, SF Mono, Menlo, monospace;
  font-size: 13px;
  font-weight: 600;
  min-width: 44px;
  flex: 0 0 auto;
}
.live-scoring-card__entry {
  flex: 1;
  min-width: 0;
}
.live-scoring-card__rider {
  font-size: 14px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.live-scoring-card__horse {
  font-size: 12px;
  color: var(--text-secondary);
  margin-top: 1px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.live-scoring-card__empty {
  color: var(--text-tertiary);
  font-size: 14px;
}

/* ---- Broadcast success inline feedback ---- */
/* Green check + label that fades in after a successful send. Mirrors iOS
 * BroadcastView's inline checkmark surface. Auto-hides after 3s in JS. */
.broadcast-success {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 12px;
  padding: 10px 14px;
  background: rgba(52, 199, 89, 0.12);
  border-radius: 10px;
  color: var(--green);
  font-weight: 600;
  font-size: 14px;
  animation: broadcast-success-in 0.28s ease-out both;
}
.broadcast-success__check {
  font-size: 16px;
  line-height: 1;
}
@keyframes broadcast-success-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---- Smoother action-button transitions ---- */
/* The earlier rule covers tap feedback only (transform + opacity 0.12s).
 * Add a longer transition for the layout collapse case — when the state
 * changes from "in-ring 3-button mode" to "lining-up single-button mode",
 * the height + opacity collapse should feel like a spring rather than
 * an instant swap. iOS achieves this via matchedGeometryEffect; on web
 * we can't morph nodes that come and go, but a smooth height/opacity
 * collapse is a defensible parity. */
.admin-actions {
  /* Animate height changes during state transitions so adding/removing
     buttons (e.g. LINE UP collapsing into the status indicator) doesn't
     visually pop. */
  transition: gap 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.admin-actions .action-btn,
.admin-actions .admin-status-indicator {
  /* Add layout properties to the transition so newly-rendered buttons
     fade in rather than slamming into place. The existing :active rule
     keeps its 0.12s tap feedback because it overrides only transform/
     opacity. */
  animation: admin-action-enter 0.32s cubic-bezier(0.34, 1.2, 0.64, 1) both;
}
@keyframes admin-action-enter {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---- Admin Danger Zone ---- */
.admin-danger-zone {
  margin-top: 32px;
  border-top: 1px solid var(--border);
  padding-top: 16px;
}

.admin-danger-zone summary {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-tertiary);
  cursor: pointer;
  padding: 8px 0;
  list-style: none;
  -webkit-tap-highlight-color: transparent;
}

.admin-danger-zone summary::before {
  content: '\u25B8 ';
}

.admin-danger-zone[open] summary::before {
  content: '\u25BE ';
}

.admin-danger-zone .action-btn {
  height: 44px;
  font-size: 14px;
}

/* ---- Announcer Segment ---- */
.announcer-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}

.announcer-owner-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: all 0.15s ease;
}

.announcer-owner-toggle.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}

.announcer-owner-toggle-icon { font-size: 14px; }

.announcer-class-header {
  text-align: center;
  padding: 24px 16px 20px;
  background: var(--bg-secondary);
  border-radius: var(--radius-xl);
  margin: 12px 0 16px;
}

.announcer-class-num {
  font-family: var(--font-display, inherit);
  font-size: 48px;
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--text);
}

.announcer-class-name {
  font-size: 19px;
  font-weight: 500;
  color: var(--text-secondary);
  margin-top: 8px;
}

.announcer-class-badges {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: 12px;
}

.announcer-status-badge {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 4px 10px;
  border-radius: 999px;
}

.announcer-badge-published { color: var(--green); background: var(--green-soft); }
.announcer-badge-draft { color: var(--orange); background: var(--orange-soft); }
.announcer-badge-none { color: var(--text-tertiary); background: var(--bg-tertiary); }

.announcer-rankings-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.announcer-rank-row {
  display: grid;
  grid-template-columns: 4px 36px 60px 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 12px 14px;
  background: var(--surface);
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
}

.announcer-rank-ribbon {
  height: 44px;
  border-radius: 2px;
  background: var(--text-tertiary);
}
.announcer-rank-ribbon[data-place="1"] { background: var(--ribbon-1); }
.announcer-rank-ribbon[data-place="2"] { background: var(--ribbon-2); }
.announcer-rank-ribbon[data-place="3"] { background: var(--ribbon-3); }
.announcer-rank-ribbon[data-place="4"] { background: var(--ribbon-4); box-shadow: inset 0 0 0 1px var(--ribbon-4-border); }
.announcer-rank-ribbon[data-place="5"] { background: var(--ribbon-5); }
.announcer-rank-ribbon[data-place="6"] { background: var(--ribbon-6); }

.announcer-rank-place {
  font-size: 22px;
  font-weight: 800;
  color: var(--text);
  text-align: center;
}
.announcer-rank-row:not([data-place-low]) .announcer-rank-place { color: var(--text-secondary); }
.announcer-rank-row[data-place-low] .announcer-rank-place { color: var(--text); }

/* ---- Admin Show Settings Modal ---- */
.modal-overlay[hidden] { display: none; }
.show-settings-section {
  padding: 1rem 0;
  border-top: 1px solid var(--border);
}
.show-settings-section h3 {
  margin: 0 0 0.5rem;
  font-size: 16px;
  font-weight: 700;
}
.show-settings-section .meta {
  font-size: 14px;
  color: var(--text-secondary);
  margin-bottom: 0.75rem;
}
.show-settings-section .meta.danger {
  color: var(--red, #c62828);
}
.btn-destructive {
  background: var(--red, #c62828);
  color: #fff;
  border: none;
  padding: 0.5rem 1rem;
  border-radius: var(--radius-md, 0.375rem);
  cursor: pointer;
  font-weight: 600;
  font-size: 15px;
}
.btn-destructive:disabled {
  opacity: 0.4;
  pointer-events: none;
}

/* Admin button loading state — used by runAdminButtonAction() in
   app.js for Class Complete / Line Up / Delay / Start / Resume.
   The spinner is intentionally small + low-contrast so the
   "verb…" label still reads as the primary signal. We tighten
   gap + flex layout on the button so the spinner sits next to
   the label without shifting the button width. */
.btn--loading {
  display: inline-flex !important;
  align-items: center;
  justify-content: center;
  gap: 8px;
  cursor: progress !important;
}
.btn--loading .btn-loading-label {
  font-weight: 600;
}
.btn-spinner {
  display: inline-block;
  width: 14px;
  height: 14px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: btn-spinner-rotate 0.7s linear infinite;
  opacity: 0.85;
  flex-shrink: 0;
}
@keyframes btn-spinner-rotate {
  to { transform: rotate(360deg); }
}
/* Disabled buttons normally drop opacity completely; for the loading
   variant we keep them readable since the operator should still be
   able to see what they tapped. */
.btn--loading[disabled],
.btn--loading:disabled {
  opacity: 0.85;
  pointer-events: none;
}

.announcer-rank-back {
  font-size: 20px;
  font-weight: 700;
  font-family: var(--mono, ui-monospace, monospace);
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.announcer-rank-info {
  min-width: 0;
}

.announcer-rank-rider {
  font-size: 19px;
  font-weight: 500;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.announcer-rank-horse {
  font-size: 15px;
  color: var(--text-secondary);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.announcer-rank-owner {
  font-size: 13px;
  color: var(--text-tertiary);
  text-align: right;
  max-width: 130px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (max-width: 500px) {
  .announcer-rank-row { grid-template-columns: 4px 28px 48px 1fr; gap: 10px; padding: 10px; }
  .announcer-rank-owner { grid-column: 3 / -1; text-align: left; max-width: none; margin-top: 4px; }
  .announcer-class-num { font-size: 38px; }
}

/* ---- Broadcast Templates ---- */
.template-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 12px 0 16px;
}

.template-chip {
  padding: 8px 14px;
  border-radius: var(--radius-full);
  font-size: 13px;
  font-weight: 500;
  background: var(--bg-secondary);
  color: var(--text-secondary);
  border: 1px solid var(--border);
  transition: all 0.15s;
}

.template-chip:hover { background: var(--surface-hover); }
.template-chip:active { transform: scale(0.95); }

/* ---- Analytics ---- */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin-bottom: 16px;
}

.stat-card {
  background: var(--surface);
  border-radius: var(--radius-md);
  padding: 14px 8px;
  text-align: center;
  box-shadow: var(--shadow-sm);
}

.stat-value {
  font-size: 22px;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.stat-label {
  font-size: 11px;
  font-weight: 500;
  color: var(--text-tertiary);
  margin-top: 2px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.activity-feed {
  display: flex;
  flex-direction: column;
  border-radius: var(--radius-md);
  overflow: hidden;
  margin-bottom: 20px;
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}

.activity-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 14px;
  border-bottom: 0.5px solid var(--divider);
}

.activity-item:last-child { border-bottom: none; }

.activity-icon {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-full);
  display: flex;
  align-items: center;
  justify-content: center;
}

.activity-icon svg { width: 14px; height: 14px; }

.push-icon {
  background: rgba(0, 122, 255, 0.12);
  color: var(--accent);
}

.audit-icon {
  background: var(--bg-secondary);
  color: var(--text-secondary);
}

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

.activity-title {
  font-size: 14px;
  font-weight: 500;
  color: var(--text);
  text-transform: capitalize;
}

.activity-meta {
  font-size: 12px;
  color: var(--text-tertiary);
  margin-top: 1px;
}

.fail-badge {
  display: inline-block;
  font-size: 11px;
  font-weight: 600;
  color: var(--red);
  background: rgba(255, 59, 48, 0.1);
  padding: 1px 6px;
  border-radius: var(--radius-full);
  margin-left: 4px;
  vertical-align: middle;
}

/* Delivery rate & failure color coding */
.stat-value-good { color: var(--green); }
.stat-value-warn { color: var(--orange); }
.stat-value-bad { color: var(--red); }

/* Queue health pill (appears inline in Notification Queue section label) */
.section-label { display: flex; align-items: center; justify-content: space-between; gap: 8px; }

.queue-health-pill {
  font-size: 11px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: var(--radius-full);
  letter-spacing: 0.02em;
  text-transform: none;
}
.queue-health-pill.queue-healthy { background: var(--green-soft); color: var(--green); }
.queue-health-pill.queue-down { background: var(--red-soft); color: var(--red); }

/* Notification type breakdown (last hour aggregates) */
.notif-type-grid {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 16px;
}

.notif-type-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

.notif-type-icon {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
}

.notif-type-icon svg { width: 18px; height: 18px; }

.notif-type-body { flex: 1; min-width: 0; }

.notif-type-label {
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
}

.notif-type-meta {
  font-size: 12px;
  color: var(--text-tertiary);
  margin-top: 2px;
}

@media (max-width: 500px) {
  .stat-grid[style*="5"] { grid-template-columns: repeat(3, 1fr) !important; }
}

@media (max-width: 380px) {
  .stat-grid { grid-template-columns: repeat(2, 1fr); }
  .stat-grid[style*="5"] { grid-template-columns: repeat(2, 1fr) !important; }
}

/* ---- Toast ---- */
#toast-container {
  position: fixed;
  top: calc(12px + var(--safe-t));
  left: 50%;
  transform: translateX(-50%);
  z-index: 9999;
  width: calc(100% - 32px);
  max-width: 420px;
  pointer-events: none;
}

.toast {
  background: var(--text);
  color: var(--bg);
  border-radius: var(--radius-md);
  padding: 14px 18px;
  font-size: 15px;
  font-weight: 500;
  box-shadow: var(--shadow-xl);
  pointer-events: auto;
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  gap: 12px;
  animation: toastIn 0.35s cubic-bezier(0.21, 1.02, 0.73, 1);
}

.toast.out { animation: toastOut 0.3s ease forwards; }

/* Follow-specific toast (icon + 2-line body + optional Undo) */
.toast-follow { align-items: flex-start; padding: 12px 14px; }
.toast-follow .toast-icon {
  font-size: 22px;
  line-height: 1;
  flex-shrink: 0;
  margin-top: 2px;
}
.toast-follow .toast-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
  min-width: 0;
  line-height: 1.3;
}
.toast-follow .toast-body strong {
  font-weight: 600;
  font-size: 14px;
}
.toast-follow .toast-detail {
  font-size: 12px;
  opacity: 0.75;
}

.toast .undo-btn {
  font-weight: 700;
  color: var(--accent-light);
  white-space: nowrap;
  padding: 6px 12px;
  border-radius: var(--radius-sm);
  margin-left: auto;
  background: transparent;
  border: none;
  cursor: pointer;
  font-size: 14px;
}

.toast .undo-btn:hover { text-decoration: underline; }

@keyframes toastIn {
  from { transform: translateY(-120%); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

@keyframes toastOut {
  from { transform: translateY(0); opacity: 1; }
  to { transform: translateY(-120%); opacity: 0; }
}

/* ---- Notification Alerts ---- */
#notification-container {
  position: fixed;
  top: calc(12px + var(--safe-t));
  left: 50%;
  transform: translateX(-50%);
  z-index: 10000;
  width: calc(100% - 24px);
  max-width: 420px;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.notification-alert {
  background: var(--surface);
  border-radius: 16px;
  padding: 14px 16px;
  box-shadow: 0 4px 24px rgba(0,0,0,0.12);
  display: flex;
  gap: 12px;
  align-items: flex-start;
  pointer-events: auto;
  cursor: pointer;
  animation: notifIn 0.4s cubic-bezier(0.21, 1.02, 0.73, 1);
  transition: opacity 0.3s ease, transform 0.3s ease;
  touch-action: pan-y;
}

.notification-alert.stacked {
  opacity: 0.85;
  transform: scale(0.97);
}

.notification-alert.out {
  animation: notifOut 0.3s ease forwards;
}

.notification-alert .notif-icon {
  width: 36px;
  height: 36px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: 16px;
  font-weight: 700;
  color: #fff;
  background: linear-gradient(135deg, #1B4D72, #2A6A9E);
}

.notification-alert .notif-body {
  flex: 1;
  min-width: 0;
}

.notification-alert .notif-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.notification-alert .notif-title {
  font-weight: 600;
  font-size: 14px;
  color: var(--text);
}

.notification-alert .notif-time {
  font-size: 11px;
  color: var(--text-tertiary);
}

.notification-alert .notif-text {
  font-size: 13px;
  color: var(--text-secondary);
  margin-top: 2px;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

@keyframes notifIn {
  from { transform: translateY(-120%); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

@keyframes notifOut {
  from { transform: translateY(0); opacity: 1; }
  to { transform: translateY(-120%); opacity: 0; }
}

/* ---- Modal ---- */
.overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(0,0,0,0.4);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  animation: overlayIn 0.2s ease;
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}

.overlay.out { animation: overlayOut 0.2s ease forwards; }

@keyframes overlayIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes overlayOut { from { opacity: 1; } to { opacity: 0; } }

.sheet {
  width: 100%;
  max-width: 500px;
  max-height: 85dvh;
  background: var(--bg-secondary);
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: var(--safe-b);
  animation: sheetUp 0.35s cubic-bezier(0.21, 1.02, 0.73, 1);
}

.overlay.out .sheet { animation: sheetDown 0.2s ease forwards; }

@keyframes sheetUp { from { transform: translateY(100%); } to { transform: translateY(0); } }
@keyframes sheetDown { from { transform: translateY(0); } to { transform: translateY(100%); } }

.sheet-handle {
  width: 36px;
  height: 5px;
  border-radius: 3px;
  background: var(--bg-tertiary);
  margin: 10px auto 0;
}

.sheet-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px 12px;
}

.sheet-title {
  font-size: 18px;
  font-weight: 700;
}
.sheet-subtitle {
  font-size: 13px;
  color: var(--text-secondary);
  margin-top: 4px;
  line-height: 1.35;
}

/* Split-class modal: section count segmented buttons + strategy
 * radios. Both controls fit in one sheet body — chosen layout over
 * a two-step wizard so the operator sees their full choice surface
 * at once (parity with the at-a-glance scratch flow). */
.split-field { margin-bottom: 18px; }
.split-field:last-child { margin-bottom: 0; }
.split-field__label {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-tertiary);
  margin-bottom: 8px;
}
.split-sections {
  display: flex;
  gap: 6px;
}
.split-section-btn {
  flex: 1;
  background: var(--surface);
  border: 1px solid var(--border, var(--bg-tertiary));
  border-radius: var(--radius-md);
  padding: 12px 0;
  font-size: 17px;
  font-weight: 700;
  color: var(--text);
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.split-section-btn:active { transform: scale(0.97); }
.split-section-btn.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent, #ffffff);
}

.split-strategy {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border, var(--bg-tertiary));
  cursor: pointer;
  margin-bottom: 6px;
  transition: background 0.12s, border-color 0.12s;
}
.split-strategy:last-child { margin-bottom: 0; }
.split-strategy:hover { background: var(--surface-hover); }
.split-strategy.active {
  background: var(--surface-hover);
  border-color: var(--accent);
}
.split-strategy input[type="radio"] {
  margin-top: 3px;
  flex-shrink: 0;
}
.split-strategy__body {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.split-strategy__title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
}
.split-strategy__sub {
  font-size: 12px;
  color: var(--text-secondary);
  line-height: 1.4;
}

.sheet-close {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--bg-secondary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  color: var(--text-secondary);
}

.sheet-close:active { background: var(--bg-tertiary); }

.sheet-body { padding: 0 20px 20px; }
.sheet-actions { padding: 0 20px 24px; display: flex; flex-direction: column; gap: 8px; }

/* Delay modal options */
.delay-options {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-bottom: 16px;
}

.delay-option {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border-radius: var(--radius-md);
  font-size: 15px;
  font-weight: 500;
  color: var(--text);
  transition: background 0.15s;
}

.delay-option:hover { background: var(--surface-hover); }
.delay-option:active { background: var(--surface-active); }

.delay-option.selected {
  background: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  color: var(--accent);
  font-weight: 600;
}

.delay-option .option-icon {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  flex-shrink: 0;
}

.delay-option.selected .option-icon {
  background: color-mix(in srgb, var(--accent) 15%, transparent);
}

.delay-option .check {
  margin-left: auto;
  opacity: 0;
  color: var(--accent);
  font-weight: 700;
}

.delay-option.selected .check { opacity: 1; }

.duration-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  margin-bottom: 16px;
}

.duration-btn {
  padding: 12px 0;
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-weight: 600;
  text-align: center;
  background: var(--bg-secondary);
  color: var(--text-secondary);
  transition: all 0.15s;
}

.duration-btn:active { transform: scale(0.94); }

.duration-btn.selected {
  background: var(--accent);
  color: #ffffff;
}

/* ---- Back Button ---- */
.back-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 17px;
  font-weight: 500;
  color: var(--accent);
  padding: 8px 0;
  margin-bottom: 4px;
}

.back-btn:hover { text-decoration: underline; }

.back-btn svg {
  width: 20px;
  height: 20px;
}

/* ---- Detail shared (Person / Horse pages still use this label:value pattern) ---- */
.detail-header {
  padding: 12px 0 20px;
}

.detail-rows {
  background: var(--surface);
  border-radius: var(--radius-lg);
  overflow: hidden;
  margin-bottom: 18px;
  box-shadow: var(--shadow-sm);
}

.detail-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 13px 16px;
  border-bottom: 0.5px solid var(--divider);
  font-size: 15px;
}

.detail-row:last-child { border-bottom: none; }
.detail-row .dl { color: var(--text-secondary); font-weight: 500; }
.detail-row .dv { font-weight: 600; }

/* ---- Class Detail ---- */
.detail-hero {
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: 18px 18px 16px;
  margin-bottom: 14px;
  box-shadow: var(--shadow-sm);
}

.detail-hero-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}

.detail-num {
  font-size: 13px;
  font-weight: 700;
  color: var(--accent);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.detail-follow-btn {
  padding: 6px 14px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-full);
  background: var(--surface);
  color: var(--text);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.detail-follow-btn:hover { background: var(--surface-hover); }
.detail-follow-btn:active { background: var(--surface-active); }

.detail-follow-btn.is-followed {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}

.detail-follow-btn.is-followed:hover { filter: brightness(1.05); }

.detail-name {
  font-family: var(--font-display);
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.2;
  margin: 2px 0 12px;
}

.detail-badges {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.detail-when {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 0.5px solid var(--divider);
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
}

.detail-when svg {
  color: var(--text-secondary);
  flex-shrink: 0;
}

.detail-delay {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 6px;
  font-size: 13px;
  color: var(--orange);
  font-weight: 600;
}

.detail-delay svg {
  color: var(--orange);
  flex-shrink: 0;
}

/* Meta grid — two-column definition list for the less-important fields */
.detail-meta {
  background: var(--surface);
  border-radius: var(--radius-lg);
  overflow: hidden;
  margin-bottom: 14px;
  box-shadow: var(--shadow-sm);
}

.detail-meta-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 0.5px solid var(--divider);
  font-size: 15px;
}

.detail-meta-row:last-child { border-bottom: none; }
.detail-meta-row .dl { color: var(--text-secondary); font-weight: 500; }
.detail-meta-row .dv { font-weight: 600; text-align: right; min-width: 0; }

.detail-meta-value-with-star {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Notes — left-bordered callout so it reads as pinned commentary rather
   than a generic card */
.detail-notes {
  background: var(--orange-soft);
  border-left: 3px solid var(--orange);
  border-radius: var(--radius-md);
  padding: 12px 14px;
  margin-bottom: 18px;
}

.detail-notes-label {
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--orange);
  margin-bottom: 4px;
}

.detail-notes p {
  margin: 0;
  font-size: 15px;
  line-height: 1.45;
  color: var(--text);
}

/* Section labels on detail pages get a right-aligned count chip */
.section-count {
  font-family: var(--font);
  font-size: 13px;
  font-weight: 500;
  color: var(--text-tertiary);
  letter-spacing: 0;
  text-transform: none;
}

.championship-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px;
  border-radius: var(--radius-full);
  background: linear-gradient(135deg, #FFD700 0%, #F0B400 100%);
  color: #5B4500;
  font-size: 12px;
  font-weight: 700;
}

/* Results */
.result-list {
  padding: 4px 16px;
}

.result-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 0.5px solid var(--divider);
}

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

.result-place {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.result-ribbon {
  width: 4px;
  height: 36px;
  border-radius: 2px;
  flex-shrink: 0;
}

.result-back {
  font-family: var(--mono);
  font-weight: 600;
  font-size: 12px;
  color: var(--text-tertiary);
  margin-right: 6px;
  font-variant-numeric: tabular-nums;
}

.result-score {
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  text-align: right;
  min-width: 56px;
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}

.ribbon-1 { background: var(--ribbon-1); }
.ribbon-2 { background: var(--ribbon-2); }
.ribbon-3 { background: var(--ribbon-3); }
.ribbon-4 { background: var(--ribbon-4); box-shadow: inset 0 0 0 1px var(--ribbon-4-border); }
.ribbon-5 { background: var(--ribbon-5); }
.ribbon-6 { background: var(--ribbon-6); }
.ribbon-default { background: var(--ribbon-default); }

.result-num {
  width: 24px;
  font-size: 18px;
  font-weight: 700;
  text-align: center;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.result-num.dim { color: var(--text-secondary); }

.result-info { flex: 1; min-width: 0; }
.result-horse { font-size: 15px; font-weight: 600; }
.result-entry { font-size: 13px; color: var(--text-secondary); margin-top: 1px; }
.result-trainer { font-size: 13px; color: var(--text-tertiary); }

/* ---- Version Label ---- */
/* ---- Toggle Switch ---- */
.notif-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.toggle-switch {
  position: relative;
  display: inline-block;
  width: 51px;
  height: 31px;
  flex-shrink: 0;
}

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

.toggle-slider {
  position: absolute;
  cursor: pointer;
  top: 0; left: 0; right: 0; bottom: 0;
  background-color: var(--bg-tertiary);
  border-radius: 31px;
  transition: background-color 0.2s;
}

.toggle-slider::before {
  content: "";
  position: absolute;
  height: 27px;
  width: 27px;
  left: 2px;
  bottom: 2px;
  background-color: white;
  border-radius: 50%;
  transition: transform 0.2s;
  box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}

.toggle-switch input:checked + .toggle-slider {
  background-color: #34c759;
}

.toggle-switch input:checked + .toggle-slider::before {
  transform: translateX(20px);
}

/* ---- Loading ---- */
.loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 64px 0;
  gap: 12px;
}

.spinner {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 2.5px solid var(--border-strong);
  border-top-color: var(--accent);
  animation: spin 0.7s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

.loading-text {
  font-size: 14px;
  color: var(--text-tertiary);
}

/* ---- Skeleton ---- */
.skeleton {
  background: linear-gradient(90deg, var(--bg-secondary) 25%, var(--bg-tertiary) 50%, var(--bg-secondary) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.5s ease-in-out infinite;
  border-radius: var(--radius-sm);
}

@keyframes shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ---- Utility ---- */
.hidden { display: none !important; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

/* ---- Responsive ---- */
@media (max-width: 360px) {
  .page-title { font-size: 28px; }
  .hero .number { font-size: 40px; }
  .action-btn { height: 50px; font-size: 15px; }
}

@media (min-width: 600px) {
  .sheet {
    border-radius: var(--radius-xl);
    margin-bottom: 20px;
    max-height: 80dvh;
  }

  #toast-container { max-width: 420px; }
}

/* ============================================================
   Page-scope breakpoints — only two.
   - 900px:  sidebar visible, drawer machinery off, content gets a
             max-width treatment.
   - 1280px: roomier canvas; the Live tab gets a heavier hero
             column (kept as a final fluid step, not a layout
             rewrite).
   Everything else is container-driven (Phase 3+) or fluid via
   clamp() / auto-fit minmax().
   ============================================================ */

@media (min-width: 900px) {
  /* Make space for the fixed sidebar — every other body child gets
     pushed right by the sidebar's width. */
  body { padding-left: var(--sidebar-w); }

  /* Sidebar pinned to the left edge of the viewport, full-height,
     always visible. position: fixed avoids the CSS Grid `grid-row:
     1 / -1` gotcha (which doesn't span implicit rows) and survives
     page scroll without effort. Reset the compact-drawer's opacity
     and visibility so the sidebar isn't invisible at desktop. */
  .primary-nav {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: var(--sidebar-w);
    max-width: var(--sidebar-w);
    transform: none;
    opacity: 1;
    visibility: visible;
    transition: none;
  }
  /* Top app bar is redundant at desktop — the sidebar already carries
     the brand link (top) and the profile chip (footer), so a separate
     top strip would just be empty whitespace above the canvas. Hide
     it entirely; the canvas gets its own .view padding-top below. */
  .top-app-bar {
    display: none;
  }
  /* Strip sticks at viewport top once scrolled, since the top bar is
     no longer there to clear above it. */
  .live-status-strip {
    top: 0;
  }
  /* Re-show the sidebar header at desktop. */
  .primary-nav__brand {
    display: inline-flex;
  }
  /* Sidebar profile chip — bottom-anchored via margin-top: auto so
     it parks against the bottom edge regardless of how many nav
     items are above it. Mirrors the Notion / Linear / Vercel
     pattern of "user pill at the foot of the rail." */
  .primary-nav__profile {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: auto;
    padding: 12px 16px;
    border-top: 1px solid var(--border);
    text-decoration: none;
    color: var(--text-secondary);
    transition: background 0.12s ease, color 0.12s ease;
    min-width: 0;
  }
  .primary-nav__profile[hidden] { display: none; }
  .primary-nav__profile:hover {
    background: var(--bg-secondary);
    color: var(--text);
    text-decoration: none;
  }
  .primary-nav__profile-avatar {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--blue-bg);
    color: var(--accent);
    font-weight: 700;
    font-size: 13px;
    letter-spacing: -0.02em;
  }
  .primary-nav__profile-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.2;
  }
  .primary-nav__profile-name {
    font-size: 14px;
    font-weight: 500;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .primary-nav__profile-email {
    font-size: 12px;
    color: var(--text-tertiary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .primary-nav__profile-email:empty { display: none; }

  /* Sidebar sign-in entry — same bottom-anchored slot as the profile
     chip, shown only when the visitor has no session. Mirrors the
     visual weight of the profile chip so swapping between the two
     doesn't shift the layout above. */
  .primary-nav__signin {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: auto;
    padding: 12px 16px;
    border-top: 1px solid var(--border);
    text-decoration: none;
    color: var(--text);
    transition: background 0.12s ease, color 0.12s ease;
    min-width: 0;
  }
  .primary-nav__signin[hidden] { display: none; }
  .primary-nav__signin:hover {
    background: var(--bg-secondary);
    color: var(--accent);
    text-decoration: none;
  }
  .primary-nav__signin-icon {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--blue-bg);
    color: var(--accent);
  }
  .primary-nav__signin-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.2;
  }
  .primary-nav__signin-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
  }
  .primary-nav__signin-sub {
    font-size: 12px;
    color: var(--text-tertiary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* Canvas top padding so the page title doesn't abut the viewport
     top — at compact widths the top app bar provided this visual
     breathing room; at desktop the canvas needs it explicitly. */
  .view {
    padding-top: 16px;
  }

  /* Weather alert banner is `position: fixed` (it floats above all
     content as a critical overlay) so without an explicit `left`
     override it would draw on top of the sidebar at desktop. Anchor
     it to the canvas only. The store banner is now in regular block
     flow inside body's padding-left, so it doesn't need this. */
  .weather-alert-banner {
    left: var(--sidebar-w);
  }

  /* Hamburger and the in-bar home shortcut are redundant once the
     sidebar is visible — the sidebar's brand link is the same
     destination, in the upper-left of the visible chrome. */
  .top-app-bar__menu,
  .top-app-bar__home {
    display: none;
  }

  /* Drawer backdrop never used at desktop. */
  .nav-backdrop { display: none !important; }
  body[data-drawer="open"] .nav-backdrop { display: none !important; }

  /* Content area — give views room to breathe. */
  .view {
    max-width: 100%;
    padding: 0 32px 32px;
  }
}

@media (min-width: 1280px) {
  .view { padding: 0 48px 40px; }
}

/* ============================================================
   Live tab — container-driven layout.
   Live's hero+sidebar split responds to the .view canvas width, not
   the viewport. So an iPad-portrait phone-width-but-tall canvas
   ALSO gets two-column when it's wide enough — not just desktop.
   .view declares `container-type: inline-size; container-name: view;`
   above; these queries reference that container by name.
   ============================================================ */

@container view (min-width: 44rem) {
  .live-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 28px;
    align-items: start;
  }
  .live-hero .hero {
    min-height: 300px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 36px;
  }
  .live-hero .hero .number { font-size: 72px; }
  .live-hero .hero .name   { font-size: 24px; }
  .live-hero .hero .timer  { font-size: 36px; }
  .live-sidebar .section-label:first-child { margin-top: 0; }
}

@container view (min-width: 64rem) {
  .live-layout {
    grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
    gap: 40px;
  }
  .live-hero .hero {
    min-height: 360px;
    padding: 44px;
  }
  .live-hero .hero .number { font-size: 96px; }
  .live-hero .hero .name   { font-size: 28px; }
  .live-hero .hero .label  { font-size: 14px; }
  .live-hero .hero .timer  { font-size: 40px; margin-top: 28px; }
  .live-sidebar .class-row       { padding: 14px 16px; }
  .live-sidebar .announcement-row { padding: 12px 0; }
}

@media (display-mode: standalone) {
  body { padding-top: var(--safe-t); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

@media print {
  .top-app-bar, .primary-nav, .nav-backdrop,
  #toast-container, .overlay { display: none !important; }
  #app { padding-bottom: 0; }
}

/* ================================================================
   New components: session header, announcements, filter toggle, sponsors
   ================================================================ */

.session-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 18px;
  margin: -4px -16px 10px;
  background: var(--surface);
  border-radius: var(--radius-md);
  font-weight: 600;
  font-size: 15px;
  color: var(--text-secondary);
  box-shadow: var(--shadow-sm);
}

.session-header svg {
  width: 16px;
  height: 16px;
  opacity: 0.6;
}

.announcement-row {
  padding: 12px 16px;
  margin: 0 -16px;
  border-bottom: 0.5px solid var(--divider);
}

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

.announcement-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-tertiary);
  margin-bottom: 4px;
}

.announcement-icon {
  font-size: 14px;
}

.announcement-msg {
  font-size: 15px;
  line-height: 1.5;
  color: var(--text);
}

.filter-mode-toggle {
  display: flex;
  gap: 0;
  margin-bottom: 14px;
  background: var(--bg-tertiary);
  border-radius: var(--radius-md);
  padding: 3px;
}

.filter-mode-btn {
  flex: 1;
  border: none;
  background: none;
  font-family: var(--font);
  font-size: 14px;
  font-weight: 600;
  padding: 9px 16px;
  border-radius: calc(var(--radius-md) - 3px);
  color: var(--text-secondary);
  cursor: pointer;
  transition: all 0.2s ease;
}

.filter-mode-btn.active {
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-sm);
}

:root {
  --gold: #B8860B;
}

.role-badge { display:inline-block; font-size:12px; font-weight:600; padding:2px 8px; border-radius:10px; margin-right:4px; }
.role-rider { background:#E3F2FD; color:#1565C0; }
.role-trainer { background:#E8F5E9; color:#2E7D32; }
.role-owner { background:#FFF3E0; color:#E65100; }

/* ---- Entry List (Class Detail) ---- */
.entry-list {
  padding: 4px 16px;
}

.entry-row {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 12px 0;
  border-bottom: 0.5px solid var(--divider);
}

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

/* Scratched entry row. Visual treatment mirrors HSO's class-results
   scratch row: strikethrough through the back# / horse / rider names
   plus a muted opacity so the eye registers "not running" at a glance
   without losing the information. Used in the "Scratched" section
   under a class's results / entries list. */
.entry-row--scratched .entry-back,
.entry-row--scratched .entry-horse,
.entry-row--scratched .entry-rider,
.entry-row--scratched .entry-owner,
.entry-row--scratched .entry-trainer {
  text-decoration: line-through;
}
.entry-row--scratched {
  opacity: 0.6;
}

.entry-back {
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 600;
  color: var(--accent);
  min-width: 36px;
  text-align: center;
  flex-shrink: 0;
  padding-top: 1px;
  font-variant-numeric: tabular-nums;
}

.entry-info { flex: 1; min-width: 0; }

.entry-horse {
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
}

.entry-horse a { color: var(--text); }
.entry-horse a:hover { color: var(--accent); text-decoration: underline; }

.entry-rider {
  font-size: 14px;
  color: var(--text-secondary);
  margin-top: 2px;
}

.entry-rider a { color: var(--text-secondary); }
.entry-rider a:hover { color: var(--accent); text-decoration: underline; }

.entry-owner,
.entry-trainer {
  font-size: 13px;
  color: var(--text-tertiary);
  margin-top: 1px;
}

.entry-owner a,
.entry-trainer a { color: var(--text-tertiary); }
.entry-owner a:hover,
.entry-trainer a:hover { color: var(--accent); text-decoration: underline; }

.entry-horse,
.entry-rider {
  display: flex;
  align-items: center;
  gap: 2px;
}

.entry-horse .star-btn,
.entry-rider .star-btn {
  width: 32px;
  height: 32px;
  font-size: 16px;
}

.entry-info a,
.result-info a,
.class-meta a {
  display: inline-block;
  padding: 4px 8px;
  margin: -4px -2px;
  border-radius: var(--radius-sm);
  color: var(--blue);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  cursor: pointer;
}

.entry-info a:active,
.result-info a:active,
.class-meta a:active {
  background: var(--blue-bg);
}

/* ============================================================
   Class detail — Results podium + Entries grid
   Two opt-in containers used only on the class-detail page.
   Person/Horse pages keep using `.result-list` / `.entry-list`
   (the compact list look) so this redesign is scoped tightly.
   ============================================================ */

/* Section header label — keeps the page's existing 20px display
   typography but lays out the optional icon + text inline so we
   can prefix the Results section with a trophy without breaking
   the visual rhythm of the other section headers on the page. */
.section-label-text {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.section-label-text > svg {
  color: var(--accent);
  flex-shrink: 0;
  margin-bottom: -2px;
}

/* The Results podium uses standard horse-show ribbon accents
   (blue / red / yellow / white / pink / green) on the left edge
   and medal of each row for places 1–6. 7th and beyond fall into
   a neutral "other" tier. Each row is its own card so the list
   reads as a stack of pinned ribbons, not a single dense table. */
.results-podium {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 14px;
}

.results-podium .result-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 16px;
  padding: 16px 18px;
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  transition: transform 0.15s ease, box-shadow 0.2s ease, border-color 0.2s ease;
  position: relative;
  overflow: hidden;
}

.results-podium .result-row::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 4px;
  background: var(--divider);
  border-radius: 0;
}

/* Standard US horse-show ribbon accent on each result row's left
 * edge. The first-place card gets a touch more padding so the blue
 * ribbon row reads as the headline result. Other places stay
 * uniform, the way ribbons in a real horse-show results book do. */
.results-podium .result-row--p1 { padding: 22px 22px; }
.results-podium .result-row--p1::before { background: var(--ribbon-1); }
.results-podium .result-row--p2::before { background: var(--ribbon-2); }
.results-podium .result-row--p3::before { background: var(--ribbon-3); }
.results-podium .result-row--p4::before {
  background: var(--ribbon-4);
  box-shadow: inset 0 0 0 1px var(--ribbon-4-border);
}
.results-podium .result-row--p5::before { background: var(--ribbon-5); }
.results-podium .result-row--p6::before { background: var(--ribbon-6); }

.results-podium .result-row--other {
  padding: 14px 18px;
}

/* Medal — circular numbered badge filled with the corresponding
 * ribbon color so the listing reads like a row of pinned ribbons. */
.results-podium .result-medal {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  font-size: 18px;
  font-weight: 800;
  color: #fff;
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12), inset 0 -2px 0 rgba(0, 0, 0, 0.10);
}
.results-podium .result-row--p1 .result-medal {
  width: 56px;
  height: 56px;
  font-size: 24px;
  background: var(--ribbon-1);
}
.results-podium .result-row--p2 .result-medal { background: var(--ribbon-2); }
/* Yellow + white medals need a dark numeral so the place stays
 * readable; white also needs an inset border so it's visible. */
.results-podium .result-row--p3 .result-medal {
  background: var(--ribbon-3);
  color: var(--text);
  text-shadow: 0 1px 0 rgba(255,255,255,0.4);
}
.results-podium .result-row--p4 .result-medal {
  background: var(--ribbon-4);
  color: var(--text);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12), inset 0 0 0 1px var(--ribbon-4-border);
}
.results-podium .result-row--p5 .result-medal { background: var(--ribbon-5); }
.results-podium .result-row--p6 .result-medal { background: var(--ribbon-6); }
.results-podium .result-row--other .result-medal {
  width: 38px;
  height: 38px;
  font-size: 15px;
  color: var(--text-secondary);
  background: var(--surface-active);
  box-shadow: inset 0 0 0 1px var(--divider);
}

/* Result info — primary horse, secondary rider, tertiary trainer */
.results-podium .result-info {
  flex: 1;
  min-width: 0;
}
.results-podium .result-horse {
  font-size: 16px;
  font-weight: 700;
  line-height: 1.25;
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.results-podium .result-row--p1 .result-horse {
  font-size: 19px;
  letter-spacing: -0.01em;
}
.results-podium .result-back {
  display: inline-flex;
  align-items: center;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  color: var(--text-secondary);
  background: var(--surface-active);
  padding: 2px 8px;
  border-radius: 999px;
  margin-right: 0;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}
.results-podium .result-entry {
  font-size: 14px;
  font-weight: 500;
  color: var(--text-secondary);
  margin-top: 3px;
}
.results-podium .result-trainer {
  font-size: 12px;
  color: var(--text-tertiary);
  margin-top: 2px;
}

/* Score chip — tabular numerals, subtle bg, anchored right */
.results-podium .result-score {
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  background: var(--surface-active);
  padding: 7px 12px;
  border-radius: 999px;
  text-align: right;
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  align-self: center;
}
.results-podium .result-row--p1 .result-score {
  background: rgba(212, 175, 55, 0.18);
  color: #6E5A0A;
}
@media (prefers-color-scheme: dark) {
  .results-podium .result-row--p1 .result-score {
    background: rgba(255, 215, 0, 0.16);
    color: #FFD86A;
  }
}

/* Entries grid — responsive auto-fill cards. Mobile stays single
   column for thumb scrolling; tablet/desktop fans out into a
   2–3 column grid so an 80-entry class doesn't read as an
   endless ribbon. */
.entry-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
  margin-bottom: 14px;
}
@media (min-width: 720px) {
  .entry-grid { grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); gap: 10px; }
}

.entry-grid .entry-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  border-bottom: 1px solid var(--divider); /* override base */
  transition: transform 0.15s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
.entry-grid .entry-row:hover {
  border-color: var(--accent-faint);
  box-shadow: var(--shadow-md);
}
.entry-grid .entry-row:active {
  transform: scale(0.985);
}

/* Back number becomes a circular avatar — strong tint, easy
   scan target. Replaces the old "small accent text in a column"
   look which competed with horse name for attention. */
.entry-grid .entry-back {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  min-width: 42px;
  border-radius: 50%;
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 800;
  color: var(--accent);
  background: var(--accent-faint);
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  padding-top: 0;
  text-align: center;
  flex-shrink: 0;
}

.entry-grid .entry-info {
  flex: 1;
  min-width: 0;
  padding-top: 1px;
}
.entry-grid .entry-horse {
  font-size: 15px;
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.005em;
}
.entry-grid .entry-rider {
  font-size: 13.5px;
  color: var(--text-secondary);
  margin-top: 3px;
  font-weight: 500;
}
.entry-grid .entry-owner,
.entry-grid .entry-trainer {
  font-size: 12px;
  color: var(--text-tertiary);
  margin-top: 1px;
}

/* ============================================================
   Person + Horse detail — entity hero, stats, connections, class rows.
   Built to mirror iOS ParticipantDetailView's information density
   without losing the web-native polish set by the class-detail
   redesign above.
   ============================================================ */

.entity-hero {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  padding: 18px 18px 14px;
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  margin-bottom: 12px;
}
.entity-hero__avatar {
  flex-shrink: 0;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.entity-hero__avatar--person {
  background: linear-gradient(135deg, var(--accent-faint), rgba(91, 163, 217, 0.05));
  color: var(--accent);
}
.entity-hero__avatar--horse {
  background: linear-gradient(135deg, rgba(52, 199, 89, 0.18), rgba(52, 199, 89, 0.04));
  color: #2E7D32;
}
.entity-hero__avatar--horse svg {
  width: 28px;
  height: 28px;
  stroke-width: 1.8;
}
@media (prefers-color-scheme: dark) {
  .entity-hero__avatar--horse { color: #4CAF50; }
}
.entity-hero__main {
  flex: 1;
  min-width: 0;
}
.entity-hero__name {
  font-family: var(--font-display, var(--font));
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--text);
  margin: 0 0 6px;
  word-break: break-word;
}
.entity-hero__meta {
  font-size: 14px;
  color: var(--text-secondary);
  font-weight: 500;
  margin-bottom: 8px;
}
.entity-hero__location {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 14px;
  color: var(--text-secondary);
  margin-bottom: 10px;
}
.entity-hero__location > svg {
  color: var(--text-tertiary);
  flex-shrink: 0;
}
.entity-hero__roles {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.entity-hero__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 4px;
}
.entity-hero__chip {
  display: inline-flex;
  align-items: center;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  background: var(--surface-active);
  padding: 4px 10px;
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
}
.entity-hero__chip--back {
  font-family: var(--mono);
  color: var(--accent);
  background: var(--accent-faint);
  letter-spacing: -0.01em;
}

/* Role chips (replaces .role-badge for the new entity-hero header) */
.role-chip {
  display: inline-flex;
  align-items: center;
  font-size: 11px;
  font-weight: 700;
  padding: 3px 9px;
  border-radius: 999px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.role-chip--rider   { background: rgba(33, 150, 243, 0.15); color: #1565C0; }
.role-chip--driver  { background: rgba(33, 150, 243, 0.15); color: #1565C0; }
.role-chip--trainer { background: rgba(76, 175, 80, 0.15);  color: #2E7D32; }
.role-chip--owner   { background: rgba(255, 152, 0, 0.18);  color: #E65100; }
@media (prefers-color-scheme: dark) {
  .role-chip--rider, .role-chip--driver { background: rgba(91, 163, 217, 0.22); color: #82B6E1; }
  .role-chip--trainer { background: rgba(76, 175, 80, 0.22); color: #81C784; }
  .role-chip--owner   { background: rgba(255, 152, 0, 0.22); color: #FFB74D; }
}

/* Stat strip — at-a-glance counts under the hero, color-coded by
   role. Each stat is a self-contained chip. */
.entity-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 8px;
  margin-bottom: 16px;
}
.entity-stat {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
.entity-stat > svg { flex-shrink: 0; }
.entity-stat__num {
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  margin-left: 2px;
}
.entity-stat__label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  text-transform: lowercase;
  letter-spacing: 0.02em;
}
.entity-stat--rider   > svg { color: #1565C0; }
.entity-stat--trainer > svg { color: #2E7D32; }
.entity-stat--owner   > svg { color: #E65100; }
.entity-stat--rider   { border-left: 3px solid rgba(33, 150, 243, 0.6); }
.entity-stat--trainer { border-left: 3px solid rgba(76, 175, 80, 0.6); }
.entity-stat--owner   { border-left: 3px solid rgba(255, 152, 0, 0.6); }

/* Connection cards (horse detail) — trainer / owner / rider, each
   role color-coded. Single column on mobile, fans out to a grid
   on tablet+. */
.connection-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
  margin-bottom: 14px;
}
@media (min-width: 720px) {
  .connection-grid { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 10px; }
}
.connection-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
.connection-card:hover {
  border-color: var(--accent-faint);
  box-shadow: var(--shadow-md);
}
.connection-card:active { transform: scale(0.985); }
.connection-card__icon {
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.connection-card__icon > svg { width: 18px; height: 18px; }
.connection-card--trainer .connection-card__icon { background: rgba(76, 175, 80, 0.15); color: #2E7D32; }
.connection-card--owner   .connection-card__icon { background: rgba(255, 152, 0, 0.18); color: #E65100; }
.connection-card--rider   .connection-card__icon { background: rgba(33, 150, 243, 0.15); color: #1565C0; }
@media (prefers-color-scheme: dark) {
  .connection-card--trainer .connection-card__icon { background: rgba(76, 175, 80, 0.22); color: #81C784; }
  .connection-card--owner   .connection-card__icon { background: rgba(255, 152, 0, 0.22); color: #FFB74D; }
  .connection-card--rider   .connection-card__icon { background: rgba(91, 163, 217, 0.22); color: #82B6E1; }
}
.connection-card__body { flex: 1; min-width: 0; }
.connection-card__role {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  margin-bottom: 2px;
}
.connection-card__name {
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.25;
}
.connection-card__right {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
  color: var(--text-tertiary);
}

/* Entity class list — used by Person Riding/Training/Owns and
   Horse Classes. Each row is its own card; nested rows under a
   horse-group header indent visibly without losing card identity. */
.entity-class-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 14px;
}
.entity-class-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
.entity-class-row:hover {
  border-color: var(--accent-faint);
  box-shadow: var(--shadow-md);
}
.entity-class-row:active { transform: scale(0.99); }
.entity-class-row--indent {
  margin-left: 18px;
  background: var(--surface-hover, var(--surface));
}
.entity-class-row__num {
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--accent);
  background: var(--accent-faint);
  padding: 4px 10px;
  border-radius: 8px;
  min-width: 44px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.entity-class-row__body { min-width: 0; }
.entity-class-row__name {
  font-size: 14.5px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.entity-class-row__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  margin-top: 4px;
}
.entity-class-row__link {
  font-size: 12.5px;
  color: var(--blue);
  text-decoration: none;
  cursor: pointer;
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.entity-class-row__link:hover { text-decoration: underline; }
.entity-class-row__day {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  background: var(--surface-active);
  padding: 2px 7px;
  border-radius: 999px;
}
.entity-class-row__right {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}

/* Horse-group header — sits above the indented classes a person is
   training/owning that horse in. Bold horse name with back # chip
   and a follow star + chevron right. */
.horse-group {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  margin-top: 4px;
  background: linear-gradient(180deg, var(--surface-active), var(--surface));
  border-radius: var(--radius-md, 10px);
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.2s ease;
}
.horse-group:hover { box-shadow: var(--shadow-sm); }
.horse-group__back {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 800;
  color: var(--accent);
  background: var(--accent-faint);
  padding: 3px 8px;
  border-radius: 999px;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.horse-group__name {
  font-size: 14.5px;
  font-weight: 700;
  color: var(--text);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.horse-group__right {
  display: flex;
  align-items: center;
  gap: 4px;
  color: var(--text-tertiary);
  flex-shrink: 0;
}

/* Result-row — when used inside .results-podium on Person/Horse pages,
   include a small class number chip in the horse line. */
.results-podium .result-class-num {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  color: var(--text-secondary);
  background: var(--surface-active);
  padding: 2px 7px;
  border-radius: 6px;
  margin-right: 2px;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
.results-podium .result-entry-sep {
  color: var(--text-tertiary);
}

/* ---- Search Suggestions ---- */
.search-suggestions {
  margin-bottom: 8px;
}

.suggestion-group {
  margin-bottom: 16px;
}

.suggestion-title {
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
  padding: 0 4px 8px;
}

.suggestion-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.suggestion-chip {
  padding: 8px 16px;
  border-radius: var(--radius-full);
  font-size: 14px;
  font-weight: 500;
  background: var(--surface);
  color: var(--text-secondary);
  border: 1.5px solid var(--border-strong);
  box-shadow: var(--shadow-sm);
  transition: all 0.15s;
  cursor: pointer;
}

.suggestion-chip:hover { background: var(--surface-hover); }
.suggestion-chip:active { transform: scale(0.94); }

.link-btn {
  background: none;
  border: none;
  color: var(--blue);
  font-size: 13px;
  cursor: pointer;
  padding: 4px 8px;
  -webkit-tap-highlight-color: transparent;
}

/* ---- Search Scope Tabs ---- */
.scope-tabs {
  display: flex;
  gap: 8px;
  margin-bottom: 16px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.scope-tabs::-webkit-scrollbar { display: none; }

.scope-tab {
  padding: 8px 16px;
  border-radius: 20px;
  border: 1px solid var(--border);
  background: none;
  color: var(--text-secondary);
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: all 0.15s;
}

.scope-tab.active {
  background: var(--blue);
  color: #fff;
  border-color: var(--blue);
}

/* ============================================================================
   Live Header Title
   ============================================================================ */

.live-header-title__plain {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.live-header-title__name { font-weight: 600; }
.live-header-title__venue {
  font-size: 0.875rem;
  color: var(--color-text-secondary, #666);
}

/* Sticky connectivity banner — fills the top of the viewport when the
   network is down or the data we're showing may be out of date. Debounced
   by the connectivity monitor in app.js so it doesn't flicker. */
.connectivity-banner {
  position: sticky;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1500;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.4rem 1rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: #fff;
  text-align: center;
  line-height: 1.25;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}
.connectivity-banner[hidden] { display: none; }
.connectivity-banner.offline { background: #d97706; }   /* amber-600 */
.connectivity-banner.stale   { background: #b45309; }   /* amber-700, slightly darker */
.connectivity-banner .dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: currentColor;
  opacity: 0.9;
}
.connectivity-banner .meta {
  font-weight: 500;
  opacity: 0.85;
  margin-left: 0.25rem;
}

/* ================================================================
   Weather chip (Phase 4 — Live view header)
   ================================================================ */
.live-header-title__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.live-header-title__logo {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 8px;
  object-fit: contain;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.10);
  display: flex;
  align-items: center;
  justify-content: center;
}
.live-header-title__logo--placeholder {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--text-secondary, rgba(255, 255, 255, 0.7));
}

.live-header-title__text {
  flex: 1 1 auto;
  min-width: 0;
}

.live-header-title__chip {
  flex: 0 0 auto;
}

.weather-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.12);
  cursor: pointer;
  color: inherit;
  font: inherit;
  transition: transform 120ms ease, background 120ms ease;
}

.weather-chip:hover,
.weather-chip:focus-visible {
  transform: translateY(-1px);
  background: rgba(255, 255, 255, 0.14);
  outline: none;
}

.weather-chip:active {
  transform: translateY(0);
}

.weather-chip__icon {
  font-size: 18px;
  line-height: 1;
}

.weather-chip__temp {
  font-size: 14px;
  font-weight: 600;
}

.weather-chip__label {
  font-size: 12px;
  opacity: 0.75;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 120px;
}

@media (max-width: 480px) {
  .weather-chip__label {
    display: none; /* space tight on narrow viewports */
  }
}

/* ================================================================
   Weather modal (Phase 4)
   ================================================================ */
.weather-modal-card {
  max-width: 520px;
}

.weather-modal__hero {
  display: flex;
  align-items: center;
  gap: 20px;
  padding-bottom: 16px;
}

.weather-modal__hero-icon {
  font-size: 64px;
  line-height: 1;
}

.weather-modal__temp {
  font-size: 48px;
  font-weight: 600;
  line-height: 1.05;
}

.weather-modal__condition {
  font-size: 18px;
  opacity: 0.75;
  margin-top: 4px;
}

.weather-modal__metrics {
  display: flex;
  gap: 24px;
  padding: 12px 0 20px;
  border-bottom: 1px solid var(--border, rgba(255,255,255,0.08));
}

.weather-modal__metric-label {
  font-size: 12px;
  opacity: 0.65;
}

.weather-modal__metric-value {
  font-size: 15px;
  font-weight: 500;
  margin-top: 2px;
}

.weather-modal__section-title {
  font-size: 16px;
  font-weight: 600;
  opacity: 0.75;
  margin: 16px 0 8px;
}

.weather-modal__venue-name {
  font-weight: 600;
}

.weather-modal__venue-address {
  font-size: 14px;
  opacity: 0.7;
  margin-top: 2px;
}

.weather-modal__map {
  width: 100%;
  height: 200px;
  border-radius: 12px;
  overflow: hidden;
  margin-top: 10px;
  background: rgba(255,255,255,0.04);
}

.weather-modal__directions {
  display: block;
  text-align: center;
  margin-top: 12px;
  text-decoration: none;
}

.weather-modal__forecast-strip {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  padding-bottom: 4px;
  -webkit-overflow-scrolling: touch;
}

.weather-modal__forecast-cell {
  flex: 0 0 auto;
  min-width: 64px;
  padding: 10px 8px;
  border-radius: 12px;
  background: rgba(255,255,255,0.06);
  text-align: center;
}

.weather-modal__forecast-day {
  font-size: 12px;
  opacity: 0.7;
}

.weather-modal__forecast-day--today {
  font-weight: 700;
  opacity: 1;
}

/* Small numeric M/D helper beneath the weekday so a multi-week show
   doesn't leave "Wed" ambiguous. */
.weather-modal__forecast-date {
  font-size: 10px;
  opacity: 0.55;
  margin-top: 1px;
}

.weather-modal__forecast-icon {
  font-size: 22px;
  margin: 4px 0;
}

.weather-modal__forecast-hi {
  font-size: 15px;
  font-weight: 600;
}

.weather-modal__forecast-lo {
  font-size: 12px;
  opacity: 0.65;
}

.weather-modal__forecast-precip {
  font-size: 11px;
  color: #4aa3ff;
  margin-top: 2px;
}

.weather-modal__attribution {
  font-size: 12px;
  opacity: 0.65;
  border-top: 1px solid var(--border, rgba(255,255,255,0.08));
  padding-top: 12px;
  margin-top: 16px;
  text-align: center;
}

.weather-modal__attribution a {
  color: inherit;
  text-decoration: underline;
}

/* ================================================================
   Schedule forecast row + placeholder (Phase 4)
   ================================================================ */
.schedule-forecast-slot {
  margin: 8px 16px 0;
}

.schedule-forecast-row {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px 12px;
  border: none;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.06);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: inherit;
  font: inherit;
  cursor: pointer;
  text-align: left;
  transition: background 120ms ease, transform 120ms ease;
}

.schedule-forecast-row:hover,
.schedule-forecast-row:focus-visible {
  background: rgba(255, 255, 255, 0.1);
  outline: none;
  transform: translateY(-1px);
}

.schedule-forecast-row__icon {
  font-size: 22px;
}

.schedule-forecast-row__main {
  display: flex;
  flex-direction: column;
  gap: 1px;
  flex: 1 1 auto;
  min-width: 0;
}

.schedule-forecast-row__label {
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.schedule-forecast-row__temps {
  font-size: 12px;
  opacity: 0.7;
}

.schedule-forecast-row__precip {
  font-size: 11px;
  color: #4aa3ff;
  font-weight: 500;
}

.schedule-forecast-row__chevron {
  font-size: 18px;
  opacity: 0.5;
}

.schedule-forecast-placeholder {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.04);
  opacity: 0.75;
}

.schedule-forecast-placeholder__icon {
  font-size: 20px;
  opacity: 0.7;
}

.schedule-forecast-placeholder__text {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.schedule-forecast-placeholder__title {
  font-size: 14px;
  font-weight: 500;
}

.schedule-forecast-placeholder__subtitle {
  font-size: 12px;
  opacity: 0.7;
}

/* Loading + unavailable variants of the weather chip */
.weather-chip--loading,
.weather-chip--unavailable {
  cursor: default;
  opacity: 0.75;
}

.weather-chip--loading .weather-chip__icon {
  animation: weather-chip-pulse 1.4s ease-in-out infinite;
}

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

/* ================================================================
   Weather alert banner (Phase 5)
   ================================================================ */
.weather-alert-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 900;
  padding: 0;
  font-family: inherit;
}

/* Shift content down when the alert banner is visible so it doesn't
   cover the UI. The banner is position: fixed at top with z-index 900,
   so it overlays whatever sits under it. Top app bar and #app each
   gain a small offset; the sidebar (≥900px) is unaffected because the
   banner is full-width and the sidebar is below it in z-order. */
body.has-weather-alert #top-app-bar { padding-top: calc(8px + 28px); }
body.has-weather-alert #app { padding-top: 28px; }

.weather-alert-banner[hidden] { display: none; }

.weather-alert-banner.sev-moderate { background: #d97706; color: white; }
.weather-alert-banner.sev-severe   { background: #c23214; color: white; }
.weather-alert-banner.sev-extreme  { background: #b91c1c; color: white; }

.weather-alert-banner__button {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 12px;
  background: transparent;
  border: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  text-align: left;
}

.weather-alert-banner__button:hover,
.weather-alert-banner__button:focus-visible {
  background: rgba(0,0,0,0.12);
  outline: none;
}

.weather-alert-banner__icon { font-size: 14px; }
.weather-alert-banner__title { font-size: 13px; font-weight: 600; flex: 1 1 auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.weather-alert-banner__more { font-size: 12px; opacity: 0.85; }
.weather-alert-banner__chevron { font-size: 16px; opacity: 0.7; }

/* ================================================================
   Broadcasted-alert full-screen dialog (Phase 5)
   ================================================================ */
.weather-alert-dialog {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
}

.weather-alert-dialog[hidden] { display: none; }

.weather-alert-dialog.sev-moderate { background: #d97706; }
.weather-alert-dialog.sev-severe   { background: #c23214; }
.weather-alert-dialog.sev-extreme  { background: #b91c1c; }

.weather-alert-dialog__content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: 32px;
  max-width: 480px;
  text-align: center;
}

.weather-alert-dialog__icon { font-size: 72px; line-height: 1; }

.weather-alert-dialog__label {
  font-size: 13px;
  letter-spacing: 2px;
  opacity: 0.85;
  font-weight: 600;
}

.weather-alert-dialog__title {
  font-size: 28px;
  font-weight: 700;
  margin: 0;
  line-height: 1.2;
}

.weather-alert-dialog__summary {
  font-size: 16px;
  opacity: 0.9;
  line-height: 1.4;
  margin: 0;
}

.weather-alert-dialog__source {
  font-size: 12px;
  opacity: 0.7;
  margin: 0;
}

.weather-alert-dialog__ack {
  margin-top: 12px;
  padding: 12px 32px;
  background: white;
  color: #c23214;
  border: none;
  border-radius: 999px;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
}

.weather-alert-dialog.sev-moderate .weather-alert-dialog__ack { color: #d97706; }
.weather-alert-dialog.sev-extreme  .weather-alert-dialog__ack { color: #b91c1c; }

/* ================================================================
   Admin weather alert card (Phase 6)
   ================================================================ */
.admin-alert-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 12px 16px 8px;
  padding: 12px;
  background: var(--surface);
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.06);
}

.admin-alert-row {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 10px;
  border-radius: 10px;
  border: 1px solid var(--border);
}

.admin-alert-row.sev-moderate { border-left: 4px solid #d97706; }
.admin-alert-row.sev-severe   { border-left: 4px solid #c23214; }
.admin-alert-row.sev-extreme  { border-left: 4px solid #b91c1c; }

.admin-alert-row__header {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}

.admin-alert-row__icon { font-size: 20px; line-height: 1; }

.admin-alert-row__meta { flex: 1 1 auto; min-width: 0; }

.admin-alert-row__title {
  font-weight: 600;
  font-size: 15px;
  line-height: 1.3;
}

.admin-alert-row__badges {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 4px;
  font-size: 12px;
  color: var(--text-secondary);
}

.admin-alert-row__sev-badge {
  padding: 2px 6px;
  border-radius: 999px;
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.5px;
}
.admin-alert-row.sev-moderate .admin-alert-row__sev-badge { background: rgba(217,119,6,0.15);  color: #d97706; }
.admin-alert-row.sev-severe   .admin-alert-row__sev-badge { background: rgba(194,50,20,0.15);  color: #c23214; }
.admin-alert-row.sev-extreme  .admin-alert-row__sev-badge { background: rgba(185,28,28,0.15);  color: #b91c1c; }

.admin-alert-row__actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.admin-alert-row__broadcast,
.admin-alert-row__dismiss {
  padding: 8px 14px;
  border-radius: 8px;
  border: none;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.admin-alert-row__broadcast { background: var(--accent); color: white; }
.admin-alert-row__broadcast:hover:not(:disabled) { background: var(--accent-hover); }
.admin-alert-row__broadcast:disabled { opacity: 0.5; cursor: wait; }

.admin-alert-row__dismiss { background: var(--bg-tertiary); color: var(--text); }
.admin-alert-row__dismiss:hover:not(:disabled) { background: var(--surface-hover); }
.admin-alert-row__dismiss:disabled { opacity: 0.5; cursor: not-allowed; }

.admin-alert-row__clear {
  padding: 8px 14px;
  border-radius: 8px;
  border: 1px solid #c23214;
  background: transparent;
  color: #c23214;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.admin-alert-row__clear:hover:not(:disabled) { background: rgba(194,50,20,0.08); }
.admin-alert-row__clear:disabled { opacity: 0.5; cursor: not-allowed; }

.admin-alert-row__broadcasted {
  color: #15803d;
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.5px;
}

/* ================================================================
   Event row (Info tab social events — Calendar-app inspired)
   ================================================================ */
.event-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
}

.event-row__date {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--accent) 15%, transparent);
  color: var(--accent);
  flex-shrink: 0;
}

.event-row__wkday {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.5px;
}

.event-row__day {
  font-size: 20px;
  font-weight: 600;
  line-height: 1;
  margin-top: 2px;
}

.event-row__body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.event-row__title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.25;
}

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

.event-row__add {
  font-size: 16px;
  color: var(--accent);
  flex-shrink: 0;
  padding-left: 4px;
}

.event-row:hover { background: var(--surface-hover); }

/* Social events — day-grouped calendar with descriptions (Info tab) */
.social-events-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
.schedule-add-btn {
  font-size: 13px;
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
  padding: 4px 10px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-radius: 999px;
  white-space: nowrap;
}
.schedule-add-btn:hover { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.social-events-title__actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.social-events-edit-btn {
  background: transparent;
  cursor: pointer;
  font-family: inherit;
}
.social-events { display: flex; flex-direction: column; gap: 18px; }
.event-day__header {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--accent);
  padding: 0 12px 4px;
}
.event-day__list { display: flex; flex-direction: column; }
.event-row--grouped { align-items: flex-start; }
.event-row--grouped + .event-row--grouped {
  border-top: 1px solid var(--border, rgba(128, 128, 128, 0.15));
}
.event-row--grouped .event-row__add { align-self: center; text-decoration: none; }
.event-row__desc {
  font-size: 13px;
  color: var(--text-secondary);
  line-height: 1.4;
  margin-top: 4px;
}
.event-badge {
  display: inline-block;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 15%, transparent);
  padding: 1px 6px;
  border-radius: 6px;
  margin-left: 6px;
  vertical-align: middle;
}

/* ================================================================
   Venue card (Phase 7) — used on Info tab + weather modal
   ================================================================ */

.venue-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 16px;
  background: var(--surface);
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.04);
}

.venue-card__name {
  font-size: 17px;
  font-weight: 600;
  color: var(--text);
}

.venue-card__address {
  font-size: 14px;
  color: var(--text-secondary);
  line-height: 1.4;
}

.venue-card__map {
  width: 100%;
  height: 220px;
  border-radius: 12px;
  overflow: hidden;
  background: var(--bg-secondary);
}

/* Look Around overlay CSS removed — feature is iOS-only; web relies on
   the Directions button opening Apple Maps for street-level view. */

/* Shared action row for Directions + Share on the venue card (Info tab)
   and the weather modal. Mobile / narrow layout: stack vertically with
   full-width buttons. Wide (≥520px): inline. Top margin separates from
   the map / card content above. */
.venue-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 14px;
}

.venue-actions .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 10px 16px;
  border-radius: 10px;
  font-weight: 600;
  font-size: 15px;
  line-height: 1.2;
  min-height: 42px;
  white-space: nowrap;
}

.venue-actions__primary { background: var(--accent); color: white; }
.venue-actions__primary:hover { background: var(--accent-hover); }

.venue-actions__secondary { background: var(--bg-tertiary); color: var(--text); border: none; }
.venue-actions__secondary:hover { background: var(--surface-hover); }

@media (min-width: 520px) {
  .venue-actions { flex-direction: row; }
  .venue-actions .btn { flex: 1 1 0; }
}

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

.venue-card__meta-label {
  font-weight: 600;
  color: var(--text);
  margin-right: 6px;
}

/* ----------------------------------------------------------------------
 * Schedule timezone banner
 *
 * Sticky pill above the schedule list disclosing the show's timezone.
 * Individual class rows below render bare wall-clock times; the banner
 * carries the zone disclosure so the dense list stays uncluttered.
 * iOS counterpart: ShowTimeBanner.swift.
 * --------------------------------------------------------------------*/

.schedule-tz-banner {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0.75rem;
  margin: 0.5rem auto 0.75rem;
  background: var(--surface-tinted, rgba(0, 0, 0, 0.06));
  border-radius: 9999px;
  font-size: 0.85rem;
  color: var(--text-secondary, rgba(0, 0, 0, 0.65));
  width: fit-content;
}

.schedule-tz-banner > span:first-child {
  font-size: 0.95rem;
  line-height: 1;
}

@media (prefers-color-scheme: dark) {
  .schedule-tz-banner {
    background: rgba(255, 255, 255, 0.08);
  }
}

/* ---- Admin tool modals (Announcer / Broadcast / Analytics) ---- */
/* Mount one .modal-overlay per tool, reuse generic modal chrome. Each
 * holds the existing renderAdmin{Announcer,Broadcast}Segment /
 * renderAnalyticsContent output verbatim — the modal is just a
 * container. Broadcast disables click-outside (see spec §5) so a
 * draft message isn't lost. */
.admin-tool-modal__card {
  max-width: 720px;
  width: 100%;
  max-height: 88vh;
  display: flex;
  flex-direction: column;
}
.admin-tool-modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px 12px;
  border-bottom: 1px solid var(--border);
}
.admin-tool-modal__header h2 {
  margin: 0;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.admin-tool-modal__close {
  background: transparent;
  border: 0;
  font-size: 22px;
  line-height: 1;
  color: var(--text-tertiary);
  cursor: pointer;
  padding: 4px 8px;
  margin: -4px -8px 0 0;
  border-radius: 8px;
}
.admin-tool-modal__close:hover {
  background: var(--bg-secondary, rgba(120,120,128,.08));
  color: var(--text-primary);
}
.admin-tool-modal__body {
  flex: 1;
  overflow-y: auto;
  padding: 16px 20px 20px;
  -webkit-overflow-scrolling: touch;
}
@media (max-width: 600px) {
  .admin-tool-modal__card { max-width: 100%; max-height: 92vh; }
}

/* ---- Manage Announcements list (admin tool) ---- */
.manage-ann-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
/* Unified Announcements modal — composer at top, list below.
   Mirrors iOS AnnouncementsView from Tools → Announcements. */
.announcements-modal__composer {
  margin-bottom: 4px;
}
.announcements-modal__compose-cta {
  margin: 0;
}
.announcements-modal__compose-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 12px;
}
.announcements-modal__divider {
  height: 1px;
  background: var(--border);
  margin: 16px 0 12px;
}
.announcements-modal__empty {
  text-align: center;
  padding: 24px 16px 12px;
  color: var(--text-secondary);
}
.announcements-modal__empty-icon {
  font-size: 28px;
  display: block;
  margin-bottom: 8px;
}
.announcements-modal__empty h3 {
  font-size: 15px;
  margin: 0 0 6px;
  color: var(--text-primary);
}
.announcements-modal__empty p {
  font-size: 13px;
  margin: 0;
  line-height: 1.45;
}

.announcements-modal__loading {
  padding: 24px 16px;
  text-align: center;
}

/* Edit drill-down: replaces the modal body with a focused form for
   one announcement. Header has a Back button + title; the form
   itself reuses the composer styles. */
.announcements-modal__edit-header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}
.announcements-modal__edit-header .btn-text {
  padding: 4px 8px;
  font-size: 14px;
  font-weight: 600;
  color: var(--accent, #0071e3);
  background: transparent;
  border: 0;
  cursor: pointer;
  border-radius: 6px;
}
.announcements-modal__edit-header .btn-text:hover {
  background: rgba(0, 113, 227, 0.08);
}
.announcements-modal__edit-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
}
.announcements-modal__edit-meta {
  font-size: 12px;
  color: var(--text-secondary);
  margin-bottom: 12px;
}

.manage-ann-row__badge {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text-secondary);
  background: rgba(120, 120, 128, 0.18);
}
.manage-ann-row--archived .manage-ann-row__message {
  color: var(--text-secondary);
  text-decoration: line-through;
  text-decoration-color: rgba(120, 120, 128, 0.5);
}
.manage-ann-row__actions .btn-text-warn {
  color: #b06000;
  padding: 4px 10px;
  font-size: 13px;
  font-weight: 600;
  background: transparent;
  border: 0;
  cursor: pointer;
  border-radius: 6px;
}
.manage-ann-row__actions .btn-text-warn:hover {
  background: rgba(176, 96, 0, 0.1);
}

/* Auto-archive countdown pill on admin rows. Spectator surfaces
   (LiveNow announcement banner / push notifications) don't render
   expiresAt at all — the timer is an admin-only signal. */
.manage-ann-row__expiry {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-left: 8px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: #b06000;
  background: rgba(176, 96, 0, 0.12);
}
.manage-ann-row__expiry-icon {
  font-size: 11px;
  line-height: 1;
}

/* Expiry picker form-row inside the announcements modal. The custom
   datetime input slides in below the select when "Custom time" is
   chosen. */
.announcements-modal__expiry {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 12px;
}
.announcements-modal__expiry-custom {
  margin-top: 4px;
}
.announcements-modal__expiry-custom.hidden {
  display: none;
}

.manage-ann-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
}
.manage-ann-row:last-child { border-bottom: 0; }
.manage-ann-row__body { flex: 1; min-width: 0; }
.manage-ann-row__message {
  font-size: 14px;
  color: var(--text-primary);
  line-height: 1.45;
  word-wrap: break-word;
}
.manage-ann-row__meta {
  margin-top: 4px;
  font-size: 12px;
  color: var(--text-secondary);
}
.manage-ann-row__actions {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex-shrink: 0;
}
.manage-ann-row__actions .btn-text,
.manage-ann-row__actions .btn-text-danger {
  padding: 4px 10px;
  font-size: 13px;
  font-weight: 600;
  background: transparent;
  border: 0;
  cursor: pointer;
  border-radius: 6px;
}
.manage-ann-row__actions .btn-text { color: var(--accent); }
.manage-ann-row__actions .btn-text-danger { color: #dc3c3c; }
.manage-ann-row__actions .btn-text:hover { background: rgba(120, 120, 128, 0.10); }
.manage-ann-row__actions .btn-text-danger:hover { background: rgba(220, 60, 60, 0.10); }
.manage-announcements-empty {
  text-align: center;
  padding: 32px 12px;
}
.manage-announcements-empty__icon {
  font-size: 40px;
  display: block;
  margin-bottom: 8px;
}
.manage-announcements-empty h3 {
  margin: 4px 0;
  font-size: 17px;
  color: var(--text-primary);
}
.manage-announcements-empty p {
  margin: 0;
  font-size: 13px;
  color: var(--text-secondary);
}

/* ---- Admin Undo confirm popover ---- */
/* Anchored under the toolbar Undo button. Single destructive action.
 * Click-outside + Esc dismiss. Mirrors iOS Menu-with-destructive-item
 * pattern. */
.admin-undo-confirm {
  position: fixed;
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18);
  padding: 6px;
  z-index: 100;
  min-width: 220px;
  animation: admin-undo-confirm-in 0.18s ease-out both;
}
@keyframes admin-undo-confirm-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
.admin-undo-confirm__action {
  display: block;
  width: 100%;
  background: transparent;
  border: 0;
  padding: 10px 14px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  color: var(--red, #ff3b30);
  text-align: left;
  cursor: pointer;
}
.admin-undo-confirm__action:hover {
  background: rgba(255, 59, 48, 0.10);
}

/* Post-magic-link passkey enrollment prompt
   (passkey-prompt.js — see spec docs/specs/2026-04-26-passkey-onboarding-design.md §8). */
.passkey-prompt-card {
  max-width: 420px;
}
.passkey-prompt-icon {
  font-size: 48px;
  line-height: 1;
}
/* Tertiary link-style "Don't ask again" affordance. The first two
   buttons reuse .btn / .btn-primary; this one is muted on purpose so
   it doesn't compete with the primary action. */
.btn-text {
  background: transparent;
  border: none;
  color: var(--text-secondary, #666);
  padding: 8px;
  cursor: pointer;
  font: inherit;
  font-size: 13px;
}
.btn-text:hover {
  color: var(--text, #000);
}

/* ---- Info tab hero ---- */
/* Logo to the left of show name + date range. Matches the rhythm of
   the Live header so the show identity reads consistently everywhere. */
.info-hero {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 16px;
  padding: 20px 0 12px;
}
.info-hero__logo {
  flex: 0 0 auto;
  width: 72px;
  height: 72px;
  border-radius: 14px;
  object-fit: contain;
  background: var(--bg-secondary, rgba(120,120,128,.08));
  border: 1px solid var(--border, rgba(120,120,128,.18));
  display: flex;
  align-items: center;
  justify-content: center;
}
.info-hero__logo--placeholder {
  font-size: 24px;
  font-weight: 800;
  letter-spacing: 0.04em;
  color: var(--text-secondary, #555);
}
.info-hero__text {
  flex: 1 1 auto;
  min-width: 0;
}
.info-hero__title {
  margin: 0;
  padding: 0;
  /* Fluid clamp — scales the show name with the canvas. One step
     below .page-title so it sits visually beneath the hero icon
     without dominating. */
  font-size: var(--step-3);
  line-height: 1.15;
}
.info-hero__subtitle {
  margin: 0;
  padding: 4px 0 0;
}

/* ============================================================================
 * Demo mode chrome treatment
 * ============================================================================
 *
 * Applied to <body> by updateDemoBanner() in app.js whenever the active
 * show is the shared demo template or a personal sandbox. The goal: make
 * the chrome visually distinct so operators always know they're in
 * practice mode and any action is safe — without blocking, overlaying,
 * or hiding any actual UI. Pairs with the solid-orange .demo-chrome-
 * banner pinned to the top of the page (see public/css/demo-badge.css).
 *
 * No "modal" / floating treatments here. Edges + accents only. */

body.is-demo-mode .top-app-bar {
  /* Bumped from the default 1px var(--border) hairline. Reads as the
     primary "you're inside the demo" signal once you've scrolled past
     the chrome banner — the orange accent stays visible on every tab. */
  border-bottom: 3px solid #ff8c00;
}

body.is-demo-mode .primary-nav {
  /* Drawer / side nav picks up the same accent so the brand color is
     unambiguous on wider layouts where the sidebar replaces the top
     hamburger menu. */
  border-top: 3px solid #ff8c00;
  border-right-color: #ff8c00;
}

body.is-demo-mode .top-app-bar__brand,
body.is-demo-mode .primary-nav__brand {
  /* Subtle — just shifts the brand text orange so users see the color
     even when the borders are scrolled offscreen on long content. */
  color: #ff8c00;
}

body.is-demo-mode .top-app-bar__brand-name {
  color: #ff8c00;
}

/* Active primary-nav item border accent so the selected tab also
   carries the orange signal on wider layouts. */
body.is-demo-mode .primary-nav__item.is-active {
  box-shadow: inset 3px 0 0 #ff8c00;
}

/* ============================================================================
 * HSO Sync modal — mode picker (Initial / During / Final)
 * ============================================================================ */

.hso-sync-mode {
  margin-bottom: 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.hso-sync-mode__label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted, #888);
}
.hso-sync-mode__seggroup {
  display: inline-flex;
  border: 1px solid var(--divider, #d0d0d0);
  border-radius: 10px;
  overflow: hidden;
  width: fit-content;
}
.hso-sync-mode__seg {
  padding: 8px 16px;
  background: transparent;
  border: none;
  border-right: 1px solid var(--divider, #d0d0d0);
  font-size: 14px;
  font-weight: 600;
  color: var(--text-muted, #666);
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}
.hso-sync-mode__seg:last-child { border-right: none; }
.hso-sync-mode__seg:hover { background: rgba(0, 0, 0, 0.04); }
.hso-sync-mode__seg--active {
  background: var(--accent, #2563eb);
  color: white;
}
.hso-sync-mode__help {
  font-size: 12px;
  color: var(--text-muted, #666);
  line-height: 1.4;
  max-width: 540px;
}

/* ---- Multi-ring tab strip (Live tab) ---- */
.ring-tabs {
  display: flex;
  gap: 6px;
  margin: 0 auto 12px;
  padding: 4px;
  background: rgba(0, 0, 0, 0.04);
  border-radius: 12px;
  max-width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.ring-tab {
  flex: 1 1 0;
  min-height: 44px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  padding: 6px 12px;
  background: transparent;
  border: none;
  border-radius: 8px;
  color: inherit;
  cursor: pointer;
  font: inherit;
  transition: background 0.12s ease, transform 0.12s ease;
}
.ring-tab:hover { background: rgba(0, 0, 0, 0.04); }
.ring-tab.is-active {
  background: var(--bg, #fff);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08), 0 0 0 0.5px rgba(0, 0, 0, 0.06);
}
.ring-tab__name {
  font-size: 14px;
  font-weight: 600;
  line-height: 1.1;
}
.ring-tab__hint {
  font-size: 11px;
  font-weight: 500;
  opacity: 0.6;
  line-height: 1.1;
}
@media (prefers-color-scheme: dark) {
  .ring-tabs { background: rgba(255, 255, 255, 0.06); }
  .ring-tab:hover { background: rgba(255, 255, 255, 0.06); }
  .ring-tab.is-active {
    background: rgba(255, 255, 255, 0.10);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 0 0 0.5px rgba(255, 255, 255, 0.08);
  }
}

/* ---- Multi-ring chip on class rows (Schedule + entity lists) ---- */
.ring-chip {
  display: inline-block;
  vertical-align: middle;
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
  padding: 3px 7px;
  margin-right: 2px;
  border-radius: 999px;
  color: var(--text-secondary, #4b5563);
  background: rgba(0, 0, 0, 0.05);
  border: 0.5px solid rgba(0, 0, 0, 0.08);
}
@media (prefers-color-scheme: dark) {
  .ring-chip {
    color: rgba(255, 255, 255, 0.7);
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.12);
  }
}

/* ---- Schedule: ring section header for multi-ring shows ---- */
.schedule-ring-header {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-secondary, #4b5563);
  margin: 18px 4px 6px;
  padding: 4px 0;
  border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}
@media (prefers-color-scheme: dark) {
  .schedule-ring-header {
    color: rgba(255, 255, 255, 0.7);
    border-bottom-color: rgba(255, 255, 255, 0.08);
  }
}
.schedule-ring-header:first-of-type {
  margin-top: 4px;
}

/* ---- Admin tool modal: Edit Show Details ---- */
.edit-show { display: flex; flex-direction: column; gap: 14px; }
.edit-show__group { display: flex; flex-direction: column; gap: 10px; padding-bottom: 4px; border-bottom: 1px solid var(--border, rgba(255,255,255,0.1)); }
.edit-show__label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--text-secondary, #aaa); }
.edit-show__label--half { flex: 1; }
.edit-show__label input,
.edit-show__label textarea {
  font: inherit; padding: 8px 10px; border-radius: 8px;
  border: 1px solid var(--border, rgba(255,255,255,0.12));
  background: var(--surface, #1a1a1a); color: var(--text, #eee);
  width: 100%;
}
.edit-show__label small { color: var(--text-tertiary, #888); font-size: 11px; }
.edit-show__row { display: flex; gap: 10px; }
.edit-show__fieldset {
  border: 1px solid var(--border, rgba(255,255,255,0.1));
  border-radius: 8px; padding: 10px 12px; display: flex; flex-direction: column; gap: 10px;
}
.edit-show__fieldset legend { font-size: 12px; color: var(--text-tertiary, #888); padding: 0 4px; }
.edit-show__error { color: #ff6b6b; font-size: 13px; }
.edit-show__error.hidden { display: none; }
.edit-show__actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 6px; }
#edit-show-info-json { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; min-height: 220px; }

/* ============================================================================
   Schedule Disclaimer ("ShowRing is unofficial")
   ============================================================================
   Quiet footer pinned beneath every schedule list (Live, Schedule) plus
   the "How ShowRing Works" explainer surfaces (modal + Info-tab card).
   Mirrors the iOS ScheduleInfoSheet and tvOS DisclaimerStrip. Copy lives
   in app.js so it stays in sync with the iOS surfaces.
*/

.schedule-disclaimer-footer {
  padding: 24px 20px 32px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  max-width: 720px;
}

.schedule-disclaimer-text {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-secondary);
}

.schedule-disclaimer-link {
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent);
  cursor: pointer;
  text-decoration: none;
}

.schedule-disclaimer-link:hover {
  text-decoration: underline;
}

/* Info-tab compact card — short disclaimer + accent link that opens
   the full explainer modal. Same visual rhythm as the other info-group
   cards (surface bg, rounded corners, shadow) so it sits naturally in
   the grid without screaming for attention. */
.schedule-info-tab-card {
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: 14px 18px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}

.schedule-info-tab-card__text {
  margin: 0;
  font-size: 14px;
  line-height: 1.45;
  color: var(--text-secondary);
}

.schedule-info-tab-card__link {
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  color: var(--accent);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.schedule-info-tab-card__link:hover {
  text-decoration: underline;
}

.schedule-info-tab-card__icon {
  font-size: 16px;
  line-height: 1;
}

/* Info-tab card — full explainer rendered in the existing .info-group
   chrome but with a body that holds prose (paragraphs + subheadings +
   bullets) instead of an .info-list. */
.schedule-info-card__body {
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: 16px 20px;
  color: var(--text);
  font-size: 15px;
  line-height: 1.5;
}

.schedule-info-card__body p {
  margin: 0 0 12px;
}

.schedule-info-card__body p:last-child {
  margin-bottom: 0;
}

.schedule-info-card__body h4 {
  margin: 16px 0 6px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
}

.schedule-info-card__body ul {
  margin: 0;
  padding-left: 20px;
}

.schedule-info-card__body li {
  margin-bottom: 4px;
}

.schedule-info-card__body li:last-child {
  margin-bottom: 0;
}

/* Modal body — same content as the info-tab card, rendered in the
   existing .modal-card chrome. */
.schedule-info-body {
  font-size: 15px;
  line-height: 1.5;
}

.schedule-info-body p {
  margin: 0 0 12px;
}

.schedule-info-body p:last-child {
  margin-bottom: 0;
}

.schedule-info-body h3 {
  margin: 16px 0 6px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
}

.schedule-info-body ul {
  margin: 0;
  padding-left: 20px;
}

.schedule-info-body li {
  margin-bottom: 4px;
}

.schedule-info-body li:last-child {
  margin-bottom: 0;
}

/* ===========================================================
 * Live leaderboard — Jumper / Hunter Derby / per-round Hunter
 * / Equitation. Rendered into #live-leaderboard-mount on the
 * class detail page when scoring_format != SADDLEBRED_SUBJECTIVE.
 * =========================================================== */
.leaderboard {
  margin: 20px 0;
  padding: 16px;
  background: var(--surface, #fff);
  border-radius: 12px;
  border: 1px solid var(--border, rgba(0,0,0,0.08));
  box-shadow: 0 1px 3px rgba(0,0,0,0.04);
}
/* Compact variant on the Live tab, sitting right under the in-ring hero. */
.leaderboard--compact { margin: 12px 0 0; }
/* Collapse the mount entirely when there's no leaderboard to show
   (non-leaderboard formats / nothing in play) so the hero has no gap. */
#live-hero-leaderboard-mount:empty { display: none; }
.leaderboard__viewfull {
  display: block;
  text-align: center;
  margin-top: 10px;
  padding: 8px 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent, #1e6fff);
  text-decoration: none;
}
.leaderboard__viewfull:hover { text-decoration: underline; }
/* Owner order-of-go editor (modal). Up/down reordering, touch-friendly. */
.order-editor__hint { font-size: 13px; color: var(--text-secondary); margin: 0 0 12px; }
.order-editor { display: flex; flex-direction: column; gap: 6px; }
.order-editor__row {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px;
  background: var(--surface-secondary, #f7f8fa);
  border-radius: 10px;
}
.order-editor__num { font-size: 13px; color: var(--text-tertiary); width: 24px; }
.order-editor__back { font-weight: 700; font-size: 14px; width: 44px; }
.order-editor__info {
  flex: 1; font-size: 14px; color: var(--text-secondary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.order-editor__moves { display: flex; gap: 4px; }
.order-editor__move {
  width: 36px; height: 36px; border-radius: 8px;
  border: 1px solid var(--border, rgba(0,0,0,0.12));
  background: var(--surface, #fff); color: var(--text-primary, #111);
  font-size: 12px; cursor: pointer;
}
.order-editor__move:disabled { opacity: 0.35; cursor: default; }
.leaderboard__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}
.leaderboard__title {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-secondary);
}
.leaderboard__fmt {
  font-size: 12px;
  padding: 2px 10px;
  border-radius: 10px;
  background: var(--surface-secondary, #f0f4ff);
  color: var(--accent, #1e6fff);
  font-weight: 600;
}

/* On-course card — most prominent element, sits at the top. */
.leaderboard-oncourse {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas:
    "label   label"
    "back    horse"
    "back    rider";
  gap: 2px 14px;
  align-items: center;
  padding: 14px;
  margin-bottom: 14px;
  background: linear-gradient(135deg, #fff8e1 0%, #fff4d6 100%);
  border-radius: 10px;
  border: 2px solid #f5b800;
}
.leaderboard-oncourse__label {
  grid-area: label;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: #946800;
  margin-bottom: 6px;
}
.leaderboard-oncourse__back {
  grid-area: back;
  font-size: 36px;
  font-weight: 800;
  line-height: 1;
  color: #6a4a00;
}
.leaderboard-oncourse__horse {
  grid-area: horse;
  font-size: 18px;
  font-weight: 700;
  color: var(--text);
}
.leaderboard-oncourse__rider {
  grid-area: rider;
  font-size: 14px;
  color: var(--text-secondary);
}

/* Order of go strip — horizontal scrolling list of upcoming entries. */
.leaderboard-order {
  margin-bottom: 14px;
}
.leaderboard-order__label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
  margin-bottom: 6px;
}
.leaderboard-order__list {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  padding-bottom: 4px;
  -webkit-overflow-scrolling: touch;
}
.leaderboard-order__chip {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background: var(--surface-secondary, #f7f7f8);
  border-radius: 16px;
  font-size: 12px;
  white-space: nowrap;
  flex-shrink: 0;
  border: 1px solid transparent;
}
.leaderboard-order__chip.is-current {
  background: #fff8e1;
  border-color: #f5b800;
  font-weight: 600;
}
.leaderboard-order__num {
  color: var(--text-tertiary);
  font-size: 11px;
}
.leaderboard-order__back {
  font-weight: 700;
}
.leaderboard-order__horse {
  color: var(--text-secondary);
}

/* Standings list — sorted by score / faults per format. */
.leaderboard-standings {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.leaderboard-standings--empty {
  padding: 20px;
  text-align: center;
  color: var(--text-tertiary);
  font-style: italic;
}
.leaderboard-row {
  display: grid;
  grid-template-columns: 32px 48px 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: var(--surface, #fff);
  border-radius: 8px;
  border: 1px solid var(--border, rgba(0,0,0,0.06));
}
.leaderboard-row--place-1 {
  background: linear-gradient(135deg, #fffbe6 0%, #fff8d4 100%);
  border-color: #f5c400;
}
.leaderboard-row--place-2 {
  background: linear-gradient(135deg, #f7f8fb 0%, #eef0f5 100%);
  border-color: #bbc0cc;
}
.leaderboard-row--place-3 {
  background: linear-gradient(135deg, #fbf2e8 0%, #f4e3cf 100%);
  border-color: #c98b4e;
}
.leaderboard-row__place {
  font-size: 22px;
  font-weight: 800;
  text-align: center;
  color: var(--text);
}
.leaderboard-row--place-1 .leaderboard-row__place { color: #946800; }
.leaderboard-row--place-2 .leaderboard-row__place { color: #5b6470; }
.leaderboard-row--place-3 .leaderboard-row__place { color: #7a4a1a; }
.leaderboard-row__back {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-secondary);
}
.leaderboard-row__info {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.leaderboard-row__horse {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.leaderboard-row__rider {
  font-size: 12px;
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.leaderboard-row__score {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.leaderboard-row__score--jumper {
  font-size: 13px;
  font-weight: 600;
}
.leaderboard-row__clear {
  color: #1a8a3a;
  font-weight: 700;
}
.leaderboard-row__time {
  font-size: 12px;
  color: var(--text-secondary);
  font-weight: 500;
}
.leaderboard-row__score--points .leaderboard-row__total {
  font-size: 18px;
  font-weight: 700;
}
.leaderboard-row__rounds {
  font-size: 11px;
  color: var(--text-tertiary);
}

/* Did Not Complete — collapsed by default. */
.leaderboard-dnf {
  margin-top: 12px;
}
.leaderboard-dnf summary {
  cursor: pointer;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-tertiary);
  padding: 8px 0;
}
.leaderboard-row--dnf {
  grid-template-columns: 48px 1fr auto;
  opacity: 0.7;
  background: transparent;
  border-color: transparent;
}
.leaderboard-row--dnf .leaderboard-row__horse {
  text-decoration: line-through;
}
.leaderboard-row__dnf-reason {
  font-size: 11px;
  color: var(--text-tertiary);
  text-transform: capitalize;
}

/* Live-leaderboard admin button + score-entry modal */
.leaderboard__header-right {
  display: flex;
  align-items: center;
  gap: 8px;
}
.leaderboard__admin-btn {
  background: var(--accent, #1e6fff);
  color: white;
  border: none;
  padding: 6px 12px;
  border-radius: 8px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}
.leaderboard__admin-btn:hover { opacity: 0.9; }

.score-modal { max-width: 480px; }
.score-modal__label {
  display: flex;
  flex-direction: column;
  margin-bottom: 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.score-modal__label input,
.score-modal__label select {
  margin-top: 4px;
  padding: 10px 12px;
  font-size: 16px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  color: var(--text);
  border: 1px solid var(--border, rgba(0,0,0,0.15));
  border-radius: 8px;
  background: var(--surface, #fff);
}
.score-modal__checks {
  display: flex;
  gap: 16px;
  margin: 6px 0 12px;
  font-size: 14px;
}
.score-modal__checks label {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
}
.score-modal__error {
  color: var(--danger, #c92a2a);
  font-size: 13px;
  margin-top: 6px;
  min-height: 18px;
}

/* Secondary variant for the leaderboard panel's admin buttons.
 * Used for "Enter Score" — less prominent than the primary
 * "Publish to Spectators" action. */
.leaderboard__admin-btn--secondary {
  background: transparent;
  color: var(--accent, #1e6fff);
  border: 1px solid var(--accent, #1e6fff);
}
.leaderboard__admin-btn--secondary:hover {
  background: rgba(30, 111, 255, 0.08);
}

/* Unified Live Standings — Phase 1 state pills + beta note. */
.leaderboard__state {
  font-size: 12px;
  font-weight: 700;
  padding: 2px 10px;
  border-radius: 10px;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.leaderboard__state--awaiting {
  background: var(--surface-secondary, #f0f1f4);
  color: var(--text-secondary, #5a6472);
}
.leaderboard__state--draft {
  background: rgba(245, 159, 0, 0.14);
  color: #b06a00;
}
.leaderboard__state--official {
  background: rgba(34, 139, 76, 0.14);
  color: #1f7a44;
}
.leaderboard__approver {
  font-size: 11px;
  color: var(--text-secondary, #5a6472);
  margin-left: 8px;
}
.leaderboard__beta {
  font-size: 11px;
  font-style: italic;
  color: var(--text-tertiary, #8a93a0);
  margin: -4px 0 12px;
}
/* ===========================================================
 * Live-standings Phase 2 animation — score-change pulse +
 * lead-change emphasis. Trigger classes are added one-shot by
 * the flipReplace applier (standings-flip.js). The FLIP reorder
 * itself is JS/WAAPI (transform); these are the CSS accents.
 * The global prefers-reduced-motion guard above neutralizes
 * these automatically — no extra reduced-motion rules needed.
 * =========================================================== */
@keyframes leaderboard-row__score-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(30, 111, 255, 0.0); }
  35%  { box-shadow: 0 0 0 4px rgba(30, 111, 255, 0.28); }
  100% { box-shadow: 0 0 0 0 rgba(30, 111, 255, 0.0); }
}
@keyframes leaderboard-row__lead-change {
  0%   { box-shadow: 0 0 0 0 rgba(245, 196, 0, 0.0); transform: scale(1); }
  30%  { box-shadow: 0 0 0 5px rgba(245, 196, 0, 0.45); transform: scale(1.015); }
  100% { box-shadow: 0 0 0 0 rgba(245, 196, 0, 0.0); transform: scale(1); }
}
.leaderboard-row--score-changed {
  animation: leaderboard-row__score-pulse 0.9s ease-in-out 1;
}
.leaderboard-row--lead-change {
  animation: leaderboard-row__lead-change 0.7s cubic-bezier(0.21, 1.02, 0.73, 1) 1;
}

.member-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: 8px;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1.4;
  color: #fff;
  background: var(--member-badge-color, #555);
  vertical-align: middle;
}

.app-sponsor-footer {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 22px 20px 30px;
  border-top: 1px solid var(--divider);
  margin-top: 8px;
}
.app-sponsor-footer__eyebrow {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}
.app-sponsor-footer__link { display: inline-flex; align-items: center; }
.app-sponsor-footer__logo { max-height: 44px; width: auto; object-fit: contain; }
.app-sponsor-footer__name { font-size: 17px; font-weight: 600; color: var(--text); }

/* ── App Sponsor: server-driven band + banner ──
   Look is driven by data-loudness (subtle | medium | bold) and an optional
   data-height (compact | standard | tall) stamped by window.AppSponsor's
   builders, plus an optional --app-sponsor-bg override (validated #RGB/#RRGGBB
   inline style). Loudness presets resolve a small set of custom properties
   that both the .app-sponsor-band (Live/Info footer) and .app-sponsor-banner
   (Schedule top row) consume, so the two layouts share one palette.

   Defaults below are the MEDIUM preset (toned-down) so an absent/legacy
   appearance reads as medium. BOLD restores the previous bold-black band. */
.app-sponsor-band,
.app-sponsor-banner {
  /* Medium preset (default) — clearly less intense than the old bold-black: a
     soft surface that sits on the page rather than a full dark slab. */
  --asp-bg: var(--app-sponsor-bg, var(--surface, #f5f5f7));
  --asp-eyebrow: var(--text-tertiary, #6e6e73);
  --asp-name: var(--text, #1d1d1f);
  --asp-plate-bg: #fff;
  --asp-plate-shadow: 0 2px 10px rgba(0,0,0,0.10);
  --asp-cta-color: var(--accent, #0071e3);
  --asp-cta-bg: rgba(0,0,0,0.05);
  --asp-divider: 1px solid var(--divider, rgba(0,0,0,0.08));
  /* Height preset (default = standard). */
  --asp-pad-y: 14px;
  --asp-logo-h: 60px;
}
/* SUBTLE — quietest: nearly chromeless, transparent surface, muted accents,
   text-link CTA. Reads as a small credit line, not an ad. */
.app-sponsor-band[data-loudness="subtle"],
.app-sponsor-banner[data-loudness="subtle"] {
  --asp-bg: var(--app-sponsor-bg, transparent);
  --asp-eyebrow: var(--text-tertiary, #8e8e93);
  --asp-name: var(--text-secondary, #3c3c43);
  --asp-plate-bg: transparent;
  --asp-plate-shadow: none;
  --asp-cta-color: var(--text-secondary, #6e6e73);
  --asp-cta-bg: transparent;
  --asp-divider: 1px solid var(--divider, rgba(0,0,0,0.06));
}
/* BOLD — the previous full-bleed dark band: dark gradient slab, gold eyebrow,
   white logo plate, pill CTA. Highest contrast / most prominent. */
.app-sponsor-band[data-loudness="bold"],
.app-sponsor-banner[data-loudness="bold"] {
  --asp-bg: var(--app-sponsor-bg, linear-gradient(160deg, #1b2330, #0e1620));
  --asp-eyebrow: #c9a86a;
  --asp-name: #fff;
  --asp-plate-bg: #fff;
  --asp-plate-shadow: 0 6px 22px rgba(0,0,0,0.35);
  --asp-cta-color: rgba(255,255,255,0.92);
  --asp-cta-bg: rgba(255,255,255,0.12);
  --asp-divider: 1px solid rgba(255,255,255,0.08);
}
/* Height presets (apply to both layouts). */
.app-sponsor-band[data-height="compact"],
.app-sponsor-banner[data-height="compact"] { --asp-pad-y: 10px; --asp-logo-h: 44px; }
.app-sponsor-band[data-height="standard"],
.app-sponsor-banner[data-height="standard"] { --asp-pad-y: 14px; --asp-logo-h: 60px; }
.app-sponsor-band[data-height="tall"],
.app-sponsor-banner[data-height="tall"] { --asp-pad-y: 22px; --asp-logo-h: 84px; }

/* App Sponsor: full-bleed premium band (Live footer / Info) */
.app-sponsor-band {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 11px;
  padding: calc(var(--asp-pad-y) + 4px) 20px calc(var(--asp-pad-y) + 8px);
  text-decoration: none;
  background: var(--asp-bg);
  margin-top: 8px;
}
.app-sponsor-band__eyebrow {
  font-size: 11px; font-weight: 800; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--asp-eyebrow);
}
.app-sponsor-band__plate {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--asp-plate-bg); border-radius: 12px; padding: 13px 22px;
  box-shadow: var(--asp-plate-shadow);
}
.app-sponsor-band__logo { max-height: var(--asp-logo-h); width: auto; object-fit: contain; display: block; }
.app-sponsor-band__name { font-size: 22px; font-weight: 800; color: var(--asp-name); }
.app-sponsor-band__cta {
  font-size: 12px; font-weight: 700; letter-spacing: 0.02em;
  color: var(--asp-cta-color);
  background: var(--asp-cta-bg);
  padding: 8px 16px; border-radius: 999px;
}

/* App Sponsor: wide single-row banner (Schedule top) — logo LEFT, name RIGHT.
   Shares the loudness palette via the custom props resolved above. */
.app-sponsor-banner {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: var(--asp-pad-y) 16px;
  text-decoration: none;
  background: var(--asp-bg);
  border-radius: 14px;
  border-top: var(--asp-divider);
  border-bottom: var(--asp-divider);
  margin: 8px 0 4px;
}
.app-sponsor-banner__left {
  display: inline-flex; align-items: center; min-width: 0;
}
.app-sponsor-banner__logo {
  max-height: var(--asp-logo-h); width: auto; object-fit: contain; display: block;
}
.app-sponsor-banner__logo--text {
  font-size: 18px; font-weight: 800; color: var(--asp-name); white-space: nowrap;
}
.app-sponsor-banner__right {
  display: flex; flex-direction: column; align-items: flex-end; text-align: right;
  gap: 3px; min-width: 0;
}
.app-sponsor-banner__eyebrow {
  font-size: 10px; font-weight: 800; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--asp-eyebrow);
}
.app-sponsor-banner__name {
  font-size: 17px; font-weight: 700; color: var(--asp-name);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}

/* ── Live tab: App Sponsor as a full-bleed footer bar ──
   #app-sponsor-host is used ONLY by the Live tab (Info uses
   #app-sponsor-info, Schedule #app-sponsor-schedule), so this block
   never touches those surfaces. The host is a direct child of #app —
   which has no horizontal padding and is offset by the sidebar via
   body's padding-left — so a block-level child already fills the content
   area edge-to-edge. We just give it separation from the content above
   and a tasteful top hairline to read as a footer bar. The band's inner
   content stays centered via .app-sponsor-band's align-items: center. */
#app-sponsor-host {
  margin-top: 24px;
}
/* Live tab: pin the App Sponsor to the BOTTOM of the content area in
   every state (sticky-footer layout). #app becomes a flex column so the
   host's `margin-top: auto` pushes it to the bottom when content is
   short (takeover / no-rings) and lets it sit right after the content
   when the live grid is tall. Scoped to Live (body[data-tab="live"]) so
   Info / Schedule / Search / Admin layouts are untouched. The 24px base
   rule above is intentionally overridden here on Live. */
body[data-tab="live"] #app {
  display: flex;
  flex-direction: column;
  /* Fill the viewport BELOW the in-flow chrome so the host's
     margin-top:auto pins it to the *visible* bottom, not below the fold.
     At mobile the sticky .top-app-bar (var(--top-bar-h)) sits above #app
     in flow, plus body's safe-area top padding. Without this subtraction
     #app's 100dvh runs ~48px past the fold and the footer is clipped. */
  min-height: calc(100dvh - var(--safe-t) - var(--top-bar-h));
}
/* In a flex column, .view's `margin: 0 auto` suppresses the default
   cross-axis stretch and collapses it to its content's min width — the
   live grid would shrink to one-word-per-line in a thin column. Give it
   a definite full width so it fills the content area (its `@container
   view` 2-column breakpoint fires as before); `max-width` + auto margins
   still cap and center it on mobile. */
body[data-tab="live"] #app > .view { width: 100%; }
/* A visible weather alert is a fixed overlay but bumps the top bar's
   height by 28px (see `body.has-weather-alert #top-app-bar`), pushing
   #app down that much more on mobile — subtract it too. */
body.has-weather-alert[data-tab="live"] #app {
  min-height: calc(100dvh - var(--safe-t) - var(--top-bar-h) - 28px);
}
@media (min-width: 900px) {
  /* Top bar is hidden (the sidebar carries the chrome), so only body's
     safe-area top padding sits above #app. The weather banner is a fixed
     overlay here and doesn't move #app, so both cases collapse to one. */
  body[data-tab="live"] #app,
  body.has-weather-alert[data-tab="live"] #app {
    min-height: calc(100dvh - var(--safe-t));
  }
}
body[data-tab="live"] #app > #app-sponsor-host {
  margin-top: auto;     /* sticky footer */
  position: relative;   /* establish a stacking context so... */
  z-index: 2;           /* ...the host sits ABOVE the fixed .show-state-hero
                           (z-index: 1) in takeover states — its opaque dark
                           band then both paints over and receives clicks on
                           the hero's bottom strip. */
}
body[data-tab="live"] #app > #app-sponsor-host .app-sponsor-band {
  margin-top: 0;
  /* Top hairline delineates the footer bar from the content above. Neutral
     by default (medium/subtle sit on a light surface); the bold preset
     overrides it with the white-on-dark hairline + drop-shadow below. */
  border-top: 1px solid var(--divider, rgba(0,0,0,0.08));
  /* Pad the bottom past the home indicator so the bar reads cleanly near the
     edge. This is ON the band, not a negative margin — #app's own
     padding-bottom (the mobile bottom-bar / safe-area reserve) is left intact
     and the bar sits just above it. */
  padding-bottom: calc(22px + var(--safe-b, 0px));
}
/* Bold preset: white-on-dark hairline + soft lift to match the dark
   #1b2330→#0e1620 gradient slab. */
body[data-tab="live"] #app > #app-sponsor-host .app-sponsor-band[data-loudness="bold"] {
  border-top: 1px solid rgba(255,255,255,0.08);
  box-shadow: 0 -8px 24px rgba(0,0,0,0.18);
}

/* Live tab — inline sponsor placement: when a class is in the ring the
   sponsor is relocated into the sidebar between On Deck and Coming Up
   (see renderLiveContent) so it sits above the fold. Here the host is a
   descendant of .live-sidebar (not a direct child of #app), so the
   direct-child footer rules above don't apply and it reads as a normal
   rounded card in the column rather than a full-bleed bar. The base
   `#app-sponsor-host { margin-top: 24px }` gives it space below On Deck. */
.live-sidebar #app-sponsor-host .app-sponsor-band {
  margin-top: 0;
  border-radius: 14px;
}
