:root {
  --bg: #f7f8fa;
  --surface: #ffffff;
  --border: #e3e6eb;
  --ink: #111827;
  --muted: #6b7280;
  --accent: #0d7a4f;
  --accent-ink: #ffffff;
  --error: #b91c1c;
  --warning: #f59e0b;
  --warning-strong: #b45309;
  --gold: #ffda79;
  /* "This row is mine" highlight, shared by the class table (is-me) and the
     club table (is-favourite) so both leagues mark the student's row alike. */
  --mine-row: #ffe5a1;
  --mine-row-hover: #ffdc8a;
  --success: #16a34a;
  --success-strong: #0a6c2c;
  --danger: #dc2626;
  --radius-sm: 6px;
  --radius-md: 8px;
  --radius: 10px;
  --radius-lg: 12px;
  --radius-pill: 999px;
  --tint-row: rgba(42, 51, 70, 0.04);
  --tint-row-soft: rgba(42, 51, 70, 0.03);
  --tint-row-cool: rgba(14, 63, 126, 0.04);
  --shadow: 0 1px 2px rgba(17, 24, 39, 0.04), 0 1px 3px rgba(17, 24, 39, 0.06);
  /* Layered "physical key" shadow for the raised action buttons (primary, gold,
     the green replay actions). The inset bottom edge fakes the button's
     thickness; rest / hover / press deepen and flatten it. The run-slot buttons
     intentionally share these exact values. */
  --btn-raise:
    rgba(0, 0, 0, 0.4) 0 2px 4px, rgba(0, 0, 0, 0.3) 0 7px 13px -3px,
    rgba(0, 0, 0, 0.2) 0 -3px 0 inset;
  --btn-raise-hover:
    rgba(0, 0, 0, 0.45) 0 4px 6px, rgba(0, 0, 0, 0.35) 0 11px 20px -3px,
    rgba(0, 0, 0, 0.2) 0 -3px 0 inset;
  --btn-raise-press:
    rgba(0, 0, 0, 0.4) 0 1px 2px, rgba(0, 0, 0, 0.25) 0 3px 6px -2px,
    rgba(0, 0, 0, 0.15) 0 -1px 0 inset;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  color: var(--ink);
  font-family:
    'Nunito',
    -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    Roboto,
    sans-serif;
  font-size: 16px;
  line-height: 1.5;
}
/* Background lives on <html> only, so a fixed decoration layer can sit behind
   the body content at z-index: -1 while <body> itself stays transparent. */
html {
  background: var(--bg);
}

/* Subtle full-width stadium backdrop pinned to the bottom of the viewport.
   Behind all content, never interactive. width: 100% (not 100vw) so the
   scrollbar can't trigger a horizontal-scroll glitch on a fixed element. */
.page-decoration {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  height: auto;
  z-index: -1;
  opacity: 0.03;
  pointer-events: none;
  user-select: none;
}

h1,
h2,
h3,
h4,
.favourite-card-name,
.brand {
  font-family:
    'Urbanist',
    'Nunito',
    -apple-system,
    sans-serif;
  font-weight: 600;
  letter-spacing: 0.01em;
}

a {
  color: var(--ink);
}

.space-above {
  margin-top: 32px;
}

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding: 16px 24px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.demo-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 10px 24px;
  background: #e66767;
  color: #fff;
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.01em;
}
.demo-banner[hidden] {
  display: none;
}
.demo-banner-text {
  line-height: 1.2;
}
.demo-banner-exit {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 5px 12px;
  border: 1px solid rgba(255, 255, 255, 0.55);
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  font-weight: 700;
  font-size: 0.85rem;
  text-decoration: none;
  white-space: nowrap;
  transition:
    background 0.15s ease,
    border-color 0.15s ease;
}
.demo-banner-exit:hover {
  background: rgba(255, 255, 255, 0.22);
  border-color: #fff;
}

/* Soft amber "verify your email" nudge shown across the top of the teacher
   dashboard for unverified accounts. Replaces the old hard verification gate. */
.verify-nudge {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 24px;
  background: #fff7e6;
  border-bottom: 1px solid var(--warning);
  color: var(--warning-strong);
  font-size: 0.92rem;
  font-weight: 600;
}
.verify-nudge[hidden] {
  display: none;
}
.verify-nudge-text {
  flex: 1;
  line-height: 1.3;
}
.verify-nudge-resend {
  flex: none;
  background: none;
  border: 1px solid var(--warning-strong);
  border-radius: var(--radius-sm);
  padding: 5px 12px;
  font: inherit;
  font-weight: 700;
  color: var(--warning-strong);
  cursor: pointer;
}
.verify-nudge-resend:hover {
  background: var(--warning-strong);
  color: #fff;
}
.verify-nudge-resend:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.verify-nudge-dismiss {
  flex: none;
  background: none;
  border: none;
  font-size: 1.25rem;
  line-height: 1;
  color: var(--warning-strong);
  cursor: pointer;
  padding: 0 2px;
}

/* Boxed brand chip across both app headers (student + teacher) — gives the
   identity a distinct "logo" feel and, on teacher, separates it from the
   breadcrumb beside it. .brand exists only on these two pages. */
.brand {
  font-weight: 700;
  letter-spacing: -0.01em;
  padding: 9px 0;
}
.brand span {
  font-weight: 400;
}
.site-nav {
  display: flex;
  gap: 24px;
  align-items: center;
  /* Auto margin (not just the header's space-between) keeps the actions pinned
     right even when the nav wraps to its own row at tablet widths, so the wrap
     reads as a deliberate top-left identity / bottom-right actions layout. */
  margin-left: auto;
}
/* Left side of the header groups everything about the site (brand) with a
   breadcrumb back to the teacher's class list. The right side (.site-nav)
   holds How to Play plus the live run controls. */
.site-header-left {
  display: flex;
  align-items: center;
  gap: 16px;
  min-width: 0;
}
.breadcrumb {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.9rem;
  min-width: 0;
}
.breadcrumb-sep {
  color: var(--muted);
  opacity: 0.55;
}
.breadcrumb-current {
  font-weight: 700;
  color: var(--ink);
}
/* Plain text links in the header (My Classes, How to Play). Always underlined
   so they clearly read as clickable, even projected. 1px (not 0.5px) renders
   reliably on 1x/projector screens; the offset keeps it looking light. */
.header-link {
  color: var(--muted);
  font-weight: 500;
  font-size: 0.9rem;
  white-space: nowrap;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
.header-link:hover {
  color: var(--ink);
}
/* The live season controls, lifted out of the old bottom bar into the header.
   .run-slot is the single rotating slot: Run Matchday X during the season,
   then Season Review + Start New Season once it's complete. */
.run-slot {
  display: flex;
  align-items: center;
  gap: 8px;
}
.run-slot[hidden] {
  display: none;
}
/* Icon + label layout for the run-slot action buttons. The [hidden] guard is
   essential: a plain display rule would override the hidden attribute and
   reveal the Season Review / Start New Season buttons prematurely. */
.run-slot button {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  box-shadow:
    rgba(0, 0, 0, 0.4) 0px 2px 4px,
    rgba(0, 0, 0, 0.3) 0px 7px 13px -3px,
    rgba(0, 0, 0, 0.2) 0px -3px 0px inset;
}
.run-slot button[hidden] {
  display: none;
}
.run-slot .btn-icon {
  width: 1.05em;
  height: 1.05em;
  flex: 0 0 auto;
}
/* Award Points quick action: gold, sits left of Run Matchday. */
.btn-gold {
  background: var(--gold);
  color: var(--ink);
  border: none;
  padding: 10px 14px;
  border-radius: var(--radius-md);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  transition:
    filter 0.15s ease,
    transform 0.15s ease,
    box-shadow 0.15s ease;
}
/* Hover lifts and deepens the layered shadow; active presses it down. Id-based
   and scoped to the two always-visible run-slot actions so it reliably beats
   the generic .primary / .btn-gold interaction styles regardless of source order. */
#run-matchday:not(:disabled):hover,
#run-matchday:not(:disabled):focus-visible,
#award-points-quick:hover,
#award-points-quick:focus-visible {
  transform: translateY(-1px);
  filter: brightness(1.04);
  box-shadow:
    rgba(0, 0, 0, 0.45) 0px 4px 6px,
    rgba(0, 0, 0, 0.35) 0px 11px 20px -3px,
    rgba(0, 0, 0, 0.2) 0px -3px 0px inset;
}
#run-matchday:not(:disabled):active,
#award-points-quick:active {
  transform: translateY(1px);
  filter: brightness(0.98);
  box-shadow:
    rgba(0, 0, 0, 0.4) 0px 1px 2px,
    rgba(0, 0, 0, 0.25) 0px 3px 6px -2px,
    rgba(0, 0, 0, 0.15) 0px -1px 0px inset;
}
/* Football glyph on Run Matchday. A mask (not a child node) so the button's
   dynamic textContent update can't wipe it; tinted to the button text colour. */
#run-matchday::before {
  content: '';
  width: 1.05em;
  height: 1.05em;
  flex: 0 0 auto;
  background-color: currentColor;
  -webkit-mask: url('../assets/images/soccer-ball.svg') center / contain
    no-repeat;
  mask: url('../assets/images/soccer-ball.svg') center / contain no-repeat;
}
.muted {
  color: var(--muted);
  font-size: 0.9rem;
}
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Landing page is a flex column so the footer sits in normal flow below the
   hero instead of floating over it on short viewports (e.g. landscape phones).
   Scoped with :has so other pages' <body> layout is untouched. */
body:has(main.landing) {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
}
.landing {
  flex: 1 0 auto;
  max-width: 1280px;
  margin: 0 auto;
  padding: 96px 48px 32px;
  display: grid;
  grid-template-columns: minmax(280px, 1fr) 1.4fr;
  gap: 80px;
  align-content: center;
  align-items: start;
}
@media (max-width: 880px) {
  .landing {
    grid-template-columns: 1fr;
    gap: 48px;
    /* Drop the desktop align-content: center on mobile — when the right column
       appears on expand the grid grows past 100vh, which would re-centre
       everything and visibly pull the title upward. Top-align so the title
       sits at a fixed offset across states. */
    align-content: start;
    padding: 48px 24px;
    justify-items: center;
  }
  /* Higher specificity (.landing-left >) so this beats the base .landing-title
     rule that appears later in the file with a `margin` shorthand which
     otherwise resets margin-top to 0. */
  .landing-left > .landing-title {
    /* Was 10vh; trimmed so the added reassurance row doesn't push the on-load
       app screenshot below the fold. Still clears the top nav. */
    margin-top: 6vh;
  }
  .landing-title br {
    display: none;
  }
  /* Higher specificity (.landing >) so this beats the base .landing-left's
     width: fit-content rule that appears later in the file. Locks the column
     width across collapsed / expanded states. */
  .landing > .landing-left,
  .landing > .landing-right {
    width: 100%;
    max-width: 420px;
  }
  /* Show the app screenshot on load (in its stadium frame) so phone visitors
     see the real product immediately, not only after tapping a card. Hover
     preview has no meaning on touch, so the collapsed state just shows the
     default first screenshot; tapping a card still scales it up + adds extras. */
  .landing-right {
    display: block;
  }
}

.landing-left {
  display: flex;
  flex-direction: column;
  width: fit-content;
  max-width: 460px;
  position: relative;
}
/* Desktop only: the grid top-aligns this column (align-items: start), leaving a
   band of dead space under the menu. Give the column a min-height and let the
   hero elements distribute into it so they breathe. min-height (not fixed) so it
   still grows when the menu expands; space-between keeps the headline pinned to
   the top so it never jumps on interaction. Mobile keeps its natural stacking. */
@media (min-width: 881px) {
  .landing-left {
    min-height: 72vh;
    justify-content: space-between;
  }
}
.landing-title {
  font-family: 'Urbanist', sans-serif;
  font-weight: 900;
  /* Trimmed from 4.5rem max: the headline is now a two-sentence value
     statement, not the two-word brand, so it needs to wrap readably in the
     left column rather than blow out to one giant word per line. */
  font-size: clamp(2rem, 2.5vw, 3rem);
  line-height: 1.06;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 0 0 18px;
  text-wrap: balance;
}
.landing-tagline {
  font-family: 'Urbanist', sans-serif;
  font-size: 1.4rem;
  font-weight: 600;
  color: var(--ink);
  margin: 0 0 14px;
  /* max-width: 30ch; */
  line-height: 1.5;
  opacity: 0.8;
  --rise-opacity: 0.8; /* keep the faded look as the arrival animation's end state */
}
.landing-subtagline {
  font-family: 'Urbanist', sans-serif;
  font-size: 1.05rem;
  font-weight: 400;
  color: var(--ink);
  margin: 0 0 40px;
  /* max-width: 30ch; */
  line-height: 1.6;
  letter-spacing: 0.01em;
  opacity: 0.6;
  --rise-opacity: 0.6; /* keep the faded look as the arrival animation's end state */
  text-wrap: balance;
}
/* Compact "at a glance" reassurance row under the hero copy — handles the
   practical teacher objections (privacy, no spreadsheets) the emotional copy
   can't. The negative margin pulls it up under the subtagline's 40px gap. */
.landing-reassure {
  font-family: 'Urbanist', sans-serif;
  font-size: 0.9rem;
  font-weight: 300;
  letter-spacing: 0.01em;
  color: var(--muted);
  margin: -24px 0 32px;
  /* Icon-led chips: a small line icon anchors each reassurance, replacing the
     old "·" separators. Flex row with a row/column gap so they wrap tidily. */
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 20px;
}
/* Each reassurance breaks as a unit ("No student accounts" never splits). */
.landing-reassure .reassure-item {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
}
.landing-reassure .reassure-item svg {
  width: 1.05em;
  height: 1.05em;
  flex-shrink: 0;
  fill: currentColor;
  opacity: 0.7;
  /* some Bootstrap icons are drawn to the edge of their 0 0 16 16 box; the svg's
     default overflow:hidden would shave those edges, so let them paint fully. */
  overflow: visible;
}

/* Persistent hero CTA pair, sat between the reassurance row and the menu so a
   teacher never has to open the accordion to find a button. */
.landing-hero-cta {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 0 0 36px;
}
.landing-hero-cta .nav-link {
  font-size: 1rem;
  padding: 10px 22px;
}

/* Brand lockup promoted into the top-left nav (was the hero h1). Bolder and
   ink-coloured so it reads as the wordmark, not just another muted site link.
   Higher specificity than the base .landing-top-nav-left a rule it overrides. */
.landing-top-nav-left a.landing-wordmark {
  font-family: 'Urbanist', sans-serif;
  font-weight: 800;
  font-size: 1.1rem;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin-right: 6px;
}
.landing-top-nav-left a.landing-wordmark:hover {
  background: none;
}

/* Arrival motion: stagger the hero in on load (title -> tagline -> subtagline
   -> menu -> app). Guarded by no-preference so reduced-motion users get the
   static layout (no animation = no lingering opacity:0 from fill-mode). */
@keyframes landing-rise {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    /* Per-element resting opacity (tagline 0.8, subtagline 0.6, others default
       1). Without this the fill-mode would pin everything to opacity 1 and
       override those faded looks unless they used !important. */
    opacity: var(--rise-opacity, 1);
    transform: translateY(0);
  }
}
@media (prefers-reduced-motion: no-preference) {
  .landing-title,
  .landing-tagline,
  .landing-subtagline,
  .landing-reassure,
  .landing-hero-cta,
  .landing-menu,
  .landing-right {
    animation: landing-rise 0.6s cubic-bezier(0.16, 1, 0.3, 1) both;
  }
  .landing-title {
    animation-delay: 0.05s;
  }
  .landing-tagline {
    animation-delay: 0.13s;
  }
  .landing-subtagline {
    animation-delay: 0.21s;
  }
  .landing-reassure {
    animation-delay: 0.25s;
  }
  .landing-hero-cta {
    animation-delay: 0.29s;
  }
  .landing-menu {
    animation-delay: 0.33s;
  }
  .landing-right {
    animation-delay: 0.41s;
  }
}

.landing-menu {
  position: relative;
}
.landing-menu ul {
  position: relative;
  z-index: 1;
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: 298px;
  transition: gap 0.42s cubic-bezier(0.32, 0.72, 0, 1);
}
.landing-menu.is-expanded ul {
  gap: 0;
}
.landing-menu li {
  height: 48px;
  overflow: hidden;
  transition:
    height 0.42s cubic-bezier(0.32, 0.72, 0, 1),
    opacity 0.32s ease;
}
.landing-menu.is-expanded li:not(.is-expanded-item) {
  height: 0;
  opacity: 0;
  pointer-events: none;
}
.landing-menu button {
  background: none;
  border: none;
  padding: 12px 0;
  font: inherit;
  font-size: 1rem;
  font-weight: 500;
  color: var(--muted);
  cursor: pointer;
  text-align: left;
  width: fit-content;
  display: flex;
  align-items: center;
  gap: 12px;
  transition: color 0.15s ease;
}
.landing-menu button[data-menu-item]::before {
  content: '';
  display: block;
  width: 0.85em;
  height: 0.85em;
  flex-shrink: 0;
  background-color: currentColor;
  -webkit-mask: url('../assets/images/soccer-ball.svg') center / contain
    no-repeat;
  mask: url('../assets/images/soccer-ball.svg') center / contain no-repeat;
  opacity: 0.55;
  transition: opacity 0.15s ease;
}
.landing-menu button[data-menu-item]:hover {
  color: var(--ink);
}
.landing-menu button[data-menu-item]:hover::before,
.landing-menu button[data-menu-item].is-active::before {
  opacity: 0.85;
}
.landing-menu-outline {
  position: absolute;
  left: -14px;
  right: -14px;
  top: 0;
  height: 0;
  background: var(--surface);
  border-top: 1px solid rgba(255, 255, 255, 0.15);
  border-bottom: 1px solid rgba(0, 0, 0, 0.15);
  border-radius: var(--radius-md);
  pointer-events: none;
  z-index: 0;
  box-shadow: rgba(0, 0, 0, 0.05) 0px 0px 0px 1px;
  transition:
    transform 0.28s cubic-bezier(0.32, 0.72, 0, 1),
    height 0.28s cubic-bezier(0.32, 0.72, 0, 1),
    opacity 0.18s ease;
}
.landing-menu:not(:has(button.is-active)) .landing-menu-outline {
  opacity: 0;
}
.landing-menu button.is-active {
  color: var(--ink);
}
.landing-menu.is-expanded button[data-menu-item] {
  cursor: default;
}

.landing-menu-detail {
  position: absolute;
  top: 76px;
  left: 0;
  right: 0;
  z-index: 2;
  opacity: 0;
  visibility: hidden;
  transform: translateY(16px);
  /* Fading OUT (back button): quick, no delay so menu items can expand cleanly */
  transition:
    opacity 0.12s ease,
    transform 0.12s ease,
    visibility 0s linear 0.12s;
}
.landing-menu.is-expanded .landing-menu-detail {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  /* Fading IN: smooth eased fade up, no delay */
  transition:
    opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    visibility 0s linear 0s;
}
.landing-menu-detail p {
  margin: 0 0 18px;
  font-size: 1rem;
  line-height: 1.6;
  color: var(--ink);
  max-width: 40ch;
  line-height: 2rem;
  font-weight: 400;
  opacity: 0.9;
}
.landing-menu-detail p:first-of-type {
  font-weight: bold;
}
.landing-menu-detail-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 24px;
}
.landing-menu-back {
  background: none;
  border: none;
  padding: 6px 0;
  font: inherit;
  font-size: 0.95rem;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s ease;
}
.landing-menu-back:hover {
  color: var(--ink);
}

@media (max-width: 880px) {
  /* In the stacked layout, the detail panel needs to push the right column
     down rather than floating absolutely over it. */
  .landing-menu-detail {
    position: relative;
    top: auto;
    margin-top: 24px;
  }
  /* Collapsed, the relative detail panel still occupied layout space
     (visibility:hidden keeps the Back/Start buttons' height), leaving a dead
     band between the menu and the screenshot. Costs the fade-in on mobile;
     the items' collapse motion carries the transition. */
  .landing-menu:not(.is-expanded) .landing-menu-detail {
    display: none;
  }
  /* The 298px reserve under the menu is desktop-only breathing room for the
     expanding detail panel. On mobile it's dead space that pushed the on-load
     app screenshot below the fold. */
  .landing-menu ul {
    min-height: 0;
  }
}

/* Teacher endorsements under the stadium-framed screenshot. Same below-frame
   technique as .landing-extras (absolute at top: 100%) because in-flow
   siblings stretch the screen-frame backdrop. Fades out when a menu item
   expands and the extra images slide into this space. Multiple quotes cycle
   here via the arrows/dots + auto-advance wired in index.html's inline script. */
.landing-quotes {
  position: absolute;
  /* 86px drops the quote's centre level with the menu buttons across common
     desktop sizes (measured 83-89px at 1280/1440/1920). */
  top: calc(100% + 86px);
  left: 0;
  right: 0;
  z-index: 1;
  text-align: center;
  transition: opacity 0.2s ease;
}
.landing:has(.landing-menu.is-expanded) .landing-quotes {
  opacity: 0;
  pointer-events: none;
}
.lq-viewport {
  position: relative;
}
.lq-track {
  position: relative;
}
.landing-quote {
  margin: 0;
}
/* Crossfade: the current quote sits in flow (it sets the track height); the
   others stack on top at opacity 0. Same footprint, so no layout jump as they
   swap. The fade is skipped under reduced motion (instant swap instead). */
.landing-quote:not(.is-current) {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .landing-quote {
    transition: opacity 0.5s ease;
  }
}
/* Prev/next chevrons flanking the quote, vertically centred on the viewport.
   Drawn with borders so there's no icon dependency in this inline-script page. */
.lq-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  /* Above .lq-track: it's a positioned element, so without this the track
     paints over the prev button (which precedes it in the DOM) and swallows
     its clicks, while the next button (after the track) stays clickable. */
  z-index: 2;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  opacity: 0.35;
  transition: opacity 0.15s ease;
}
.lq-nav:hover,
.lq-nav:focus-visible {
  opacity: 0.9;
  background: #f7f8fa;
  box-shadow:
    var(--tint-row-cool) 0px 0px 0px 1px,
    rgba(42, 51, 69, 0.04) 0px 1px 1px -0.5px,
    var(--tint-row) 0px 3px 3px -1.5px,
    var(--tint-row) 0px 6px 6px -3px,
    var(--tint-row-cool) 0px 12px 12px -6px,
    var(--tint-row-cool) 0px 24px 24px -12px;
}
.lq-nav::before {
  content: '';
  display: block;
  width: 9px;
  height: 9px;
  margin: 0 auto;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
}
.lq-prev {
  left: -4px;
}
.lq-next {
  right: -4px;
}
.lq-prev::before {
  transform: translateX(2px) rotate(135deg);
}
.lq-next::before {
  transform: translateX(-2px) rotate(-45deg);
}
/* Dots under the quote. */
.lq-dots {
  display: flex;
  justify-content: center;
  gap: 7px;
  margin-top: 14px;
}
.lq-dot {
  width: 7px;
  height: 7px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--muted);
  opacity: 0.3;
  cursor: pointer;
  transition:
    opacity 0.15s ease,
    transform 0.15s ease;
}
.lq-dot.is-active {
  opacity: 0.75;
  transform: scale(1.25);
}
/* A single approved quote (before a second is enabled): no nav chrome. */
.landing-quotes[data-count='1'] .lq-nav,
.landing-quotes[data-count='1'] .lq-dots {
  display: none;
}
.landing-quote blockquote {
  margin: 0 auto;
  max-width: 48ch;
  font-family: 'Urbanist', sans-serif;
  font-size: 1.05rem;
  font-weight: 200;
  line-height: 1.7;
  color: var(--ink);
  /* A step above the subtagline's 0.6 so it reads as a voice, not chrome,
     without competing with the hero. */
  opacity: 0.75;
  text-wrap: balance;
}
.landing-quote figcaption {
  margin-top: 10px;
  font-size: 0.9rem;
  font-weight: 100;
  color: var(--muted);
}
@media (max-width: 880px) {
  /* No menu alongside to centre with in the stacked layout: tuck the quote
     back under the image, and reserve flow space for it ahead of the footer
     (it hangs below the column without growing it). */
  .landing-quotes {
    top: calc(100% + 12px);
  }
  .landing-right {
    margin-bottom: 132px;
  }
}

.landing-right {
  position: relative;
  margin-top: -1vh;
}
.landing-extras {
  position: absolute;
  top: calc(100% + 24px);
  left: 0;
  right: 0;
  display: none;
  flex-direction: column;
  gap: 24px;
  padding-bottom: 48px;
  pointer-events: none;
}
/* Each extra is a figure so an endorsement can be overlaid on the image. The
   reveal animation lives on the figure so the image + quote fade in together. */
.landing-extra {
  position: relative;
  margin: 0;
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity 0.15s ease,
    transform 0.15s ease;
}
.landing-screenshot-extra {
  width: 100%;
  height: auto;
  display: block;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 3px;
  box-shadow:
    rgba(9, 30, 66, 0.25) 0px 1px 1px,
    rgba(9, 30, 66, 0.13) 0px 0px 1px 1px;
}
/* Endorsement overlay: a soft scrim dims the image and the quote sits centred on
   top. Only shown when the figure has .has-quote (set by the menu script). */
.landing-extra-quote {
  position: absolute;
  inset: 0;
  z-index: 1;
  margin: 0;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 24px 28px;
  text-align: center;
  color: #fff;
  font-size: 1.15rem;
  font-weight: 600;
  line-height: 1.4;
  background: rgba(11, 31, 23, 0.55);
  border-radius: 3px;
}
.landing-extra.has-quote .landing-extra-quote {
  display: flex;
}
.landing:has(.landing-menu.is-expanded) .landing-extras {
  pointer-events: auto;
}
.landing:has(.landing-menu.is-expanded) .landing-extra {
  opacity: 1;
  transform: translateY(0);
  transition:
    opacity 0.6s ease,
    transform 0.6s ease;
}
.landing:has(.landing-menu.is-expanded) .landing-extra:nth-of-type(1) {
  transition-delay: 0s;
}
.landing:has(.landing-menu.is-expanded) .landing-extra:nth-of-type(2) {
  transition-delay: 0.15s;
}
.landing-screen-frame {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: url('../assets/images/screenBck.webp');
  background-size: 100% 100%;
  background-position: center;
  background-repeat: no-repeat;
}
.landing-screenshot {
  position: relative;
  z-index: 1;
  width: 100%;
  height: auto;
  display: block;
  transform: scale(0.85);
  transform-origin: center;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 3px;
  box-shadow:
    rgba(9, 30, 66, 0.25) 0px 1px 1px,
    rgba(9, 30, 66, 0.13) 0px 0px 1px 1px;
  transition: transform 0.35s ease;
}
.landing:has(.landing-menu.is-expanded) .landing-screenshot {
  transform: scale(1);
}

/* "How do I start?" demo video — sits in the screen frame in place of the
   screenshot (mirrors .landing-screenshot sizing + scale-up so it lands in the
   stadium frame) and plays inline with custom controls (no native fullscreen
   button in any browser). */
.landing-video-wrap {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  width: 100%;
  aspect-ratio: 1600 / 888;
  display: none;
  overflow: hidden;
  background: #0b1f17;
  transform: scale(0.85);
  transform-origin: center;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 3px;
  box-shadow:
    rgba(9, 30, 66, 0.25) 0px 1px 1px,
    rgba(9, 30, 66, 0.13) 0px 0px 1px 1px;
  transition: transform 0.35s ease;
}
.landing-right.show-video .landing-video-wrap {
  display: block;
}
.landing-right.show-video .landing-screenshot {
  visibility: hidden;
}
.landing:has(.landing-menu.is-expanded) .landing-video-wrap {
  transform: scale(1);
}
.landing-video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: #0b1f17;
  cursor: pointer;
}

/* Centre play button — covers the frame while paused, hidden during playback.
   Only present once the item is expanded (.lv-active, toggled by JS). */
.lv-overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  background: rgba(11, 31, 23, 0);
  cursor: pointer;
  transition: background 0.15s ease;
}
.landing-video-wrap.lv-active.is-paused .lv-overlay {
  display: flex;
}
.lv-overlay:hover {
  background: rgba(11, 31, 23, 0.26);
}
.lv-overlay-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: #cd201f;
  border: 2px solid var(--accent-ink);
  color: var(--accent-ink);
  padding-left: 3px;
}
.lv-overlay-icon svg {
  display: block;
  width: 28px;
  height: 28px;
  fill: currentColor;
}

/* Slim custom control bar — play/pause, scrubber, time. No fullscreen/PiP. */
.lv-controls {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  display: none;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: linear-gradient(
    to top,
    rgba(11, 31, 23, 0.85),
    rgba(11, 31, 23, 0)
  );
  transition: opacity 0.3s ease;
}
.landing-video-wrap.lv-active .lv-controls {
  display: flex;
}
/* While playing, the bar fades out ~1.5s after the last mouse move so it stops
   covering the buttons in the recording (re-shown on mouse move / pause). */
.landing-video-wrap.lv-idle .lv-controls {
  opacity: 0;
  pointer-events: none;
}
.landing-video-wrap.lv-idle {
  cursor: none;
}
.lv-toggle {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0 0 0 2px;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  font-size: 0.8rem;
  cursor: pointer;
  transition: background 0.15s ease;
}
.lv-toggle:hover {
  background: rgba(255, 255, 255, 0.3);
}
.lv-toggle-icon {
  display: flex;
  align-items: center;
  justify-content: center;
}
.lv-toggle-icon svg {
  display: block;
  width: 14px;
  height: 14px;
  fill: currentColor;
}
.lv-scrub {
  flex: 1;
  -webkit-appearance: none;
  appearance: none;
  height: 4px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.3);
  cursor: pointer;
}
.lv-scrub::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: #fff;
  cursor: pointer;
}
.lv-scrub::-moz-range-thumb {
  width: 13px;
  height: 13px;
  border: 0;
  border-radius: 50%;
  background: #fff;
  cursor: pointer;
}
.lv-time {
  flex: none;
  min-width: 8ch;
  text-align: right;
  color: #fff;
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
}

#contact-form button[type='submit'] {
  margin-top: 16px;
}
#contact-form textarea,
#feedback-form textarea,
#demo-feedback-form textarea {
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  resize: vertical;
  font-size: 1rem;
  font-weight: 400;
}
#contact-form textarea:focus,
#feedback-form textarea:focus,
#demo-feedback-form textarea:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* Teacher-side feedback dialogs: match the homepage form field spec. */
#feedback-form,
#demo-feedback-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
#feedback-form input,
#demo-feedback-form input {
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  font-size: 1rem;
  font-weight: 400;
}
#feedback-form input:focus,
#demo-feedback-form input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.landing-top-nav {
  position: absolute;
  top: 24px;
  right: 32px;
  z-index: 100;
  display: flex;
  gap: 12px;
}
/* Secondary links mirrored top-left so they're always visible (the footer set
   drops below the fold on short screens like iPad landscape). Subtle
   text-link look, matching the footer rather than the CTA pill. */
.landing-top-nav-left {
  position: absolute;
  top: 24px;
  left: 32px;
  z-index: 100;
  display: flex;
  /* Baseline-align so the larger wordmark and the smaller text links sit on a
     common line rather than top-aligning to different heights. */
  align-items: baseline;
  gap: 4px;
  font-size: 0.85rem;
}
.landing-top-nav-left a,
.landing-top-nav-left button {
  color: var(--muted);
  background: none;
  border: 0;
  font: inherit;
  cursor: pointer;
  text-decoration: none;
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  transition:
    color 0.15s ease,
    background 0.15s ease;
}
.landing-top-nav-left a:hover,
.landing-top-nav-left button:hover {
  color: var(--ink);
  background: rgba(17, 24, 39, 0.05);
}
@media (max-width: 720px) {
  .landing-top-nav-left {
    top: 16px;
    left: 12px;
    gap: 0;
    font-size: 0.8rem;
  }
  .landing-top-nav-left a,
  .landing-top-nav-left button {
    padding: 6px 7px;
  }
}
.nav-link {
  background: #f7f8fa;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  box-shadow:
    var(--tint-row-cool) 0px 0px 0px 1px,
    rgba(42, 51, 69, 0.04) 0px 1px 1px -0.5px,
    var(--tint-row) 0px 3px 3px -1.5px,
    var(--tint-row) 0px 6px 6px -3px,
    var(--tint-row-cool) 0px 12px 12px -6px,
    var(--tint-row-cool) 0px 24px 24px -12px;
  padding: 6px 12px;
  font: inherit;
  font-size: 0.95rem;
  color: var(--muted);
  font-weight: 500;
  cursor: pointer;
  text-decoration: none;
  transition:
    color 0.18s ease,
    background 0.18s ease;
}
.nav-link:hover {
  color: var(--ink);
  background: #fff;
}
/* Promoted nav-link: filled green for the conversion-goal CTA. Same shape
   and size as the surrounding nav-link buttons so the row stays even. */
.nav-link.is-cta,
.nav-link.is-cta:hover {
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 700;
}
.nav-link.is-cta:hover {
  filter: brightness(1.06);
}
/* Separates the get-started pair (Demo, Start a League) from the returning-user
   Sign In. Centred hairline; hidden on mobile where the row wraps. */
.nav-divider {
  align-self: center;
  width: 1px;
  height: 22px;
  background: rgba(17, 24, 39, 0.14);
}
/* Keyboard-only focus indicator on the major pill buttons. */
.nav-link:focus-visible,
button.primary:focus-visible,
button.secondary:focus-visible,
button.danger:focus-visible,
.picker-action-btn:focus-visible,
.picker-leagues a:focus-visible,
.tab-main:focus-visible,
.tab-sub:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}
@media (max-width: 720px) {
  .landing-top-nav {
    top: 16px;
    right: 16px;
    flex-wrap: wrap;
    justify-content: flex-end;
  }
  .nav-divider {
    display: none;
  }
}
/* Phone widths: the two corner navs no longer fit side by side (the button
   row painted over About/How to Play/Contact). Stack them as two centred
   rows: buttons on top, text links beneath, hero clears both. */
@media (max-width: 600px) {
  .landing-top-nav {
    left: 16px;
    justify-content: center;
  }
  .landing-top-nav-left {
    top: 62px;
    left: 12px;
    right: 12px;
    justify-content: center;
    /* Wordmark + three links no longer fit one phone-width line; allow a tidy
       wrap instead of overflowing off-screen. */
    flex-wrap: wrap;
  }
  .landing-left > .landing-title {
    margin-top: max(6vh, 56px);
    margin-top: 100px;
  }
}

.signin-dialog {
  border: none;
  border-radius: var(--radius-lg);
  padding: 32px;
  width: min(92vw, 420px);
  max-height: 90dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--surface);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.25);
}
.signin-dialog[open] {
  animation: dialogIn 0.18s cubic-bezier(0.2, 0.8, 0.2, 1);
}
/* Optional full-bleed hero image at the top of a dialog. Negative margins
   cancel the 32px dialog padding so it spans edge to edge; top corners match
   the dialog radius. Used by confirmDialog's `image` option. */
.dialog-hero {
  display: block;
  width: calc(100% + 64px);
  margin: -32px -32px 24px;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.signin-dialog[open]::backdrop {
  animation: backdropIn 0.18s ease;
}
@keyframes dialogIn {
  from {
    opacity: 0;
    transform: translateY(6px) scale(0.97);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}
@keyframes backdropIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@media (prefers-reduced-motion: reduce) {
  .signin-dialog[open],
  .signin-dialog[open]::backdrop {
    animation: none;
  }
}
html.is-reduced-motion .signin-dialog[open],
html.is-reduced-motion .signin-dialog[open]::backdrop {
  animation: none;
}
.signin-dialog::backdrop {
  background: rgba(15, 23, 42, 0.5);
}
.signin-dialog-close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #f7f8fa;
  border-radius: var(--radius-md);
  box-shadow:
    var(--tint-row-cool) 0px 0px 0px 1px,
    rgba(42, 51, 69, 0.04) 0px 1px 1px -0.5px,
    var(--tint-row) 0px 3px 3px -1.5px,
    var(--tint-row) 0px 6px 6px -3px,
    var(--tint-row-cool) 0px 12px 12px -6px,
    var(--tint-row-cool) 0px 24px 24px -12px;
  border: none;
  padding: 0 0 4px;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition:
    color 0.15s ease,
    background 0.15s ease;
}
.signin-dialog-close:hover {
  color: var(--ink);
  background: var(--bg);
}
.signin-section h2 {
  font-family: 'Urbanist', sans-serif;
  margin: 0 0 12px;
  font-size: 1.25rem;
  font-weight: 900;
  text-transform: uppercase;
}

/* Demo welcome carousel: image-led, one short step at a time (replaces the old
   wall of text). Reuses the single-column .signin-dialog shell, but a touch
   wider so the step images read larger. */
.signin-dialog.demo-welcome {
  width: min(94vw, 500px);
}
.demo-welcome .demo-welcome-step {
  display: none;
}
.demo-welcome .demo-welcome-step.is-active {
  display: block;
}
.demo-welcome-img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  box-shadow: 0 1px 3px rgba(9, 30, 66, 0.08);
  margin: 0 0 20px;
}
/* The first-run tour keeps its × (it's dismissible), so its step images sit a
   little lower to clear the close button. The demo welcome has no × — its
   images stay flush to the top. */
#welcome-league-dialog .demo-welcome-img {
  margin-top: 24px;
}
.demo-welcome-step p {
  margin: 0 0 10px;
  line-height: 1.55;
  color: var(--ink);
}
.demo-welcome-step p:last-child {
  margin-bottom: 0;
}
/* Reserve a steady height for the heading + copy so the dots and buttons below
   don't jump as you step between panels with different amounts of text. Slack
   falls below the text (above the nav), so the image and heading stay put. */
.demo-welcome-copy {
  min-height: 9.5rem;
}
.demo-welcome-nav {
  margin-top: 24px;
}
.demo-welcome-dots {
  display: flex;
  justify-content: center;
  gap: 8px;
  margin-bottom: 18px;
}
.demo-welcome-dots span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--border);
  transition:
    background 0.15s ease,
    transform 0.15s ease;
}
.demo-welcome-dots span.is-active {
  background: var(--accent);
  transform: scale(1.15);
}
.demo-welcome-actions {
  display: flex;
  gap: 12px;
}
.demo-welcome-actions .primary {
  flex: 1;
}
/* Full-bleed footer panel: negative margins cancel the dialog's 32px padding so
   it spans edge to edge, and the bottom corners match the dialog radius. */
.demo-welcome-footnote {
  margin: 20px -32px -32px;
  padding: 14px 32px;
  background: var(--bg);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  text-align: center;
  font-size: 0.85rem;
  border-top: 1px solid rgba(0, 0, 0, 0.1);
}

/* Privacy page — long-form prose, homepage design language. */
.doc-page {
  max-width: 720px;
  margin: 0 auto;
  padding: 64px 24px 80px;
}
.doc-header {
  margin-bottom: 48px;
}
.doc-title {
  font-family: 'Urbanist', sans-serif;
  font-weight: 900;
  font-size: clamp(2.5rem, 5vw, 3.6rem);
  letter-spacing: -0.02em;
  margin: 0 0 12px;
  color: var(--ink);
}
.doc-lede {
  font-size: 1.2rem;
  font-weight: 300;
  color: var(--ink);
  opacity: 0.85;
  margin: 0 0 8px;
  line-height: 1.4;
}
.doc-updated {
  margin: 0;
  font-size: 0.9rem;
}
.doc-body section {
  margin-bottom: 36px;
}
.doc-body h2 {
  font-family: 'Urbanist', sans-serif;
  font-weight: 800;
  font-size: 1.45rem;
  letter-spacing: -0.01em;
  margin: 0 0 14px;
  color: var(--ink);
}
.doc-body h3 {
  font-family: 'Urbanist', sans-serif;
  font-weight: 700;
  font-size: 1.05rem;
  margin: 18px 0 8px;
  color: var(--ink);
}
.doc-body p,
.doc-body li {
  font-size: 1rem;
  line-height: 1.65;
  color: var(--ink);
  margin: 0 0 14px;
}
/* .muted is a project-wide utility — give it enough specificity inside .doc-body
   to win against the body-text rule above. */
.doc-body .muted {
  color: var(--muted);
  font-size: 0.9rem;
}
.doc-body ul {
  padding-left: 22px;
  margin: 0 0 14px;
}
.doc-body li {
  margin-bottom: 6px;
}
.doc-body a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}
/* Prospect endorsement on How to Play, sitting between the overview and the
   scoring detail (hidden for in-app visits via the page script). A pull-quote
   callout - a brand-green accent bar and a soft tint give it presence as
   validation for someone still deciding, without tipping into a CTA. */
.doc-quote {
  margin: 8px 0 28px;
  padding: 22px 26px;
  background: var(--bg);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius-sm);
}
.doc-quote[hidden] {
  display: none;
}
.doc-quote blockquote {
  margin: 0;
  max-width: 60ch;
  font-family: 'Urbanist', sans-serif;
  font-size: 1.2rem;
  font-weight: 300;
  line-height: 1.6;
  color: var(--ink);
  text-wrap: balance;
}
.doc-quote-cite {
  margin: 14px 0 0;
  font-size: 0.92rem;
  font-weight: 400;
  color: var(--muted);
}

.doc-footer {
  margin-top: 32px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: center;
}
/* Scoring table used on the How to Play page. Two columns: thing-that-happened
   on the left, points delta on the right. Right column is monospace and
   colour-coded by sign so the picture reads at a glance. */
.doc-table {
  width: 100%;
  border-collapse: collapse;
  margin: 4px 0 18px;
}
.doc-table th,
.doc-table td {
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  font-size: 1rem;
  line-height: 1.4;
}
.doc-table th {
  font-weight: 700;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}
.doc-table td.doc-table-pts {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-weight: 800;
  white-space: nowrap;
  width: 1%;
}
.doc-table td.doc-table-pts.is-pos {
  color: var(--accent);
}
.doc-table td.doc-table-pts.is-neg {
  color: #b91c1c;
}
.doc-table td.doc-table-pts.is-zero {
  color: var(--muted);
}
.doc-callout {
  background: #fff0c9;
  border: 1px solid var(--border);
  border-left: 3px solid var(--ink);
  border-radius: var(--radius-md);
  padding: 14px 16px;
  margin-top: 28px;
  margin-bottom: 28px;
}
.doc-callout p:last-child {
  margin-bottom: 0;
}

/* Small footer on the marketing homepage with a Privacy link. */
.landing-footer {
  text-align: center;
  font-size: 0.85rem;
  padding: 12px 12px 20px;
}
.landing-footer a,
.landing-footer button {
  color: var(--muted);
  background: none;
  border: 0;
  font: inherit;
  cursor: pointer;
  text-decoration: none;
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  transition:
    color 0.15s ease,
    background 0.15s ease;
}
.landing-footer a:hover,
.landing-footer button:hover {
  color: var(--ink);
  background: rgba(17, 24, 39, 0.05);
}
/* Footer hides while a menu card is expanded, to keep focus on the open card. */
.landing:has(.landing-menu.is-expanded) ~ .landing-footer {
  display: none;
}

/* Picker page footer — only shown while body.is-picker is set. Two quiet
   text links sitting low on the page so they don't compete with the hero. */
.picker-footer {
  display: none;
}
body.is-picker .picker-footer {
  position: fixed;
  bottom: 16px;
  left: 0;
  right: 0;
  display: flex;
  justify-content: center;
  gap: 24px;
  font-size: 0.85rem;
}
.picker-footer a,
.picker-footer-link {
  color: var(--muted);
  text-decoration: none;
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  background: none;
  border: none;
  font: inherit;
  cursor: pointer;
  transition:
    color 0.15s ease,
    background 0.15s ease;
}
.picker-footer a:hover,
.picker-footer-link:hover {
  color: var(--ink);
  background: rgba(17, 24, 39, 0.05);
}

/* "By submitting..." note under the Contact / Sign-in forms. */
.form-privacy-note {
  margin: 12px 0 0;
  font-size: 0.85rem;
}
.form-privacy-note a {
  color: var(--muted);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.form-privacy-note a:hover {
  color: var(--ink);
}

/* "Students do not need an account" note in the signup copy column, with an
   escape link to the student sign-in. The 18+ checkbox in the form does the
   hard gating, so this stays quiet. */
.form-student-note button {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-weight: 700;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.form-student-note button:hover {
  color: var(--ink);
}

/* 18+ self-declaration above the Create Account button. Lays out inline
   (checkbox beside the sentence), unlike the uppercase column field labels. */
.auth-form label.form-confirm-row {
  flex-direction: row;
  align-items: flex-start;
  gap: 8px;
  font-size: 0.85rem;
  font-weight: 400;
  text-transform: none;
  color: var(--ink);
  cursor: pointer;
}
.form-confirm-row input[type='checkbox'] {
  flex: none;
  width: 16px;
  height: 16px;
  margin: 2px 0 0;
  accent-color: var(--accent);
}

/* Loading state — visible by default, auto-hides as soon as any <main> on
   the page is revealed. Saves a flash of blank page on slow connections. */
.loading-state {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  background: var(--bg);
  z-index: 9999;
}
.loading-state p {
  border-top: 8px solid #16a085;
  color: var(--ink);
  font-size: 0.95rem;
  font-weight: 600;
  padding: 6px 24px;
}
body:has(main:not([hidden])) .loading-state {
  display: none;
}
/* Soccer-ball loader: gentle bounce with a full rotation per cycle. Per-
   keyframe timing makes the fall ease-in (gravity) and the rise ease-out
   (decelerating), which is how real balls move. */
.loading-ball {
  width: 44px;
  height: 44px;
  display: block;
  margin-bottom: -30px;
  animation: loading-ball-bounce 1s infinite;
  transform-origin: center center;
}
@keyframes loading-ball-bounce {
  0% {
    transform: translateY(-64px) rotate(0deg);
    animation-timing-function: cubic-bezier(0.55, 0, 0.9, 0.55);
  }
  50% {
    transform: translateY(0) rotate(180deg);
    animation-timing-function: cubic-bezier(0.1, 0.45, 0.45, 1);
  }
  100% {
    transform: translateY(-64px) rotate(360deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .loading-ball {
    animation: none;
  }
}
html.is-reduced-motion .loading-ball {
  animation: none;
}

.signin-dialog--split {
  width: min(94vw, 780px);
  max-height: 90dvh;
  padding: 0;
  overflow: auto;
  overscroll-behavior: contain;
}
/* Single-column variant (used by the About dialog). Same polished padding
   and Urbanist heading as .signin-copy in the split layout, but no second
   column. */
.signin-dialog--single {
  width: min(94vw, 560px);
  max-height: 90dvh;
  padding: 0;
  overflow: auto;
  overscroll-behavior: contain;
}
.signin-dialog--single .signin-copy {
  padding: 40px 36px;
}
@media (max-width: 720px) {
  .signin-dialog--single .signin-copy {
    padding: 32px 28px;
  }
}
.signin-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-content: center;
}
.signin-copy {
  padding: 40px 36px;
  background: var(--surface);
  display: flex;
  flex-direction: column;
  justify-content: center;
  border-right: 1px solid var(--border);
}
.signin-copy h2 {
  font-family: 'Nunito', sans-serif;
  font-weight: 700;
  font-size: 1.5rem;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 0 0 18px;
  line-height: 1.25;
}
.signin-copy p {
  margin: 0 0 14px;
  line-height: 1.55;
  color: var(--ink);
}
.signin-copy p:last-child {
  margin-bottom: 0;
}
.signin-copy-image {
  display: block;
  width: 100%;
  height: auto;
  margin-top: 24px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  box-shadow: 0 1px 3px rgba(9, 30, 66, 0.08);
}
.signin-split .signin-section {
  padding: 40px 36px;
}
.signin-images {
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: center;
  justify-content: center;
}
.signin-images img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 4px;
  border: 1px solid var(--border);
  box-shadow: 0 1px 3px rgba(9, 30, 66, 0.08);
}
@media (max-width: 720px) {
  .signin-dialog--split {
    width: min(94vw, 460px);
  }
  .signin-split {
    grid-template-columns: 1fr;
  }
  .signin-copy {
    padding: 32px 28px 8px;
  }
  .signin-copy h2 {
    font-size: 1.5rem;
  }
  .signin-split .signin-section {
    padding: 20px 28px 32px;
  }
  .signin-images {
    padding: 20px 28px 28px;
  }
}

/* Shared art panel for student dialogs (first-visit welcome + sign-in). Holds
   the transparent player illustration on a soft tinted backdrop, figures flush
   to the bottom edge rather than the bordered screenshot frame other dialogs
   use. */
.welcome-art {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px 16px 0;
  background: linear-gradient(180deg, #eef1f6 0%, #e1e7f0 100%);
}
.welcome-art img {
  display: block;
  width: auto;
  max-width: 100%;
  max-height: 340px;
  height: auto;
}
.student-welcome .welcome-steps {
  margin: 0 0 14px;
  padding-left: 1.2em;
}
.student-welcome .welcome-steps li {
  margin: 0 0 6px;
  line-height: 1.5;
  color: var(--ink);
}
.student-welcome .welcome-actions {
  margin-top: 22px;
}

/* Student sign-in (#signin-dialog student tab): art panel on the left, form on
   the right. Divider sits on the art's inner edge; the heading matches the
   .signin-copy heading used elsewhere. */
.student-codes .welcome-art {
  border-right: 1px solid var(--border);
  background: none;
}
.student-codes .signin-section h2 {
  font-family: 'Nunito', sans-serif;
  font-weight: 700;
  font-size: 1.5rem;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 0 0 18px;
  line-height: 1.25;
  /* Override the uppercase .signin-section h2 default; this is a sentence-case
     title, not an eyebrow label. */
  text-transform: none;
}
/* Inline parenthetical hint next to an uppercased field label
   ("Class code (finds your class)"). */
.form-hint {
  text-transform: none;
  font-weight: 400;
  letter-spacing: normal;
  color: var(--muted);
}
@media (max-width: 720px) {
  .welcome-art {
    padding: 16px 16px 0;
  }
  .welcome-art img {
    max-height: 240px;
  }
  .student-codes .welcome-art {
    border-right: 0;
    border-bottom: 1px solid var(--border);
  }
}

.hero {
  text-align: center;
  margin-bottom: 40px;
}
.hero h1 {
  font-size: 2rem;
  margin: 0 0 12px;
  letter-spacing: -0.02em;
}
.hero .lede {
  color: var(--muted);
  max-width: 640px;
  margin: 0 auto;
}

.entry-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 20px;
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 24px;
}

.card h2 {
  margin: 0 0 4px;
  font-size: 1.15rem;
}

/* Top-level role tabs on the sign-in dialog (Student / Teacher).
   Off-white strip with raised white tabs — the active tab merges into
   the white content panel below. */
.signin-role-tabs {
  display: flex;
  gap: 4px;
  padding: 14px 64px 0 20px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}
.signin-role-tab {
  background: transparent;
  border: 1px solid transparent;
  border-bottom: none;
  padding: 12px 22px 12px;
  margin-bottom: -1px;
  font-family: 'Nunito', sans-serif;
  font-size: 1rem;
  font-weight: 500;
  color: var(--muted);
  cursor: pointer;
  border-radius: 8px 8px 0 0;
  transition:
    background 0.15s ease,
    color 0.15s ease;
}
.signin-role-tab:hover {
  color: var(--ink);
}
.signin-role-tab.is-active {
  background: var(--surface);
  color: var(--ink);
  border-color: var(--border);
  font-weight: 600;
}
.signin-role-panel[hidden] {
  display: none;
}
/* All four sign-in states (Student / Teacher x Sign In / Create Account) settle
   to slightly different heights, so the dialog jumps as you switch tab or form.
   Pin a shared floor — the image-bearing copy column is the tallest part — so
   every state matches and nothing resizes. */
#signin-dialog .signin-role-panel {
  min-height: 560px;
}
/* "Start a League" is an explicit teacher action, so the I'm a Student / I'm a
   Teacher switcher is redundant there — hide it and let the teacher panel fill
   the dialog top. Only the ambiguous "Sign In" entry shows the role tabs. */
.signin-dialog--no-roles .signin-role-tabs {
  display: none;
}
@media (max-width: 720px) {
  .signin-role-tabs {
    padding: 12px 56px 0 12px;
  }
  .signin-role-tab {
    font-size: 0.92rem;
    padding: 10px 16px;
  }
}

.tabs {
  display: flex;
  gap: 4px;
  margin: 16px 0 12px;
  border-bottom: 1px solid var(--border);
}
.tab {
  background: none;
  border: none;
  padding: 8px 12px;
  cursor: pointer;
  color: var(--muted);
  border-bottom: 2px solid transparent;
  font: inherit;
}
.tab.is-active {
  color: var(--ink);
  border-bottom-color: var(--accent);
}

.auth-form {
  display: none;
  flex-direction: column;
  gap: 12px;
}
.auth-form.is-active {
  display: flex;
}
#contact-info {
  text-align: center;
  background-color: var(--gold);
  padding: 4px;
  border-radius: 3px;
  color: #111;
}
#contact-info:empty {
  display: none;
}

.auth-form.is-active button {
  margin-top: 12px;
}
.auth-link {
  align-self: center;

  text-align: center;
  background: none;
  border: none;
  padding: 4px 0 0;
  margin-top: 4px !important;
  font-family: 'Urbanist', sans-serif;
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.auth-link:hover {
  color: var(--ink);
}
.auth-resend {
  background: none;
  border: none;
  padding: 8px 0 0;
  margin: 4px 0 0;
  font: inherit;
  font-size: 0.9rem;
  color: var(--muted);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-align: left;
  transition: color 0.15s ease;
}
.auth-resend:hover {
  color: var(--ink);
}
.auth-resend:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.auth-form label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.7rem;
  color: var(--muted);
  font-weight: 600;
  text-transform: uppercase;
}

.auth-form label:first-of-type {
  margin-top: 12px;
}
.auth-form input {
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  font-size: 1rem;
  font-weight: 400;
}
.auth-form input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
/* Student code fields in monospace so what they type matches the printed slip
   and l/1/I, 0/O can't be confused. */
#student-form input {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: 0.03em;
}

button.primary {
  background: var(--accent);
  color: var(--accent-ink);
  border: none;
  padding: 10px 14px;
  border-radius: var(--radius-md);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  transition:
    filter 0.15s ease,
    transform 0.15s ease,
    box-shadow 0.15s ease;
}
button.primary:hover {
  filter: brightness(1.05);
  transform: translateY(-1px);
  box-shadow: 0 4px 10px rgba(17, 24, 39, 0.18);
}
button.primary:active:not(:disabled) {
  transform: translateY(0);
  box-shadow: none;
}
button.primary:disabled,
button.primary.is-disabled {
  background: var(--border);
  color: var(--muted);
  cursor: not-allowed;
}
button.primary:disabled:hover,
button.primary.is-disabled:hover {
  filter: none;
}

button.secondary {
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--border);
  padding: 10px 14px;
  border-radius: var(--radius-md);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    background 0.15s ease;
}
button.secondary:hover {
  border-color: var(--ink);
  background: var(--bg);
}

button.danger {
  background: var(--error);
  color: #fff;
  border: none;
  padding: 10px 14px;
  border-radius: var(--radius-md);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
button.danger:hover {
  filter: brightness(1.05);
}

.dialog-actions {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

.dialog-actions button {
  min-width: 40%;
}
/* A lone button looks stranded next to the space-between gap — stretch it
   full width. Automatic, so single-button dialogs (including the JS-rendered
   messageDialog) never need a manual class. */
.dialog-actions button:only-child {
  width: 100%;
}

/* Text-input dialog (promptDialog) — mirrors .auth-form field styling without
   the display:none toggle that class carries. */
.dialog-form {
  display: flex;
  flex-direction: column;
  gap: 6px;
  text-align: left;
}
.dialog-form label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.7rem;
  color: var(--muted);
  font-weight: 600;
  text-transform: uppercase;
}
.dialog-form input {
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font: inherit;
  font-size: 1rem;
  font-weight: 400;
  color: var(--ink);
  background: var(--surface);
}
.dialog-form input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.reset-season-option {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
  font-size: 0.95rem;
  color: var(--ink);
  cursor: pointer;
}
.reset-season-option input {
  width: 16px;
  height: 16px;
  cursor: pointer;
}

button:where(:not(.primary)):where(:not(.tab)) {
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--border);
  padding: 6px 10px;
  border-radius: var(--radius-md);
  font: inherit;
  cursor: pointer;
}

.error {
  font-family: 'Urbanist', sans-serif;
  color: var(--error);
  min-height: 1.2em;
  margin: 8px 0 0;
  font-size: 0.9rem;
  font-weight: 700;
  text-align: center;
  text-wrap: balance;
}

.dashboard {
  max-width: 1040px;
  margin: 0 auto;
  padding: 32px 24px;
}

/* ----- Page-level tab nav ----- */
.tabs-main {
  display: flex;
  gap: 4px;
  margin-bottom: 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 6px;
  box-shadow: var(--shadow);
  flex-wrap: wrap;
}
/* The `display: flex` rule above overrides the user-agent's [hidden] display:none.
   Re-assert it for the hidden attribute to do its job. Same below for sub-tabs. */
.tabs-main[hidden],
.tabs-sub[hidden] {
  display: none;
}
.tab-main {
  flex: 1 1 auto;
  background: transparent;
  border: none;
  padding: 8px 14px;
  border-radius: var(--radius-sm);
  font: inherit;
  font-weight: 600;
  font-size: 0.92rem;
  color: var(--muted);
  cursor: pointer;
  transition:
    background 0.1s,
    color 0.1s;
}
.tab-main:hover {
  color: var(--ink);
}
.tab-main.is-active {
  background: var(--accent);
  color: var(--accent-ink);
}
.tab-main.is-active:hover {
  color: var(--accent-ink);
}

/* ----- Sub-tab nav (used inside the League tab) ----- */
/* Sits in its own pill-panel like the main tabs, but with section-label-style
   text (small uppercase) and a light yellow active state so it reads as a
   secondary filter row, not competing with the main green-on-active tabs. */
.tabs-sub {
  display: flex;
  gap: 4px;
  margin-bottom: 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 6px;
  box-shadow: var(--shadow);
  flex-wrap: wrap;
}
.tab-sub {
  flex: 1 1 auto;
  background: transparent;
  border: none;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font: inherit;
  font-family: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  transition:
    background 0.1s,
    color 0.1s;
}
.tab-sub:hover {
  color: var(--ink);
}
.tab-sub.is-active {
  background: #fde68a;
  color: var(--ink);
  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}

.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 20px;
  margin-bottom: 20px;
}

/* ============================================================
   MICRO-INTERACTION PROTOTYPE — tactile press + tab entrance
   Lifting the "flat" feel without resorting to UI sound. Two parts:
   1. A quick scale-down on press so buttons feel physical on touch
      as well as mouse — the existing :active states only read as the
      release of a hover lift, which a touchscreen never sees. The
      run-slot buttons keep their richer id-based press (id > class).
   2. A soft rise + fade as each main tab panel appears, so switching
      tabs is a transition rather than a hard cut. It fires on tab
      change and first paint only, not on live data re-renders (the
      .panel elements persist; only their contents update).
   All transforms are GPU-only and disabled under reduced motion.
   Delete this whole block to revert.
   ============================================================ */
button.secondary,
button.danger {
  /* These had no transform in their transition, so add one to ease the press. */
  transition:
    border-color 0.15s ease,
    background 0.15s ease,
    filter 0.15s ease,
    transform 0.12s ease;
}
.tab-main,
.tab-sub {
  transition:
    background 0.1s,
    color 0.1s,
    transform 0.1s ease;
}
button.secondary:active:not(:disabled),
button.danger:active:not(:disabled) {
  transform: scale(0.96);
}
.tab-main:active:not(.is-active),
.tab-sub:active:not(.is-active) {
  transform: scale(0.97);
}
.panel[data-tab-panel]:not([hidden]) {
  animation: tab-panel-in 0.2s ease both;
}
@keyframes tab-panel-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
html.is-reduced-motion button.secondary:active:not(:disabled),
html.is-reduced-motion button.danger:active:not(:disabled),
html.is-reduced-motion .tab-main:active,
html.is-reduced-motion .tab-sub:active {
  transform: none;
}
html.is-reduced-motion .panel[data-tab-panel]:not([hidden]) {
  animation: none;
}

/* ---- Raised action buttons ----
   Give the prominent action buttons the run-slot's physical layered shadow so
   they read as raised at rest, and on touch where there's no hover to lift them.
   Lift on hover, press into the surface on click. The quiet .replay-skip "Skip"
   state and the lower-tier secondary/danger buttons deliberately stay flat. The
   run-slot buttons keep their own id-based hover/press (higher specificity), on
   the same shared tokens. */
button.primary,
.btn-gold,
.replay-skip.is-done,
.replay-skip.is-kickoff {
  box-shadow: var(--btn-raise);
  transition:
    filter 0.15s ease,
    transform 0.12s ease,
    box-shadow 0.15s ease;
}
button.primary:hover:not(:disabled),
.btn-gold:hover:not(:disabled),
.replay-skip.is-done:hover,
.replay-skip.is-kickoff:hover {
  transform: translateY(-1px);
  filter: brightness(1.04);
  box-shadow: var(--btn-raise-hover);
}
button.primary:active:not(:disabled),
.btn-gold:active:not(:disabled),
.replay-skip.is-done:active,
.replay-skip.is-kickoff:active {
  transform: translateY(1px);
  filter: brightness(0.99);
  box-shadow: var(--btn-raise-press);
}
button.primary:disabled,
button.primary.is-disabled {
  box-shadow: none;
}
html.is-reduced-motion button.primary:hover:not(:disabled),
html.is-reduced-motion .btn-gold:hover:not(:disabled),
html.is-reduced-motion .replay-skip.is-done:hover,
html.is-reduced-motion .replay-skip.is-kickoff:hover,
html.is-reduced-motion button.primary:active:not(:disabled),
html.is-reduced-motion .btn-gold:active:not(:disabled),
html.is-reduced-motion .replay-skip.is-done:active,
html.is-reduced-motion .replay-skip.is-kickoff:active {
  transform: none;
}

/* Persistent Run Matchday bar pinned to the bottom of the viewport so the
   teacher's primary action is always one click away, on any tab. */
/* Guiding copy beneath the fixtures — explains the run loop and warns when
   teams aren't built yet. A quiet, right-aligned footnote under a separator,
   so it informs without competing with the green Run Matchday button above. */
.run-helper {
  margin: 24px 0 0;
  padding-top: 24px;
  padding-bottom: 6px;
  border-top: 1px solid var(--border);
  text-align: center;
  color: var(--muted);
  font-size: 0.9rem;
  font-weight: 300;
}
.run-helper strong {
  color: var(--ink);
}
/* Mirrors button.secondary (the quiet button), but applied to the <a>. Centred
   as a shrink-to-fit block beneath the run helper. */
.run-helper-link {
  display: block;
  width: fit-content;
  margin: 12px auto 0;
  padding: 8px 16px;
  background: var(--surface);
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font-size: 0.9rem;
  font-weight: 600;
  text-decoration: none;
  transition:
    border-color 0.15s ease,
    background 0.15s ease;
}
.run-helper-link:hover {
  border-color: var(--ink);
  background: var(--bg);
}

/* Subtle fade when a tab or subtab panel becomes visible. Re-fires every time
   the `hidden` attribute is toggled off, which is how the tab JS swaps panels. */
[data-tab-panel]:not([hidden]),
[data-subtab-panel]:not([hidden]) {
  animation: panelIn 0.14s ease-out;
}
@keyframes panelIn {
  from {
    opacity: 0;
    transform: translateY(3px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
@media (prefers-reduced-motion: reduce) {
  [data-tab-panel]:not([hidden]),
  [data-subtab-panel]:not([hidden]) {
    animation: none;
  }
}
html.is-reduced-motion [data-tab-panel]:not([hidden]),
html.is-reduced-motion [data-subtab-panel]:not([hidden]) {
  animation: none;
}

.panel h2 {
  margin: 0 0 12px;
  font-size: 1.05rem;
}

/* ----- League picker (teacher first-touch / re-entry) ----- */
/* Picker is its own page-level surface — hide the global site header
   so the picker hero acts as the title. */
body.is-picker .site-header {
  display: none;
}
/* :not([hidden]) so display:flex doesn't override the HTML hidden attribute
   when the page navigates from picker to dashboard. */
.league-picker:not([hidden]) {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  padding: 80px 24px 64px;
  min-height: 100vh;
  width: 100%;
  max-width: 520px;
  margin: 0 auto;
  box-sizing: border-box;
}
.picker-header {
  text-align: center;
  margin-bottom: 40px;
}
.picker-title {
  font-family: 'Urbanist', sans-serif;
  font-weight: 900;
  font-size: clamp(2.4rem, 5vw, 3.6rem);
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 0 0 12px;
}
.picker-subline {
  margin: 0;
  font-size: 1.05rem;
  color: var(--muted);
  line-height: 1.5;
}
.picker-view {
  width: 100%;
}
.picker-view .picker-action-btn {
  width: 100%;
}
.picker-leagues {
  list-style: none;
  margin: 0 0 18px;
  padding: 0;
  display: flex;
  flex-direction: column;
}
.picker-leagues li {
  display: flex;
  align-items: stretch;
  border-bottom: 1px solid var(--border);
}
.picker-leagues li:first-child {
  border-top: 1px solid var(--border);
}
.picker-leagues .league-open {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  padding: 14px 4px;
  text-decoration: none;
  color: var(--ink);
  transition:
    padding 0.15s ease,
    color 0.15s ease;
}
.picker-leagues .league-code-sub {
  font-family: 'Courier New', monospace;
  font-size: 0.78rem;
  color: var(--muted);
  margin-top: 2px;
}
.picker-leagues .league-open:hover {
  padding-left: 8px;
}
.picker-leagues .league-name {
  font-family: 'Nunito', sans-serif;
  font-size: 1.15rem;
  color: var(--ink);
}
.class-code-line {
  margin: 0 0 12px;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 0.95rem;
  color: var(--muted);
}
.class-code-line strong {
  font-family: 'Courier New', monospace;
  font-size: 1rem;
  color: var(--ink);
  letter-spacing: 0.02em;
}
.class-code-hint {
  font-size: 0.82rem;
  color: var(--muted);
}
.admin-code {
  font-family: 'Courier New', monospace;
  font-size: 0.78rem;
}
.picker-leagues .league-delete {
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  padding: 8px 10px;
  margin: 4px 0;
  border-radius: var(--radius-sm);
  color: var(--muted);
  cursor: pointer;
  transition:
    color 0.15s ease,
    background 0.15s ease;
}
.picker-leagues .league-delete:hover {
  color: var(--error);
  background: rgba(185, 28, 28, 0.08);
}
.picker-leagues .league-delete:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.picker-action-btn {
  background: var(--bg);
  border: 1px solid var(--ink);
  border-radius: var(--radius-sm);
  padding: 12px 22px;
  font: inherit;
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--ink);
  cursor: pointer;
  transition:
    background 0.15s ease,
    color 0.15s ease;
  margin-top: 16px;
}
.picker-action-btn:hover {
  background: var(--ink);
  color: var(--surface);
}
/* The welcome screen's only action is the primary affirmative step, so it takes
   the brand green rather than the neutral outline — whose near-black hover read
   as an error. The returning-teacher list keeps the outline: there the primary
   action is opening an existing class, so create stays secondary. */
#picker-welcome-view .picker-action-btn {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  transition:
    filter 0.15s ease,
    transform 0.15s ease,
    box-shadow 0.15s ease;
}
#picker-welcome-view .picker-action-btn:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  filter: brightness(1.05);
  transform: translateY(-1px);
  box-shadow: 0 4px 10px rgba(17, 24, 39, 0.18);
}
.picker-welcome-img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  box-shadow: 0 1px 3px rgba(9, 30, 66, 0.08);
  margin: 0 0 20px;
}
.picker-welcome-copy {
  margin: 0 0 16px;
  color: var(--ink);
  line-height: 1.6;
  font-size: 1rem;
}
.picker-welcome-copy + .picker-action-btn {
  margin-top: 16px;
}
/* ----- Wizard steps ----- */
/* :not([hidden]) so display:flex doesn't override the HTML hidden attribute. */
.picker-wizard:not([hidden]) {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.picker-step-label {
  margin: 0;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--muted);
}
.picker-wizard-heading {
  font-family: 'Urbanist', sans-serif;
  font-weight: 800;
  font-size: 1.6rem;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 0;
}
.picker-wizard-help {
  margin: 0;
  font-size: 0.95rem;
  color: var(--muted);
  line-height: 1.5;
}
.picker-wizard input[type='text'],
.picker-wizard textarea {
  width: 100%;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font: inherit;
  font-size: 1rem;
  background: var(--surface);
  color: var(--ink);
  transition:
    border-color 0.15s ease,
    box-shadow 0.15s ease;
  box-sizing: border-box;
}
.picker-wizard textarea {
  resize: vertical;
  min-height: 160px;
  font-family: inherit;
  line-height: 1.5;
}
.picker-wizard input[type='text']::placeholder,
.picker-wizard textarea::placeholder {
  color: var(--muted);
}
.picker-wizard input[type='text']:focus,
.picker-wizard textarea:focus {
  outline: none;
  border-color: var(--ink);
  box-shadow: 0 0 0 3px rgba(17, 24, 39, 0.08);
}
.picker-wizard-error {
  margin: 0;
  font-size: 0.9rem;
  color: var(--error);
}
.picker-wizard-preview {
  margin: -4px 0 0;
  font-size: 0.85rem;
}
.picker-wizard-roster-count {
  margin: -4px 0 0;
  font-size: 0.85rem;
  text-align: right;
}
.picker-wizard-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 8px;
}
.picker-back-btn {
  background: none;
  border: none;
  padding: 8px 4px;
  font: inherit;
  font-size: 0.95rem;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s ease;
}
.picker-back-btn:hover {
  color: var(--ink);
}
.picker-next-btn {
  padding: 14px 28px;
  font-size: 1rem;
  font-weight: 700;
  border-radius: var(--radius-pill);
}
/* Sign-out lives in the same top-right slot as the homepage's Sign In, using
   the shared .nav-link styling. Only shown when the picker is active. */
.picker-top-nav {
  display: none;
}
body.is-picker .picker-top-nav {
  display: flex;
}
/* Top-left Privacy/Terms — reuses .landing-top-nav-left styling but gated to the
   picker view (mirrors .picker-top-nav so it never shows on the dashboard). */
.picker-top-nav-left {
  display: none;
}
body.is-picker .picker-top-nav-left {
  display: flex;
}
@media (max-width: 720px) {
  .league-picker {
    padding: 48px 16px 48px;
  }
  .picker-header {
    margin-bottom: 28px;
  }
}

code {
  background: #eef0f3;
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 0.85em;
}

/* ----- Squad builder ----- */

.name-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
}
.name-form label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--ink);
}
.name-form input {
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font: inherit;
  font-weight: normal;
  color: var(--ink);
  background: var(--surface);
}
.name-form input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.team-name-form {
  display: flex;
  gap: 8px;
  align-items: center;
}
.team-name-form input {
  flex: 1;
  min-width: 0;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font: inherit;
  font-weight: normal;
  color: var(--ink);
  background: var(--surface);
}
.team-name-form input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.surprise-me-btn {
  flex-shrink: 0;
  padding: 9px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg);
  font: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    background 0.15s ease;
}
.surprise-me-btn:hover {
  border-color: var(--accent);
  background: var(--surface);
}

.formation-picker {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 12px;
}

.formation-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  background: var(--bg);
  border: 2px solid var(--border);
  border-radius: var(--radius);
  padding: 14px;
  cursor: pointer;
  font: inherit;
  color: var(--ink);
  transform: scale(0.95);
  opacity: 0.8;
  transition:
    border-color 0.1s,
    transform 0.1s;
}
.formation-card:hover {
  border-color: var(--accent);
}
.formation-card.is-active {
  border-color: var(--accent);
  background: #fff;
  transform: scale(1);
  opacity: 1;
}
.formation-name {
  font-weight: 700;
}
.formation-shape {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--accent);
  font-size: 0.95rem;
  margin: 4px 0;
}
.formation-shape-img {
  display: block;
  width: 100%;
  max-width: 180px;
  height: auto;
  margin: 8px auto;
  border-radius: var(--radius-sm);
  object-fit: contain;
}
.formation-desc {
  color: var(--muted);
  font-size: 0.85rem;
  font-weight: 100;
}

.budget {
  display: flex;
  gap: 12px;
  align-items: center;
  margin-bottom: 12px;
  font-size: 0.95rem;
}
.budget-stars {
  display: inline-flex;
  gap: 3px;
  font-size: 1.4rem;
  line-height: 1;
}
.budget-star {
  color: var(--border);
}
.budget-star.is-filled {
  color: var(--warning);
}

.slots {
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: center;
  padding: 8px 8px;
  background: rgba(0, 0, 0, 0.05);
  border-radius: var(--radius);
  border-top: 1px solid rgba(0, 0, 0, 0.1);
  border-bottom: 1px solid #fff;
}
.slot-row {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 12px;
  width: 100%;
  max-width: 1124px;
  margin: 0 auto;
  justify-content: center;
}
.slot {
  position: relative;
  background: var(--surface);
  border-radius: var(--radius);
  cursor: pointer;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition:
    box-shadow 0.1s,
    transform 0.08s;
}

.slot.is-empty {
  min-height: 270px;
  border: 2px dashed var(--border);
  padding: 10px;
  align-items: center;
  justify-content: center;
  text-align: center;
}
.slot.is-empty:hover {
  border-color: var(--accent);
}

.slot.is-filled {
  border: 1px solid var(--border);
  border-top: 4px solid var(--club-color, var(--border));
}
.slot.is-filled:hover {
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08);
}

.slot.is-selected {
  box-shadow: 0 0 0 3px var(--accent);
}

.slot-pos {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--muted);
}
.slot-prompt {
  color: var(--muted);
  font-size: 0.85rem;
  margin-top: 6px;
}

.slot.is-filled .player-info {
  padding: 8px 10px;
}
.slot.is-filled .player-name {
  font-size: 0.85rem;
  margin-bottom: 4px;
}
.slot.is-filled .player-card-club,
.slot.is-filled .player-sub {
  font-size: 0.72rem;
}

.slot-remove {
  position: absolute;
  bottom: 6px;
  right: 6px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.92);
  color: var(--ink);
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  padding: 0;
  z-index: 2;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}
.slot-remove:hover {
  background: var(--error);
  color: white;
}

/* On a confirmed team with trades left, a full-width "Trade out" button sits at
   the foot of each card — far clearer than the old corner icon. The .slot is a
   flex column, so the button stretches to the card width on its own. */
.slot-trade-btn {
  border: none;
  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
  background: var(--gold);
  color: var(--ink);
  font: inherit;
  font-weight: 700;
  font-size: 0.75rem;
  text-transform: uppercase;
  padding: 9px;
  cursor: pointer;
  transition: background 0.12s ease;
  width: 90%;
  margin: auto;
  margin-bottom: 9px;
}
.slot-trade-btn:hover {
  filter: brightness(1.1);
}

.filter-row {
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.position-filter {
  display: flex;
  gap: 4px;
}
.pos-btn {
  background: var(--bg);
  border: 1px solid var(--border);
  padding: 6px 12px;
  border-radius: var(--radius-pill);
  cursor: pointer;
  font: inherit;
  font-size: 0.85rem;
  color: var(--ink);
}
.pos-btn.is-active {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
}

.player-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 12px;
}

.player-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: 4px solid var(--club-color, var(--border));
  border-radius: var(--radius);
  cursor: pointer;
  overflow: hidden;
  transition:
    transform 0.08s,
    box-shadow 0.08s;
}
.player-card:hover:not(.is-disabled) {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.player-card.is-disabled {
  opacity: 0.55;
}

/* The square ratio lives on the <img>, not this box. Driving the height from
   the box's aspect-ratio trips a WebKit bug: while sizing a stretched grid/flex
   cell Safari miscomputes this box's intrinsic height, inflating the row so the
   cards stretch tall with a white gap below the stats. A replaced element sizes
   reliably, so the portrait carries the 1/1 ratio and the box follows it. */
.player-card-photo {
  position: relative;
  background: var(--surface);
  overflow: hidden;
  isolation: isolate;
}

.player-portrait {
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  display: block;
}

.player-card-stars {
  position: absolute;
  top: 8px;
  left: 8px;
  background: rgba(255, 255, 255, 0.92);
  color: var(--warning);
  font-weight: 700;
  font-size: 0.9rem;
  padding: 3px 7px;
  border-radius: 4px;
  z-index: 2;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
  letter-spacing: 0.04em;
  line-height: 1;
}

.player-card-pos {
  position: absolute;
  top: 8px;
  right: 8px;
  background: rgba(255, 255, 255, 0.92);
  color: var(--ink);
  font-weight: 700;
  font-size: 0.7rem;
  padding: 4px 7px;
  border-radius: 4px;
  z-index: 2;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
  letter-spacing: 0.06em;
  line-height: 1;
}

.player-info {
  background: var(--surface);
  padding: 10px 12px;
  border-top: 1px solid var(--border);
}

.player-name {
  font-weight: 700;
  font-size: 0.95rem;
  line-height: 1.2;
  margin-bottom: 6px;
}

.player-pos {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 6px;
  font-weight: 600;
}

.player-card-club {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--muted);
  margin-bottom: 2px;
}

.player-sub {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 0.75rem;
  color: var(--muted);
}

.player-reason {
  position: absolute;
  bottom: 6px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 0.7rem;
  font-weight: 600;
  color: white;
  background: rgba(15, 23, 42, 0.72);
  padding: 3px 8px;
  border-radius: 4px;
  z-index: 3;
  white-space: nowrap;
}

.favourite-detail-star .player-card {
  max-width: 200px;
  margin: 0 auto;
}

.actions:not([hidden]) {
  display: flex;
  gap: 12px;
  align-items: center;
}
#actions-panel {
  margin-top: 20px;
}
#actions-panel #save {
  margin-left: auto;
}
#save-status {
  font-size: 0.9rem;
}
#save-status.error {
  color: var(--error);
}

.badge-tiny {
  width: 14px;
  height: 14px;
  object-fit: contain;
}

.badge-medium {
  width: 24px;
  height: 24px;
  object-fit: contain;
}

.stat-bars {
  padding: 8px 20px 20px;
}
.stat-row {
  display: grid;
  grid-template-columns: 78px 1fr 22px;
  gap: 10px;
  align-items: center;
  margin-bottom: 8px;
  font-size: 0.9rem;
}
.stat-label {
  color: var(--muted);
  font-size: 0.85rem;
}
.stat-segs {
  display: flex;
  gap: 3px;
}
.stat-seg {
  flex: 1 1 0;
  height: 10px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 2px;
}
.stat-seg.is-filled {
  background: var(--accent);
  border-color: var(--accent);
}
.stat-value {
  font-weight: 700;
  text-align: right;
  font-size: 0.9rem;
}

/* ----- Flags ----- */

.flag {
  display: inline-block;
  height: 12px;
  width: auto;
  vertical-align: -1px;
  margin-right: 4px;
}

/* ----- Icons (assets/icons via the icon() helper) ----- */
/* Monochrome icons inline as <svg fill="currentColor"> and inherit text
   colour; colour event icons come in as <img>. Both size to 1em by default
   so they scale with whatever text they sit beside. */
.icon {
  display: inline-block;
  width: 1em;
  height: 1em;
  vertical-align: -0.125em;
  flex: none;
}

/* ----- Favourite club picker ----- */

.favourite-picker {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}
@media (max-width: 560px) {
  .favourite-picker {
    grid-template-columns: 1fr;
  }
}

.favourite-card {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 14px;
  background: var(--bg);
  border: 3px solid var(--club-color);
  border-radius: var(--radius);
  overflow: hidden;
  font: inherit;
  color: var(--ink);
  text-align: left;
}
.favourite-card-top {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 16px;
  padding: 16px 16px 0;
}
.favourite-card-stadium-row {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: 12px;
  align-items: stretch;
  padding: 12px 16px 0;
  border-top: 1px solid var(--border);
  margin-top: 0;
}
.favourite-card-location {
  display: flex;
  flex-direction: column;
  justify-content: center;
  font-size: 0.78rem;
  color: var(--muted);
  line-height: 1.4;
}
.favourite-card-location strong {
  color: var(--ink);
  font-weight: 600;
}
.favourite-card-stadium-info {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}
.favourite-card-stadium-info:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}
.favourite-card-label {
  display: block;
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
  color: var(--muted);
  margin-bottom: 2px;
}
.favourite-card-stadium-info > div {
  color: var(--ink);
  font-weight: 500;
}
.favourite-card-star-pos {
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin-left: 4px;
}

/* ----- Favourite confirm overlay ----- */

.favourite-confirm {
  padding: 28px 24px 20px;
  text-align: center;
  background: var(--surface);
  border-top: 4px solid var(--club-color, var(--accent));
  border-radius: var(--radius-lg);
}
.favourite-confirm-badge {
  width: 88px;
  height: 88px;
  object-fit: contain;
  margin-bottom: 14px;
}
.favourite-confirm-title {
  margin: 0 0 6px;
  font-size: 1.2rem;
  letter-spacing: -0.01em;
}
.favourite-confirm-actions {
  display: flex;
  gap: 12px;
  justify-content: center;
  margin-top: 36px;
}
.favourite-confirm-actions .primary {
  background: var(--club-color, var(--accent));
}
.favourite-card-stadium-image {
  border-radius: var(--radius-sm);
  overflow: hidden;
  box-shadow:
    var(--tint-row-cool) 0px 0px 0px 1px,
    rgba(42, 51, 69, 0.04) 0px 1px 1px -0.5px,
    var(--tint-row) 0px 3px 3px -1.5px,
    var(--tint-row) 0px 6px 6px -3px,
    var(--tint-row-cool) 0px 12px 12px -6px,
    var(--tint-row-cool) 0px 24px 24px -12px;
}
.favourite-card-stadium-image img {
  width: 100%;
  height: auto;
  display: block;
}
.favourite-card-footer {
  background: var(--club-color, var(--accent));
  padding: 12px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.favourite-card-motto {
  color: #fff;
  font-size: 0.8rem;
  flex: 1 1 auto;
  min-width: 0;
  text-transform: uppercase;
  font-weight: 900;
}
.favourite-card-pledge {
  background: white;
  color: var(--ink);
  border: none;
  padding: 8px 18px;
  border-radius: var(--radius-sm);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
  flex: 0 0 auto;
  transition:
    filter 0.1s,
    transform 0.08s;
}
.favourite-card-pledge:hover {
  filter: brightness(0.97);
  transform: translateY(-1px);
}
.favourite-card-left {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 0 0 auto;
  text-align: center;
  width: 160px;
}
.favourite-card-right {
  flex: 1 1 auto;
  min-width: 0;
}
.favourite-card-badge {
  width: 140px;
  height: 140px;
  object-fit: contain;
}
.favourite-card-name {
  font-weight: 900;
  font-size: 2rem;
  line-height: 1.15;
  letter-spacing: -0.01em;
  margin-bottom: 10px;
}
.favourite-card-identity {
  color: var(--muted);
  font-size: 0.7rem;
  line-height: 1.3;
  text-transform: uppercase;
}

.favourite-card-rival {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px dashed var(--border);
  font-size: 0.78rem;
  color: var(--ink);
}
.favourite-card-rival-label {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.62rem;
  font-weight: 700;
  color: var(--warning-strong);
  margin-right: 2px;
}

/* ----- Favourite detail (preview before pledging) ----- */

.favourite-detail {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow);
}

.favourite-detail-hero {
  display: grid;
  grid-template-columns: minmax(160px, 1fr) 1.5fr;
  border-bottom: 1px solid #eee;
}

.favourite-detail-badge-pane {
  background: var(--surface);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 12px;
  text-align: center;
}

.favourite-detail-badge {
  width: 100%;
  max-width: 140px;
  height: auto;
  object-fit: contain;
  display: block;
  margin-bottom: 6px;
}

.favourite-detail-badge-pane .favourite-detail-name {
  font-size: 1.5rem;
  margin: 4px 0 0;
  letter-spacing: -0.01em;
  line-height: 1.2;
  font-weight: 700;
}
.favourite-detail-badge-pane .favourite-detail-stadium-name {
  font-size: 0.95rem;
  font-weight: 600;
  margin: 0;
  margin-top: 6px;
}
.favourite-detail-badge-pane .favourite-detail-location {
  font-size: 0.85rem;
  color: var(--muted);
  margin: 0;
}

.favourite-detail-stadium {
  background: var(--surface);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}
.favourite-detail-stadium img {
  width: 92.5%;
  height: 92.5%;
  object-fit: cover;
  display: block;
  border: 6px solid #eee;
  border-radius: 3px;
  box-shadow:
    rgba(9, 30, 66, 0.25) 0px 1px 1px,
    rgba(9, 30, 66, 0.13) 0px 0px 1px 1px;
}

.favourite-detail-body {
  padding: 22px 24px;
  background: var(--bg);
}

@media (max-width: 560px) {
  .favourite-detail-hero {
    grid-template-columns: 1fr;
  }
  .favourite-detail-badge-pane {
    border-right: none;
    border-bottom: 1px solid var(--border);
    padding: 18px;
  }
  .favourite-detail-badge {
    max-width: 100px;
  }
  .favourite-detail-stadium {
    aspect-ratio: 16 / 9;
  }
}
.favourite-detail-name {
  font-size: 1.4rem;
  margin: 0 0 4px;
  letter-spacing: -0.01em;
}
.favourite-detail-identity {
  font-style: italic;
  font-size: 1rem;
  color: var(--ink);
  border-left: 3px solid var(--club-color, var(--accent));
  padding: 4px 0 4px 14px;
  margin: 16px 0 18px;
}

.favourite-detail-rival {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  background: #fff8e6;
  border: 1px solid #fbbf24;
  border-radius: var(--radius-md);
  margin-bottom: 18px;
}
.favourite-detail-rival-label {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--warning-strong);
}
.favourite-detail-rival-club {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
}

.favourite-detail-star {
  margin: 18px 0 8px;
}
.favourite-detail-star h4 {
  margin: 0 0 10px;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}
.favourite-detail-description {
  margin: 10px 2px 0;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--muted);
}

.player-card.readonly {
  cursor: default;
}
.player-card.readonly:hover {
  transform: none;
  box-shadow: none;
}
/* TOP PLAYERS podium cards are read-only (no editing) but ARE clickable to open
   the player, like the student team overlay. Re-enable the pointer + subtle lift
   that .readonly suppresses, and cancel the generic [data-player-link] heading
   typography and green-text hover that would otherwise land on the whole card. */
.leader-podium-slot .player-card.readonly[data-player-link] {
  cursor: pointer;
  font-weight: normal;
  font-size: inherit;
  line-height: inherit;
  margin-bottom: 0;
}
.leader-podium-slot .player-card.readonly[data-player-link]:hover {
  color: inherit;
  transform: translateY(-2px);
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08);
}

.favourite-detail-actions {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
}
.favourite-detail-actions .primary {
  background: var(--club-color, var(--accent));
}
/* A lone action button would sit stranded at the left by the space-between
   gap — centre it instead. (cf. .dialog-actions button:only-child, which
   stretches; here we centre at content width.) */
.favourite-detail-actions button:only-child {
  margin-inline: auto;
}

/* ----- Inline player detail (replaces the modal) ----- */

.player-detail {
  display: grid;
  grid-template-columns: 240px 1fr;
  gap: 20px;
  padding: 20px;
  background: var(--surface);
  border-radius: var(--radius-lg);
}

.player-detail-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.player-detail-info {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
}

.player-detail-section {
  display: block;
  padding: 12px 14px;
  background: var(--bg);
  border: 1px solid rgba(0, 0, 0, 0.025);
  border-radius: var(--radius-md);
}
.player-detail-section .section-label {
  margin-bottom: 8px;
}
.picked-by-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.picked-by-pill {
  display: inline-block;
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  background: var(--surface);
  border: 1px solid var(--border);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink);
}
/* The pill's display:inline-block beats the UA stylesheet's [hidden] rule,
   so the capped extras need an explicit hide for the reveal to work. */
.picked-by-pill[hidden] {
  display: none;
}
/* The "+ N more" reveal is a button sharing the pill look; it only needs the
   button-default resets and a quieter tone than the names around it. */
button.picked-by-more {
  cursor: pointer;
  font-family: inherit;
  color: var(--muted);
}
button.picked-by-more:hover {
  color: var(--ink);
}

.player-detail-description {
  margin: 0;
  line-height: 1.5;
  font-size: 0.95rem;
}

.player-stat-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.stat-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  font-size: 0.85rem;
  color: var(--muted);
  line-height: 1.3;
}
.stat-chip-num {
  font-weight: 700;
  color: var(--text);
}
.stat-chip-label {
  color: var(--muted);
}
.player-season-total {
  margin-top: 8px;
  font-size: 0.9rem;
  color: var(--muted);
}
.player-season-total strong {
  color: var(--accent);
  font-size: 1.1rem;
  font-weight: 700;
}

.card-icon {
  display: inline-block;
  width: 8px;
  height: 11px;
  margin-left: 3px;
  border-radius: 1px;
  vertical-align: -1px;
  box-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.15);
}
.card-icon.card-yellow {
  background: #fbbf24;
}
.card-icon.card-red {
  background: var(--danger);
}

.player-detail-info .stat-bars {
  padding: 0;
}

.player-detail-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 12px;
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

.player-detail-actions-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

.player-detail-actions .primary {
  background: var(--club-color, var(--accent));
}

.player-detail-actions .primary:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.player-detail-status {
  font-size: 0.85rem;
  font-weight: 700;
  text-wrap: balance;
  text-align: center;
}

@media (max-width: 540px) {
  .player-detail {
    grid-template-columns: 1fr;
  }
}

/* ----- Modal overlay (dialog) ----- */

/* While the overlay is open, freeze the page so scrolling stays inside the
   modal (toggled by the showModal wrapper in student.js). */
html.overlay-open {
  overflow: hidden;
}

/* Lock the page while any modal dialog is open. overscroll-behavior alone only
   stops scroll chaining once a scrollable modal hits its edge; when the modal
   content fits (nothing to scroll), wheel/touch events fall straight through to
   the body. This freezes the background for every dialog, not just this one. */
html:has(dialog[open]) {
  overflow: hidden;
}
.overlay {
  border: none;
  padding: 0;
  background: transparent;
  width: min(92vw, 640px);
  /* dvh (with a vh fallback) tracks the *visible* viewport. Plain vh on iOS
     Safari measures the largest viewport (toolbars hidden), so the dialog could
     grow taller than the screen, never scroll, and push a floating footer off
     the bottom (bit the award bar on iPad landscape). */
  max-height: 90vh;
  max-height: 90dvh;
  overflow-y: auto;
  /* Keep a scroll that reaches the modal's top/bottom from chaining to the
     page behind it. */
  overscroll-behavior: contain;
  border-radius: var(--radius-lg);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3);
}

.overlay::backdrop {
  background: rgba(15, 23, 42, 0);
  animation: overlay-backdrop-in 0.22s ease-out forwards;
}

.overlay[open] {
  animation: overlay-in 0.22s cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes overlay-in {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.96);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

@keyframes overlay-backdrop-in {
  from {
    background: rgba(15, 23, 42, 0);
  }
  to {
    background: rgba(15, 23, 42, 0.55);
  }
}

#overlay-body {
  display: contents;
}

.overlay:has(.confirm-modal) {
  width: min(96vw, 960px);
}
.confirm-modal {
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: 28px 28px 24px;
}
.confirm-header {
  text-align: center;
  margin-bottom: 20px;
}
.confirm-eyebrow {
  margin: 0 0 4px;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.confirm-team-name {
  font-family: 'Urbanist', sans-serif;
  font-weight: 600;
  font-size: 3rem;
  margin: 0;
}
.confirm-players {
  display: flex;
  flex-wrap: nowrap;
  gap: 12px;
  justify-content: center;
  margin-bottom: 20px;
}
.confirm-players .player-card {
  flex: 1 1 0;
  max-width: 170px;
}
.confirm-actions {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
}
.confirm-actions .primary {
  margin-left: auto;
}

#slots-panel.is-locked .slot-remove {
  display: none;
}
#slots-panel.is-locked .slot {
  cursor: pointer;
}
#slots-panel.is-locked .step-num {
  display: none;
}
#slots-panel h1 {
  margin: 0 0 12px;
  font-size: 1.05rem;
}
#slots-panel.is-locked h1 {
  font-size: 2rem;
  margin-bottom: 16px;
}
/* Team name and Edit Team share one line, the action pushed to the right.
   margin-left:auto keeps the button right-aligned even when it wraps below
   the name on a narrow screen. The row owns the bottom spacing so the button
   sits centred against the heading rather than against its old margin. */
.slots-heading-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin-bottom: 16px;
}
#slots-panel .slots-heading-row h1 {
  margin: 0;
}
.edit-team-btn {
  margin-left: auto;
  flex: none;
}

/* ----- Trades (student) ----- */

/* The overlay itself is transparent and #overlay-body is display:contents, so
   each screen supplies its own panel (cf. .confirm-modal, .favourite-detail). */
.trade-flow {
  display: flex;
  flex-direction: column;
  gap: 18px;
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: 28px 28px 24px;
  /* Bound the panel so the candidate list (not the whole modal) scrolls; the
     header and Cancel row stay pinned. */
  max-height: 90vh;
}
.trade-flow-head,
.trade-flow-actions {
  flex-shrink: 0;
}
.trade-flow-head .trade-flow-title {
  margin: 0 0 6px;
  font-size: 1.4rem;
}
.trade-flow-head .section-label {
  margin-bottom: 8px;
}
/* Pure scroll wrapper around the .player-list grid (kept separate so the grid
   sizes its rows naturally — combining grid + scroll on one element mis-sized
   the aspect-ratio card photos). Grows into the panel's spare height; min-height:0
   lets this flex child shrink so it scrolls instead of pushing the panel taller. */
.trade-candidates {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* Don't let a scroll that reaches the top/bottom of the list chain on to the
     page behind the modal. */
  overscroll-behavior: contain;
}
.trade-card-season {
  margin-top: 4px;
  font-size: 0.78rem;
  color: var(--muted);
}
.trade-card-season strong {
  color: var(--accent);
  font-weight: 700;
}
.trade-card-formation {
  margin-top: 4px;
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.trade-flow-actions {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
.trade-flow-actions .primary {
  margin-left: auto;
}

.trade-swap {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 14px;
}
.trade-swap-side {
  position: relative;
}
.trade-swap-arrow {
  font-size: 1.6rem;
  color: var(--muted);
  text-align: center;
}
.trade-tag {
  position: absolute;
  top: -8px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 2px 10px;
  border-radius: 999px;
  color: white;
}
.trade-tag-out {
  background: var(--error);
}
.trade-tag-in {
  background: var(--accent);
}
.trade-budget {
  margin: 0;
  text-align: center;
  color: var(--muted);
  font-size: 0.9rem;
}
.trade-formation-note {
  margin: 0;
  text-align: center;
  font-weight: 600;
  padding: 10px 14px;
  background: color-mix(in srgb, var(--accent) 8%, var(--surface));
  border-radius: var(--radius-md);
}

/* ----- Transfer history timeline (student My Team) ----- */
/* The Trades section mirrors the Team total above it: label on the left, the
   stat (and the View-history button) hugging the right. */
.transfer-history {
  margin-top: 28px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
  text-align: right;
}
.transfer-history .section-label {
  text-align: left;
}
.trades-made {
  margin: 2px 0 0;
}
.trades-made strong {
  font-weight: 900;
  font-size: 1.6rem;
  color: var(--accent);
}
/* Small uppercase caption for a stat's unit ("PTS") or count ("2 REMAINING"). */
.stat-unit,
.trades-remaining {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
}
.trades-remaining {
  margin: 0;
}
.trades-made.is-spent strong {
  color: var(--muted);
}
/* History sits collapsed behind a View toggle, right-aligned beneath the stat;
   reset alignment inside so the expanded timeline reads left-to-right. */
.history-disclosure {
  text-align: left;
  margin-top: 10px;
}
.history-disclosure summary {
  list-style: none;
  cursor: pointer;
}
.history-disclosure summary::-webkit-details-marker {
  display: none;
}
.history-summary {
  display: flex;
  align-items: center;
  justify-content: flex-end;
}
/* Looks like a .secondary button, but the whole summary is the click target. */
.history-summary-toggle {
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--border);
  padding: 6px 16px;
  border-radius: var(--radius-md);
  font-weight: 600;
  font-size: 0.85rem;
  transition:
    border-color 0.15s ease,
    background 0.15s ease;
}
.history-disclosure summary:hover .history-summary-toggle {
  border-color: var(--ink);
  background: var(--bg);
}
.history-disclosure[open] .history-summary-show,
.history-disclosure:not([open]) .history-summary-hide {
  display: none;
}
.history-disclosure[open] .history-summary {
  margin-bottom: 14px;
}

.history-row {
  padding: 16px 0;
}
.history-row + .history-row {
  border-top: 1px dashed var(--border);
}
/* Matchday label sits as a title above the cards (not beside them). */
.history-row-label {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 12px;
  margin-bottom: 12px;
}
.history-row-when {
  font-weight: 700;
}
.history-row-tag {
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}
.history-row-formation {
  font-size: 0.78rem;
  color: var(--muted);
}
/* Each line-up reuses the team's .slots holder; here the cards are read-only,
   so drop the team's pointer/hover affordances. */
.history-slots .slot.is-filled {
  cursor: default;
}
.history-slots .slot.is-filled:hover {
  transform: none;
  box-shadow: none;
}
.history-slots .slot.is-in {
  box-shadow: rgba(0, 0, 0, 0.65) 0px 25px 20px -20px;
}
.history-slots .slot.is-in:hover {
  box-shadow: rgba(0, 0, 0, 0.65) 0px 25px 20px -20px;
}
/* IN badge sits inside the photo (the card clips overflow), centred between
   the stars and position badges that flank the top corners. */
.history-in-tag {
  position: absolute;
  top: 8px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--accent);
  color: white;
}
/* The "for you" total is the point of the row, so keep it in accent even
   though it's the only (and therefore :last-child) points row. */
.history-earned .slot-points-row:last-child strong {
  color: var(--accent);
  font-size: 1.05rem;
}

/* ----- Teacher: Transfers subtab (Class tab) ----- */
.transfers-empty {
  padding: 8px 0;
  text-align: center;
}
/* Trades as a compact, newest-first log grouped by matchday. */
.transfers-table-wrap {
  overflow-x: auto;
}
.transfers-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.95rem;
}
.transfers-table th {
  text-align: left;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  padding: 6px 12px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.transfers-table td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
/* Matchday separator row spanning the table. */
.transfers-group td {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  background: var(--bg);
  border-bottom: none;
  padding-top: 16px;
}
.transfers-mgr strong {
  display: block;
}
.transfers-mgr .muted {
  font-size: 0.85rem;
}
/* The outgoing player has left the team — fade them next to the bold incoming. */
.transfers-out .transfers-player-name {
  color: var(--muted);
  font-weight: 600;
}
/* Give-back is a rare correction, so the column is hidden until "Edit trades". */
.transfers-panel:not(.is-editing) .transfers-give-back-col {
  display: none;
}
.transfers-edit-bar {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
.transfers-edit-hint {
  flex: 1 1 280px;
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.4;
}
.transfers-player-name {
  font-weight: 700;
}
.transfers-player-club {
  display: block;
  font-size: 0.8rem;
}
.transfers-give-back {
  white-space: nowrap;
}

/* Shared eyebrow heading style for panel and sub-section titles. */
.section-label {
  display: block;
  font-family: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin: 0 0 24px;
}
.section-label.is-centered {
  text-align: center;
}

/* ----- Teacher: Settings subtab (Admin tab) ----- */
.settings-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.settings-item {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  padding: 18px 20px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.settings-item-text {
  flex: 1;
  min-width: 0;
}
.settings-item-text .section-label {
  margin-bottom: 6px;
}
.settings-item-text p {
  margin: 0;
}
.settings-item-action {
  flex: none;
}
.settings-item-action-stack {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.profile-email {
  word-break: break-all;
}
@media (max-width: 600px) {
  .settings-item {
    flex-direction: column;
    align-items: stretch;
  }
  .settings-item-action .secondary,
  .settings-item-action .danger {
    width: 100%;
  }
}

/* Quiet legal links below the settings cards — the dashboard equivalent of the
   homepage footer's Privacy/Terms pair. */
.settings-legal {
  margin: 16px 0 0;
  text-align: center;
  font-size: 0.85rem;
  color: var(--muted);
}
.settings-legal a {
  color: var(--muted);
  text-decoration: none;
}
.settings-legal a:hover {
  color: var(--ink);
  text-decoration: underline;
}

/* Simple toggle switch built around an invisible native checkbox so the
   control stays keyboard accessible. The track + thumb are drawn via the
   sibling span and the input's :checked state. */
.settings-toggle {
  display: inline-block;
  position: relative;
  cursor: pointer;
}
.settings-toggle input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.settings-toggle-track {
  display: block;
  width: 44px;
  height: 26px;
  border-radius: 999px;
  background: var(--border);
  position: relative;
  transition: background 0.15s ease;
}
.settings-toggle-track::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
  transition: transform 0.15s ease;
}
.settings-toggle input:checked + .settings-toggle-track {
  background: var(--accent);
}
.settings-toggle input:checked + .settings-toggle-track::after {
  transform: translateX(18px);
}
.settings-toggle input:focus-visible + .settings-toggle-track {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ----- Class roster (teacher Admin tab) ----- */
.roster-input {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font: inherit;
  font-size: 0.95rem;
  resize: vertical;
  background: var(--bg);
}
.roster-input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
/* Admin "Add student" zone — sits at the bottom of the Student teams panel. */
.admin-student-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
/* Add-student dialog input */
#add-student-dialog input {
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font: inherit;
  font-size: 1rem;
  background: var(--surface);
  color: var(--ink);
  margin-top: 8px;
  box-sizing: border-box;
}
#add-student-dialog input:focus {
  outline: none;
  border-color: var(--ink);
  box-shadow: 0 0 0 3px rgba(17, 24, 39, 0.08);
}
#add-student-status {
  margin: 8px 0 0;
  font-size: 0.9rem;
  color: var(--muted);
  min-height: 1.2em;
}
#add-student-status.error {
  color: var(--error);
}

/* ----- Print handout ----- */
.print-handout {
  display: none;
}
@media print {
  body * {
    visibility: hidden;
  }
  .print-handout,
  .print-handout * {
    visibility: visible;
  }
  .print-handout {
    display: block;
    position: absolute;
    inset: 0;
    padding: 16mm;
    background: white;
    color: black;
    font-family: 'Nunito', sans-serif;
  }
  .print-handout-header {
    text-align: center;
    margin-bottom: 12mm;
  }
  .print-handout-header h1 {
    font-family: 'Urbanist', sans-serif;
    font-size: 22pt;
    margin: 0 0 4mm;
    text-transform: uppercase;
    letter-spacing: 0.04em;
  }
  .print-handout-header p {
    font-size: 10pt;
    color: #555;
    margin: 0;
  }
  .print-ticket {
    border: none;
    border-bottom: 1px dashed #999;
    border-radius: 0;
    padding: 6mm 8mm;
    margin-bottom: 4mm;
    page-break-inside: avoid;
  }
  .print-ticket-name {
    font-family: 'Urbanist', sans-serif;
    font-size: 16pt;
    font-weight: 600;
    margin-bottom: 2mm;
  }
  .print-ticket-meta {
    display: flex;
    gap: 10mm;
    font-size: 10pt;
    margin-bottom: 2mm;
  }
  .print-ticket-url {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 9pt;
    color: #333;
    word-break: break-all;
  }
  /* Monospace the codes so students can't confuse l/1/I or 0/O when typing. */
  .print-code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    letter-spacing: 0.03em;
  }
}

.manager-block {
  display: none;
}
#slots-panel.is-locked .manager-block {
  display: block;
  padding-bottom: 14px;
}
.manager-row {
  display: flex;
  align-items: baseline;
  gap: 12px;
}
.manager-name {
  font-family: 'Urbanist', sans-serif;
  font-weight: 600;
  font-size: 1.4rem;
}
.manager-points {
  margin-left: auto;
  font-size: 0.95rem;
  color: var(--muted);
}
.manager-points strong {
  font-weight: 900;
  font-size: 1.5rem;
  color: var(--accent);
}

.supporting-block {
  display: none;
}
#slots-panel.is-locked .supporting-block {
  display: block;
  border-top: 1px solid var(--border);
  padding-top: 14px;
  padding-bottom: 14px;
}
.supporting-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.supporting-badge {
  width: 28px;
  height: 28px;
  object-fit: contain;
}
.supporting-name {
  font-family: 'Urbanist', sans-serif;
  font-weight: 600;
  font-size: 1.4rem;
}
.supporting-points {
  margin-left: auto;
  font-size: 0.95rem;
  color: var(--muted);
}
.supporting-points strong {
  font-weight: 900;
  font-size: 1.5rem;
  color: var(--accent);
}
.supporting-fans {
  margin-top: 8px;
  font-size: 0.85rem;
  color: var(--muted);
}
.supporting-fans strong {
  font-weight: 900;
  font-size: 1rem;
  color: var(--ink);
}

#slots-panel.is-locked .rating-block {
  display: none;
}
#slots-panel.is-locked .players-block,
#slots-panel.is-locked .team-total {
  border-top: 1px solid var(--border);
  padding-top: 14px;
  padding-bottom: 14px;
}
#slots-panel.is-locked .team-total {
  padding-bottom: 0;
}

.slot-points {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px dashed var(--border);
  font-size: 0.85rem;
  color: var(--muted);
  display: flex;
  /* Default is an inline stat ("3 goals"); the team/history cards stack their
     labelled rows instead — switched to a column when .slot-points-row exists. */
  align-items: baseline;
  gap: 4px;
}
.slot-points:has(.slot-points-row) {
  flex-direction: column;
  align-items: stretch;
  gap: 2px;
}
/* When a Trade out button follows, close the points off with a dashed divider so
   it reads as a separator above the button; cards without the button don't need
   a trailing line. */
.slot:has(.slot-trade-btn) .slot-points {
  padding-bottom: 12px;
  border-bottom: 1px dashed var(--border);
}
.slot-points-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
.slot-points-label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.slot-points strong {
  font-weight: 900;
  font-size: 1.05rem;
  color: var(--accent);
}
/* The league-wide season total is the secondary number — keep it present but
   visually quieter than the points the player has earned for this manager. */
.slot-points-row:last-child strong {
  font-size: 1.05rem;
  color: var(--muted);
}

.team-total {
  display: none;
}
#slots-panel.is-locked .team-total {
  display: block;
  text-align: right;
}
#slots-panel.is-locked .team-total .section-label {
  text-align: left;
}
.team-total strong {
  font-weight: 900;
  font-size: 1.6rem;
  color: var(--accent);
}

/* ----- Empty state (used where a list/table has no rows yet) ----- */

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 12px;
  padding: 40px 24px;
  margin: 12px 0 4px;
  background: var(--tint-row-soft);
  border: 1px dashed var(--border);
  border-radius: var(--radius-lg);
}
.empty-state-title {
  margin: 0;
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--ink);
}
.empty-state-body {
  margin: 0;
  max-width: 38ch;
  color: var(--muted);
  font-size: 0.95rem;
  line-height: 1.5;
}
.empty-state .primary {
  margin-top: 4px;
}

/* ----- Teacher: student squads table ----- */

.squads-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 1rem;
  margin-top: 10px;
}
.squads-table thead th {
  text-align: left;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  font-weight: 700;
}
.squads-table tbody td {
  padding: 10px;
  border-bottom: 1px solid var(--border);
}
.squads-table tbody tr:last-child td {
  border-bottom: none;
}
.squads-table tbody tr:hover {
  background: var(--bg);
}
.squads-table .leader-club {
  display: inline-flex;
}
.squads-table .row-action {
  font-size: 0.78rem;
  padding: 4px 10px;
}
.squads-table tbody tr.is-pending td {
  color: var(--muted);
}
.squads-table tbody tr.is-pending td:first-child,
.squads-table tbody tr.is-pending td:nth-child(2),
.squads-table tbody tr.is-pending td:nth-child(3) {
  color: var(--ink);
}

.overlay:has(.admin-modal) {
  width: min(92vw, 380px);
}
.admin-modal {
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: 22px 24px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.admin-modal-header {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.admin-modal-name {
  font-size: 1.1rem;
  font-weight: 700;
  margin: 0;
}
.admin-modal-team {
  font-size: 0.85rem;
  color: var(--muted);
  margin: 0;
}
.admin-modal h2 {
  margin: 0;
  font-size: 1.05rem;
}
.admin-modal-actions {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
/* Each action is a light, tappable menu row rather than a filled button, so
   the routine edits stay calm and only the destructive row carries colour. */
.admin-modal-actions .admin-action-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px;
  background: transparent;
  border: none;
  border-radius: var(--radius-md);
  font: inherit;
  font-weight: 600;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  transition: background 0.15s ease;
}
.admin-modal-actions .admin-action-row:hover,
.admin-modal-actions .admin-action-row:focus-visible {
  background: #f3f4f6;
  outline: none;
}
.admin-action-icon {
  width: 20px;
  height: 20px;
  flex: none;
  fill: var(--accent);
}
.admin-action-label {
  flex: 1 1 auto;
}
.admin-action-chevron {
  width: 18px;
  height: 18px;
  flex: none;
  fill: none;
  stroke: var(--muted);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* Danger zone: a divider sets the destructive action apart from the edits. */
.admin-modal-actions .admin-action-row--danger {
  margin-top: 8px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  border-radius: 0 0 var(--radius-md) var(--radius-md);
  color: var(--error);
}
.admin-action-row--danger .admin-action-icon {
  fill: var(--error);
}
.admin-modal-actions .admin-action-row--danger:hover,
.admin-modal-actions .admin-action-row--danger:focus-visible {
  background: #fbeaea;
}
.admin-modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}
.admin-edit-input {
  width: 100%;
  padding: 8px 10px;
  font-size: 0.95rem;
  font-family: inherit;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
  color: var(--ink);
}
.admin-edit-input:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
  border-color: var(--accent);
}

.results-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.match-row {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  grid-template-areas:
    'home center away'
    'home-scorers . away-scorers'
    'divider divider divider'
    'home-cards . away-cards';
  align-items: center;
  column-gap: 12px;
  padding: 12px 14px;
  background: var(--bg);
  border-radius: var(--radius-sm);
  margin-bottom: 6px;
  border: 1px solid rgba(0, 0, 0, 0.05);
}
.match-cards-divider {
  grid-area: divider;
  border-top: 1px dashed var(--border);
  margin: 6px 0;
}
.match-row.is-derby {
  background: #fff0f0;
  border: 1px solid #f5b5b5;
}
.match-home {
  grid-area: home;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  font-weight: 600;
  font-size: 1rem;
  cursor: pointer;
}
.match-away {
  grid-area: away;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 6px;
  font-weight: 600;
  font-size: 1rem;
  cursor: pointer;
}
.match-home.is-favourite,
.match-away.is-favourite {
  font-weight: 700;
}
.match-home:hover,
.match-away:hover {
  color: var(--accent);
}
.match-center {
  grid-area: center;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 56px;
  line-height: 1;
}
.match-score {
  font-weight: 700;
  font-size: 1.5rem;
}
.match-vs {
  font-size: 0.85rem;
  text-transform: lowercase;
}
.match-home-scorers {
  grid-area: home-scorers;
  text-align: right;
  align-self: start;
}
.match-away-scorers {
  grid-area: away-scorers;
  text-align: left;
  align-self: start;
}
.match-home-cards {
  grid-area: home-cards;
  text-align: right;
  align-self: start;
}
.match-away-cards {
  grid-area: away-cards;
  text-align: left;
  align-self: start;
}
/* Keep each booked player's name and their card icon on one line so the icon
   can't orphan onto the next row. Players still wrap as whole units. */
.match-home-cards [data-player-link],
.match-away-cards [data-player-link] {
  white-space: nowrap;
}
.match-detail {
  font-size: 0.8rem;
  color: var(--muted);
  line-height: 1.5;
  margin-top: 4px;
}
.match-detail:empty {
  display: none;
}
.event-icon {
  font-size: 0.95em;
  white-space: nowrap;
}
.match-goal {
  margin-bottom: 2px;
}
.match-goal:last-child {
  margin-bottom: 0;
}
/* Keep scorer name + goal icon together, and the entire assist bracket
   clause together so the closing ")" never orphans onto its own line. */
.match-scorer,
.match-assist {
  white-space: nowrap;
}
.match-minute {
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  font-size: 0.85em;
  margin-right: 2px;
}
.is-my-player {
  font-weight: 700;
  color: var(--ink);
}
.derby-tag {
  position: absolute;
  top: 4px;
  right: 8px;
  background: var(--error);
  color: white;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: 3px;
}

.results-nav {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}
.results-nav h3 {
  margin: 0;
  flex: 1;
  text-align: center;
}
.md-arrow {
  padding: 4px 10px;
  font-size: 1rem;
  line-height: 1;
  aspect-ratio: 1;
}
.md-arrow:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

[data-player-link] {
  font-weight: 700;
  font-size: 0.95rem;
  line-height: 1.2;
  margin-bottom: 6px;
}
/* The heading style above is for leader tables and player cards. Match rows
   tag every scorer, assist and booking with data-player-link too, so reset
   them back to inheriting the surrounding match text. */
.match-row [data-player-link] {
  font-weight: inherit;
  font-size: inherit;
  line-height: inherit;
  margin-bottom: 0;
}
[data-player-link],
[data-club-link] {
  cursor: pointer;
  transition: color 0.1s;
}
[data-player-link]:hover,
[data-club-link]:hover {
  color: var(--accent);
}
/* Subtle zebra stripe below the hover rule so :hover still wins. */
.standings tbody tr:nth-child(even) {
  background: rgba(0, 0, 0, 0.025);
}
.standings tbody tr:hover {
  background: var(--bg);
}

/* ----- Club detail overlay (reuses favourite-detail layout) ----- */

.club-detail-meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 14px 24px;
  margin: 0 0 14px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.club-detail-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.9rem;
}
.club-detail-label {
  text-transform: uppercase;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--muted);
}
.club-detail-value {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.club-detail-value strong {
  font-weight: 600;
}
.club-detail-identity {
  font-style: normal;
}

.club-detail-section {
  margin-bottom: 14px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.club-detail-section .section-label {
  margin-bottom: 10px;
}

.club-detail-squad {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 6px;
}
.club-detail-squad li {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  background: var(--bg);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.9rem;
  transition: background 0.1s;
}
.club-detail-squad li:hover {
  background: #e8f3eb;
}
.club-detail-player-name {
  flex: 1 1 auto;
  font-weight: 600;
}
.club-detail-player-stars {
  color: var(--warning);
  font-size: 0.85rem;
}

/* Players / Supporters toggle inside the club detail panel (teacher).
   Supporters reuse the player card's .picked-by-pills / .picked-by-pill. */
.club-detail-tabs {
  margin-bottom: 14px;
}
.club-supporters-block + .club-supporters-block {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
.club-supporters-block .picked-by-pill {
  border-color: var(--club-color, var(--accent));
  border-width: 2px;
}
.worldwide-count {
  font-weight: 900;
  font-size: 2.4rem;
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--club-color, var(--accent));
}

.class-standings {
  font-size: 1rem;
}
.class-standings-head,
.class-row {
  display: grid;
  grid-template-columns: 32px 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 8px;
  border-bottom: 1px solid var(--border);
}
/* The ▲/▼ movement column only appears in the teacher's animated view. */
.class-standings.has-move .class-standings-head,
.class-standings.has-move .class-row {
  grid-template-columns: 32px 56px 1fr auto;
}
/* Animated standings reveal. The old order is rendered and held static for a
   beat so everyone can find their team, then rows slide to their new positions
   (staggered top-to-bottom) and the scores + arrows fade in. Rows that changed
   rank get a brief background flash so the eye is pulled to what moved. */
.class-row-pts,
.class-row-move {
  transition: opacity 0.3s ease;
}
.class-standings.is-revealing .class-row-pts,
.class-standings.is-revealing .class-row-move {
  opacity: 0;
}
.class-row.is-moved {
  animation: class-row-flash 1.1s ease-out;
}
@keyframes class-row-flash {
  0% {
    background: rgba(255, 218, 121, 0);
  }
  30% {
    background: rgba(255, 218, 121, 0.6);
  }
  100% {
    background: rgba(255, 218, 121, 0);
  }
}
.class-row-rank {
  font-weight: 700;
}
.class-row-move {
  display: flex;
  justify-content: flex-start;
}
.rank-move {
  display: inline-flex;
  align-items: center;
  /* Space the arrow from its number via flex gap, not letter-spacing — the
     latter also pushes apart the digits of a two-figure jump (e.g. ▲12). */
  gap: 0.35em;
  font-size: 1rem;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}
.rank-move.is-up {
  color: var(--success);
}
.rank-move.is-down {
  color: var(--danger);
}
.rank-move.is-same {
  color: var(--muted);
}
.class-standings-head {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  font-weight: 700;
  padding: 6px 8px;
}
.class-standings-head > span:last-child,
.class-row-pts {
  text-align: right;
  justify-self: end;
}
.class-row:last-child {
  border-bottom: none;
}
/* Subtle zebra stripe. Sits below the hover and is-me rules in source order
   so both still win where they apply. */
.class-row:nth-child(even):not(.is-me) {
  background: rgba(0, 0, 0, 0.025);
}
.class-row.is-me {
  background: var(--mine-row);
  box-shadow: inset 4px 0 0 var(--gold);
}
.class-row.is-clickable {
  cursor: pointer;
}
.class-row.is-clickable:hover {
  background: #f6f8fa;
}
.class-row.is-me.is-clickable:hover {
  background: var(--mine-row-hover);
}
.class-row-team {
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.class-team {
  font-weight: 600;
  color: var(--ink);
}
.class-manager {
  color: var(--muted);
  margin-left: 6px;
  font-size: 0.85em;
}

.standings {
  width: 100%;
  border-collapse: collapse;
  font-size: 1rem;
}
.standings thead th {
  text-align: left;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  padding: 6px 8px;
  border-bottom: 1px solid var(--border);
  font-weight: 700;
}
.standings tbody td {
  padding: 8px;
  border-bottom: 1px solid var(--border);
}
.standings tbody tr:last-child td {
  border-bottom: none;
}
.standings tbody tr.is-favourite {
  background: var(--mine-row);
}
.standings tbody tr.is-favourite td:first-child {
  box-shadow: inset 4px 0 0 var(--gold);
}
.standings tbody tr.is-favourite:hover {
  background: var(--mine-row-hover);
}
.standings-club {
  display: flex;
  align-items: center;
  gap: 6px;
  border-left: 3px solid var(--club-color, var(--border));
  padding-left: 8px;
  font-weight: 600;
  font-size: 1rem;
}
.standings-form span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  font-size: 0.7rem;
  font-weight: 500;
  color: white;
}
.standings-form span:not(:last-of-type) {
  margin-right: 3px;
}
/* W / D / L are built dynamically via class="form-${result}" — must stay in CSS. */
.form-W {
  background: var(--success);
}
.form-D {
  background: #94a3b8;
}
.form-L {
  background: var(--danger);
}

.leader-row {
  display: grid;
  grid-template-columns: 28px 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  background: var(--bg);
  border-radius: var(--radius-sm);
  margin-bottom: 4px;
  font-size: 1rem;
}
.leader-row.is-clickable {
  cursor: pointer;
}
.leader-row.is-clickable:hover {
  background: #f6f8fa;
}
.leader-value {
  font-weight: 700;
  color: var(--accent);
}
.leader-value .leader-cards {
  color: var(--ink);
  font-weight: 600;
  font-size: 0.85rem;
  white-space: nowrap;
}
.leader-rank {
  color: var(--muted);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.leader-table th:last-child,
.leader-table td.leader-table-value {
  text-align: right;
}
.leader-table td.leader-table-value strong {
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

/* ----- Podium row for top 5 in each leader list ----- */
.leader-podium {
  display: flex;
  gap: 12px;
  margin-bottom: 20px;
  flex-wrap: wrap;
  justify-content: center;
}
.leader-podium-slot {
  flex: 1 1 140px;
  max-width: 220px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.leader-rank-label {
  font-weight: 600;
  font-size: 1rem;
  text-align: center;
  color: var(--muted);
}
.leader-club {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 0.78rem;
}
@media (max-width: 600px) {
  .standings {
    font-size: 0.78rem;
  }
  .standings thead th,
  .standings tbody td {
    padding: 6px 4px;
  }
  .standings-club {
    border-left-width: 2px;
    padding-left: 5px;
    gap: 4px;
  }
  .standings-form span {
    width: 16px;
    height: 16px;
    font-size: 0.62rem;
  }
}

/* ----- Matchday replay overlay ----- */
.replay-overlay {
  width: min(1800px, 96vw);
  max-width: none;
  height: min(1000px, 95svh);
  padding: 0;
  border: none;
  border-radius: 14px;
  background: var(--bg);
  color: var(--ink);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.35);
  overflow: hidden;
}
.replay-overlay::backdrop {
  background: rgba(8, 12, 18, 0.78);
  backdrop-filter: blur(2px);
}

/* ----- End-of-season finale ----- */

.finale-overlay {
  /* Portrait-oriented card. */
  width: min(540px, 94vw);
  max-width: none;
  padding: 0;
  border: none;
  border-radius: 18px;
  background: var(--surface);
  color: var(--ink);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.35);
  overflow: hidden;
}
.finale-overlay::backdrop {
  background: rgba(8, 12, 18, 0.82);
  backdrop-filter: blur(3px);
}
.finale-overlay[open] {
  animation: finale-overlay-in 0.32s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes finale-overlay-in {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.96);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.finale-body {
  display: flex;
  flex-direction: column;
  gap: 18px;
  /* No top padding: the slide's header image sits flush to the modal top
     edge (clipped by the modal's border-radius via overflow:hidden). */
  padding: 0 40px 28px;
  text-align: center;
}

/* The slide is the whole card. Grid splits it 50/50: top row = image,
   bottom row = (content + actions + nav). Fixed height + grid stops the
   image's intrinsic aspect-ratio overriding the row sizing. */
.finale-slide {
  position: relative;
  display: grid;
  grid-template-rows: 1fr 1fr;
  height: min(720px, 86vh);
  animation: finale-slide-in 0.32s ease;
}
/* Header image wrap fills its grid row and bleeds left/right to the modal
   edges by cancelling the .finale-body horizontal padding. Also acts as the
   positioning context for an optional overlay image. */
.finale-image-wrap {
  position: relative;
  width: calc(100% + 80px);
  height: 100%;
  min-height: 0;
  margin: 0 -40px;
}
.finale-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Centred overlay image (e.g., the league trophy on the title slide). Sits at
   80% of the wrap in both dimensions; object-fit:contain keeps the overlay's
   aspect ratio inside that box. */
.finale-image-overlay {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 50%;
  height: 50%;
  transform: translate(-50%, -50%);
  object-fit: contain;
  pointer-events: none;
}
/* trophy-only styling */
.finale-slide--title .finale-image-overlay {
  width: 80%;
  height: 80%;
}
/* Override for player portraits only */
.finale-slide--player .finale-image-overlay {
  width: auto;
  height: 60%;
  aspect-ratio: 1;
  border-radius: 100%;
  object-fit: cover;
  border: 4px solid var(--gold);
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.3);
  padding: 3px;
}
.finale-slide--club .finale-image-overlay,
.finale-slide--manager .finale-image-overlay,
.finale-slide--champion .finale-image-overlay {
  width: 80%;
  height: 80%;
}
/* Full-frame overlay (the in-stadium trophy on the champions slide). Mirrors
   .finale-image exactly so the trophy lands where it was composed in the
   matching champion image. Compound selector + source order beats the 80%
   kind rule above. */
.finale-image-overlay.finale-image-overlay--cover {
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  transform: none;
  object-fit: cover;
}

/* Bottom half: content fills the top, actions + nav pinned to the bottom. */
.finale-slide-bottom {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-height: 0;
  padding-top: 18px;
}
.finale-slide-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  flex: 1;
  min-height: 0;
  text-align: center;
}
@keyframes finale-slide-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.finale-eyebrow {
  margin: 0;
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.finale-heading {
  font-family: 'Urbanist', sans-serif;
  font-weight: 900;
  font-size: clamp(2rem, 5vw, 3rem);
  line-height: 1;
  letter-spacing: -0.02em;
  margin: 0;
  color: var(--ink);
}
.finale-headline {
  font-family: 'Urbanist', sans-serif;
  font-weight: 900;
  font-size: clamp(1.8rem, 4.4vw, 2.8rem);
  line-height: 1;
  letter-spacing: -0.02em;
  margin: 0;
  color: var(--ink);
}
/* Big centred badge under the club name on the League Champions slide. */
.finale-club-badge-large {
  width: 96px;
  height: 96px;
  display: block;
  margin: 0 auto;
}
.finale-sub {
  margin: 0;
  font-size: 1rem;
  color: var(--muted);
}
.finale-stat {
  margin: 4px 0 0;
  font-size: 1rem;
  color: var(--muted);
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: center;
}
.finale-stat strong {
  font-weight: 900;
  font-size: 1.4rem;
  color: var(--ink);
}
.finale-stat span {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.78rem;
}

/* Player meta row on the three player slides: flag, position, club, stars. */
.finale-player-meta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  flex-wrap: wrap;
  font-size: 0.95rem;
  color: var(--muted);
}
.finale-player-meta .flag {
  width: 22px;
  height: auto;
  border-radius: 2px;
}
.finale-player-pos {
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-size: 0.8rem;
  color: var(--ink);
}
.finale-player-club {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--ink);
}
.finale-player-club .badge-tiny {
  width: 18px;
  height: 18px;
}
.finale-player-stars {
  color: #d4a017;
  letter-spacing: 2px;
  font-size: 0.9rem;
}

/* Persistent corner close, shown on every slide (reuses the .overlay-close
   chip). z-index lifts it above the confetti layer so it stays tappable. */
.finale-close {
  z-index: 4;
}

/* Certificate button on the Manager of the Season + Class League Champion
   slides — prints the season certificate (opens in a new tab). */
.finale-cert-btn {
  margin-top: 6px;
  font: inherit;
  font-weight: 700;
  font-size: 0.85rem;
  padding: 7px 18px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  transition:
    background 0.15s ease,
    border-color 0.15s ease,
    transform 0.1s ease;
}
.finale-cert-btn:hover {
  background: var(--bg);
  border-color: var(--ink);
}
.finale-cert-btn:active {
  transform: translateY(1px);
}

/* Compact nav row at the foot of the finale overlay: back arrow, dots,
   next arrow. Replaces the old "Next" pill button and standalone dots row. */
.finale-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
}
.finale-nav-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  transition:
    background 0.15s ease,
    border-color 0.15s ease,
    transform 0.1s ease;
}
.finale-nav-arrow:hover {
  background: var(--bg);
  border-color: var(--ink);
}
.finale-nav-arrow:active {
  transform: translateY(1px);
}
.finale-nav-arrow:disabled {
  opacity: 0.3;
  cursor: default;
}
.finale-nav-arrow:disabled:hover {
  background: var(--surface);
  border-color: var(--border);
}
.finale-nav-arrow .icon {
  width: 18px;
  height: 18px;
}

.finale-progress {
  display: flex;
  justify-content: center;
  gap: 6px;
}
.finale-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--border);
}
.finale-dot.is-past {
  background: var(--muted);
}
.finale-dot.is-current {
  background: var(--accent);
  transform: scale(1.25);
}

/* ----- Finale celebratory motion ----- */
/* Content reveals in sequence — eyebrow, then name, then the rest — so the
   winner lands with a beat rather than all at once. animation-fill-mode
   backwards holds the from-state only during the delay, so disabling the
   animation (reduced motion) leaves every element at its normal visible state. */
.finale-slide-content > * {
  animation: finale-rise 0.5s cubic-bezier(0.16, 1, 0.3, 1) backwards;
}
.finale-slide-content > *:nth-child(1) {
  animation-delay: 0.06s;
}
.finale-slide-content > *:nth-child(2) {
  animation-delay: 0.16s;
}
.finale-slide-content > *:nth-child(3) {
  animation-delay: 0.26s;
}
.finale-slide-content > *:nth-child(4) {
  animation-delay: 0.36s;
}
.finale-slide-content > *:nth-child(n + 5) {
  animation-delay: 0.46s;
}
@keyframes finale-rise {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* The trophy / portrait / champion image pops in with a little overshoot a beat
   after the slide. Scoped away from the full-frame --cover overlay, whose
   transform must stay untouched — it just fades. */
.finale-image-overlay:not(.finale-image-overlay--cover) {
  animation: finale-pop 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) 0.1s backwards;
}
@keyframes finale-pop {
  from {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.72);
  }
  to {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
  }
}
.finale-image-overlay--cover {
  animation: finale-fade 0.55s ease 0.05s backwards;
}
@keyframes finale-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* One-shot confetti burst layered over the climactic slides (title, club
   champions, class league champion). Pieces are generated in season-finale.js
   with per-piece CSS vars for position, timing, fall distance and spin. */
.finale-confetti {
  position: absolute;
  inset: 0;
  z-index: 3;
  overflow: hidden;
  pointer-events: none;
}
.finale-confetti i {
  position: absolute;
  top: -14px;
  height: 14px;
  border-radius: 1px;
  opacity: 0;
  animation: finale-confetti-fall var(--dur, 2.6s) linear var(--delay, 0s)
    forwards;
}
@keyframes finale-confetti-fall {
  0% {
    opacity: 0;
    transform: translateY(-10px) rotate(0deg);
  }
  12% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translateY(var(--fall, 640px)) rotate(var(--spin, 540deg));
  }
}

/* Honour both the system preference and the in-app Reduce Motion toggle. */
@media (prefers-reduced-motion: reduce) {
  .finale-slide-content > *,
  .finale-image-overlay,
  .finale-image-overlay--cover {
    animation: none;
  }
  .finale-confetti {
    display: none;
  }
}
html.is-reduced-motion .finale-slide-content > *,
html.is-reduced-motion .finale-image-overlay,
html.is-reduced-motion .finale-image-overlay--cover {
  animation: none;
}
html.is-reduced-motion .finale-confetti {
  display: none;
}

/* ----- Past Seasons (Admin → Past Seasons) ----- */
.past-seasons {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.past-season-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 16px 18px;
}
.past-season-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}
.past-season-title {
  font-family: 'Urbanist', sans-serif;
  font-weight: 900;
  font-size: 1.25rem;
  margin: 0;
  color: var(--ink);
}
.past-season-date {
  font-size: 0.8rem;
  color: var(--muted);
}
.past-awards {
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.past-awards li {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 0.9rem;
}
.past-award-label {
  flex: 0 0 auto;
  min-width: 180px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 0.72rem;
  color: var(--muted);
}
.past-award-name {
  color: var(--ink);
  font-weight: 600;
}
.past-award-sub {
  color: var(--muted);
  font-size: 0.82rem;
}
.past-season-actions {
  margin-bottom: 8px;
}
.past-details {
  border-top: 1px solid var(--border);
  padding-top: 8px;
  margin-top: 8px;
}
.past-details summary {
  cursor: pointer;
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--ink);
  padding: 4px 0;
}
.past-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 8px;
  font-size: 0.85rem;
}
.past-table th,
.past-table td {
  text-align: left;
  padding: 5px 8px;
  border-bottom: 1px solid var(--border);
}
.past-table th {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.past-table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Player History — compact per-season points (student player-detail view) */
.history-line {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  font-size: 0.95rem;
  color: var(--muted);
}
.history-item strong {
  color: var(--ink);
  font-weight: 800;
}

.replay-shell {
  display: flex;
  flex-direction: column;
  height: 100%;
}

/* Header grid mirrors .replay-body (same columns, gap and side padding) so the
   header bar can sit in the second column — clock aligned to the left edge of
   the right-hand leaderboard column, skip button pushed to the far edge. */
.replay-header {
  display: grid;
  grid-template-columns: 7fr 3fr;
  gap: 18px;
  align-items: center;
  padding: 14px 22px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.replay-header-title {
  grid-column: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 16px;
}
.replay-header-md {
  font-weight: 800;
  font-size: 1.5rem;
  letter-spacing: -0.01em;
  color: var(--ink);
}
/* Playback-speed segmented control beside the matchday title. The replay is
   teacher-only, so this is never student-facing. A slower tempo widens the gap
   before the next event slides in - more time to read - and the choice is
   remembered across matchdays (see SPEEDS / savedSpeed in matchday-replay.js). */
.replay-speed {
  display: flex;
  align-items: center;
  gap: 8px;
}
.replay-speed-label {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}
.replay-speed-group {
  display: flex;
}
.replay-speed-btn {
  border: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.05);
  color: var(--muted);
  font: inherit;
  font-size: 0.82rem;
  font-weight: 700;
  padding: 5px 11px;
  cursor: pointer;
  margin-left: -1px;
  border-radius: 0;
  width: 72px;
  box-shadow: none;
}
.replay-speed-btn:first-child {
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  margin-left: 0;
}
.replay-speed-btn:last-child {
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.replay-speed-btn:hover {
  color: var(--ink);
}
.replay-speed-btn.is-active {
  background: #fff;
  color: var(--ink);
  position: relative;
  z-index: 1;
  box-shadow:
    rgba(0, 0, 0, 0.4) 0px 1px 2px,
    rgba(0, 0, 0, 0.3) 0px 2px 4px -1px,
    rgba(0, 0, 0, 0.2) 0px -1px 0px inset;
}
.replay-header-bar {
  grid-column: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
/* Two-digit masked-scroll clock. Each digit is its own one-row window with a
   number track sliding inside; only the digit that changes scrolls. See
   setClock() / scrollDigit() in matchday-replay.js for the scroll mechanics. */
.replay-clock {
  display: flex;
  font-weight: 900;
  font-size: 2.4rem;
  color: #111;
  box-shadow:
    rgba(6, 24, 44, 0.2) 0px 0px 0px 1px,
    rgba(6, 24, 44, 0.65) 0px 4px 6px -1px,
    rgba(255, 255, 255, 0.08) 0px 1px 0px inset;
  border-radius: 3px;
  padding: 0 8px;
  background: var(--gold);
  border-top: 1px solid rgba(255, 255, 255, 0.7);
  border-bottom: 1px solid rgba(0, 0, 0, 0.2);
  column-gap: 5px;
}
.replay-clock-digit {
  width: 1ch;
  height: 1.2em;
  overflow: hidden;
}
.replay-clock-seam {
  width: 1px;
  height: auto;
  border-left: 1px solid rgba(0, 0, 0, 0.1);
  border-right: 1px solid rgba(255, 255, 255, 0.2);
}
.replay-clock-track {
  display: flex;
  flex-direction: column;
  transition: transform 380ms cubic-bezier(0.3, 0.1, 0.2, 1);
}
.replay-clock-num {
  display: block;
  width: 1ch;
  height: 1.2em;
  line-height: 1.2;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.replay-skip {
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--border);
  padding: 6px 12px;
  border-radius: var(--radius-md);
  font: inherit;
  font-size: 0.9rem;
  cursor: pointer;
}
.replay-skip:hover {
  color: var(--ink);
  border-color: var(--ink);
}
.replay-skip.is-done,
.replay-skip.is-kickoff {
  font-weight: 700;
  padding: 8px 18px;
}
/* Green "start" buttons (Start First/Second Half) — the prominent "go" action. */
.replay-skip.is-kickoff {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
}
.replay-skip.is-kickoff:hover {
  filter: brightness(1.05);
  color: var(--accent-ink);
}
/* Points buttons (See Points Won, View League Table, Show Points So Far) go
   gold — gold is the site's "points" colour everywhere — so they read as
   distinct from the green start buttons and the quiet Skip button. */
.replay-skip.is-done {
  background: var(--gold);
  color: var(--ink);
  border-color: var(--gold);
}
.replay-skip.is-done:hover {
  filter: brightness(1.05);
  color: var(--ink);
}

.replay-body {
  position: relative;
  flex: 1;
  display: grid;
  grid-template-columns: 7fr 3fr;
  gap: 18px;
  padding: 18px 22px;
  overflow: hidden;
  min-height: 0;
}

/* Goal-celebration confetti. Sits as a sibling of the scrolling fixtures list
   (not inside it) so bursts aren't clipped by its overflow; the panel's own
   overflow: hidden keeps confetti contained to the body. Pieces are generated
   in matchday-replay.js with per-piece CSS vars and self-remove after landing. */
.replay-confetti-layer {
  position: absolute;
  inset: 0;
  z-index: 5;
  overflow: visible;
  pointer-events: none;
}
.replay-goal-burst {
  position: absolute;
  width: 0;
  height: 0;
}
.replay-goal-burst i {
  position: absolute;
  top: 0;
  left: 0;
  border-radius: 1px;
  opacity: 0;
  animation: replay-goal-confetti var(--dur, 2.2s) ease-out var(--delay, 0s)
    forwards;
}
/* Pop up and out from the origin, then arc down and fade. Opacity holds full
   through most of the flight and only eases away over the final third, so the
   pieces settle out softly instead of snapping off. translate(-50%, -50%) keeps
   each piece centred on the burst point. */
@keyframes replay-goal-confetti {
  0% {
    opacity: 0;
    transform: translate(-50%, -50%) rotate(0deg);
  }
  10% {
    opacity: 1;
  }
  35% {
    transform: translate(calc(-50% + var(--tx) * 0.5), calc(-50% + var(--peak)))
      rotate(calc(var(--spin) * 0.5));
  }
  65% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translate(calc(-50% + var(--tx)), calc(-50% + var(--ty)))
      rotate(var(--spin));
  }
}
@media (prefers-reduced-motion: reduce) {
  .replay-confetti-layer {
    display: none;
  }
}
html.is-reduced-motion .replay-confetti-layer {
  display: none;
}

.replay-fixtures {
  display: flex;
  flex-direction: column;
  gap: 6px;
  overflow-y: auto;
  min-height: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px;
}
.replay-fixtures .match-row {
  margin-bottom: 0;
}
/* A fixture goes "pending" for the one 800ms tick before its next event
   fires. Two quick beats of an accent ring, a swell and a glow read as a
   quickening heartbeat so the eye snaps to the row about to do something. */
.replay-fixtures .match-row.is-pending {
  z-index: 1;
  animation: replay-row-charge 400ms ease-in-out 2;
}

/* Pre-match atmosphere shown beneath each fixture before kickoff: home
   stadium, weather + Celsius temperature, referee + their season cards.
   The whole block is removed from the DOM when Start First Half fires. */
.replay-fixture-slot {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.pre-match-info {
  padding: 8px 12px 10px;
  border-top: 1px dashed var(--border);
  font-size: 0.85rem;
  color: var(--muted);
}
.pre-match-stadium {
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 4px;
}
.pre-match-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
.pre-match-weather {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.pre-match-weather-icon {
  width: 36px;
  height: 36px;
  display: block;
}
.pre-match-temp {
  display: inline-block;
  min-width: 2.75em;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--ink);
}
.pre-match-ref {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.pre-match-ref-name {
  color: var(--ink);
  font-weight: 600;
}
.pre-match-ref-name span {
  color: var(--muted);
  font-weight: 400;
}
.pre-match-ref-cards {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-variant-numeric: tabular-nums;
}
.ref-card-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 18px;
  padding: 0 5px;
  border-radius: 3px;
  font-size: 0.75rem;
  font-weight: 700;
  color: #fff;
}
.ref-card-yellow {
  background: #e6b800;
  color: #2a2a2a;
}
.ref-card-red {
  background: #c0392b;
}
@keyframes replay-row-charge {
  0%,
  100% {
    transform: scale(1);
    background: var(--bg);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05);
  }
  50% {
    transform: scale(1.015);
    background: color-mix(in srgb, var(--accent) 8%, var(--bg));
    box-shadow:
      0 0 0 2px var(--accent),
      0 6px 18px color-mix(in srgb, var(--accent) 32%, transparent);
  }
}
/* Reduced motion: keep the cue but hold it still — a static accent ring on the
   row that's about to act, no swell or glow pulse. */
@media (prefers-reduced-motion: reduce) {
  .replay-fixtures .match-row.is-pending {
    animation: none;
    box-shadow: 0 0 0 2px var(--accent);
  }
}
html.is-reduced-motion .replay-fixtures .match-row.is-pending {
  animation: none;
  box-shadow: 0 0 0 2px var(--accent);
}

.replay-leaderboard {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 14px 12px;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  box-shadow: var(--shadow);
}
.replay-leaderboard .section-label {
  margin-bottom: 8px;
  padding: 0 4px;
}

.replay-pre-match {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 18px 12px;
  flex: 1;
  min-height: 0;
  text-align: center;
}
.replay-pre-match-line {
  margin: 0;
  font-size: 0.9rem;
  color: var(--muted);
  font-style: italic;
  line-height: 1.4;
}

/* ----- Replay event log (replaces the class leaderboard during play) ----- */

.replay-event-log {
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow-y: auto;
  flex: 1;
  min-height: 0;
  margin: 0;
  padding: 0 4px;
}
/* [hidden] alone loses to the display:flex above — make it explicit so the
   event log can yield the panel to the matchday summary at full time. */
.replay-event-log[hidden] {
  display: none;
}
.replay-event-log:empty::before {
  content: 'Waiting for the action…';
  display: block;
  padding: 16px 8px;
  color: var(--muted);
  font-style: italic;
  font-size: 0.9rem;
  text-align: center;
}

.replay-event {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 8px 10px;
  animation: replay-event-in 280ms ease-out;
}
@keyframes replay-event-in {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.replay-event--yellow,
.replay-event--red {
  background: rgba(254, 243, 199, 0.6);
}
.replay-event--red {
  background: rgba(254, 226, 226, 0.6);
}
.replay-event--cleanSheet,
.replay-event--win,
.replay-event--derbyWin {
  background: rgba(220, 252, 231, 0.5);
}

.replay-event-head {
  display: grid;
  grid-template-columns: 20px 32px 1fr;
  align-items: baseline;
  gap: 8px;
}
.replay-event-minute {
  font-family: 'Urbanist', sans-serif;
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.replay-event-icon {
  font-size: 2rem;
  line-height: 1;
}
.replay-event-head .replay-event-icon {
  align-self: start;
  margin-top: 0.15em;
}

.replay-event-title-block {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.replay-event-tag {
  font-family: 'Urbanist', sans-serif;
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.2;
  color: var(--accent);
}
.replay-event--yellow .replay-event-tag {
  color: #b45309;
}
.replay-event--red .replay-event-tag {
  color: var(--error);
}
.replay-event-title {
  font-weight: 700;
  font-size: 0.92rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.replay-event-sub {
  font-size: 0.78rem;
  color: var(--muted);
}

.replay-event-awards {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 6px;
  padding-left: 64px;
}
.replay-event-award {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  font-size: 0.8rem;
}
.replay-event-award strong {
  font-family: 'Urbanist', sans-serif;
  font-weight: 700;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.replay-event--yellow .replay-event-award strong,
.replay-event--red .replay-event-award strong {
  color: #b91c1c;
}

.replay-event-divider {
  display: flex;
  align-items: center;
  gap: 8px;
  text-align: center;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 4px 6px;
}
.replay-event-divider::before,
.replay-event-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}

/* ----- Replay matchday summary (replaces the event log at full time) ----- */

.replay-summary {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  animation: replay-event-in 280ms ease-out;
}
.replay-summary-title {
  margin: 0 0 8px;
  padding: 0 4px;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.replay-summary-list {
  list-style: none;
  margin: 0;
  padding: 0 4px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  overflow-y: auto;
  flex: 1;
  min-height: 0;
}
.replay-summary-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.replay-summary-row:first-child {
  background: var(--tint-row-cool);
  border-color: var(--accent);
}
.replay-summary-rank {
  flex: none;
  width: 22px;
  text-align: center;
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.replay-summary-name {
  flex: 1;
  min-width: 0;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.replay-summary-total {
  flex: none;
  font-weight: 900;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 720px) {
  .replay-body {
    grid-template-columns: 1fr;
  }
  .replay-leaderboard {
    max-height: 240px;
  }
  /* Body is single-column here, so there's no right column to align to —
     let the header stack: title on top, clock + skip on its own row below. */
  .replay-header {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
  }
  .replay-header-md {
    font-size: 1.25rem;
  }
  .replay-header-bar {
    flex: 1;
  }
}

/* ----- Awards block (Matches tab → Awards sub-tab) ----- */
.awards-empty {
  margin: 12px 4px;
  text-align: center;
}
.awards-block {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  padding: 6px 0 2px;
  align-items: stretch;
}
.award-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 18px;
  padding: 32px 24px 28px;
  background: var(--surface);
  border-radius: 18px;
  border: 1px solid var(--border);
}
.award-card.is-empty .award-trophy {
  opacity: 0.3;
  filter: grayscale(0.4);
}
.award-trophy {
  width: 200px;
  height: 200px;
  object-fit: contain;
  display: block;
}
.award-meta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: 100%;
  min-width: 0;
}
.award-title {
  margin: 0;
  font-family: 'Urbanist', sans-serif;
  font-weight: 700;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
}
.award-name {
  font-weight: 800;
  font-size: 1.7rem;
  color: var(--ink);
  line-height: 1.1;
  margin-top: 2px;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.award-team {
  margin: 0;
  font-size: 0.92rem;
  color: var(--muted);
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.award-print {
  position: relative;
  margin-top: 38px;
  background: var(--gold);
  color: var(--ink);
  border: none;
  border-radius: var(--radius-pill);
  border: 1px solid rgba(0, 0, 0, 0.025);
  box-shadow:
    var(--tint-row-cool) 0px 0px 0px 1px,
    rgba(42, 51, 69, 0.04) 0px 1px 1px -0.5px,
    var(--tint-row) 0px 3px 3px -1.5px,
    var(--tint-row) 0px 6px 6px -3px,
    var(--tint-row-cool) 0px 12px 12px -6px,
    var(--tint-row-cool) 0px 24px 24px -12px;
  padding: 10px 20px;
  font: inherit;
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
  transition: filter 0.15s ease;
}
.award-print::before {
  content: '';
  position: absolute;
  left: 50%;
  top: -28px;
  width: 48px;
  height: 1px;
  background: var(--border);
  transform: translateX(-50%);
}
.award-print:hover {
  filter: brightness(1.15);
}
.award-empty-note {
  margin: 4px 0 0;
  font-size: 0.85rem;
  color: var(--muted);
}
@media (max-width: 720px) {
  .awards-block {
    grid-template-columns: 1fr;
    gap: 14px;
  }
  .award-card {
    padding: 24px 20px;
    gap: 14px;
  }
  .award-trophy {
    width: 120px;
    height: 120px;
  }
}

/* (Certificate styles live inside js/certificate.js — the certificate
   opens in its own window with self-contained CSS, so we don't need
   them in the main stylesheet.) */

/* ----- Manager bonus overlay ----- */
.overlay:has(.manager-bonus-overlay) {
  width: min(94vw, 720px);
}
.overlay:has(.squad-detail-overlay) {
  width: min(94vw, 1100px);
}
.squad-detail-overlay {
  position: relative;
  background: var(--surface);
  border-radius: 16px;
  padding: 36px 32px 28px;
}

/* ----- Award Points modal ----- */
.overlay:has(.award-modal) {
  width: min(94vw, 560px);
}
/* The action bar floats as its own element beneath the card, so the dialog goes
   transparent/shadowless and the card + bar each carry their own shadow with a
   gap between them. The dialog keeps its base scroll (overflow-y: auto +
   overscroll-behavior: contain) so on a short screen the whole thing scrolls and
   the floating bar stays reachable — never the page behind. The padding gives
   the card/bar shadows room so they aren't hard-clipped at the scroll edges. */
.overlay:has(.award-action-bar) {
  background: transparent;
  box-shadow: none;
  /* padding: 10px; */
}
#overlay-body:has(.award-action-bar) {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.award-modal {
  position: relative;
  background: var(--surface);
  border-radius: 16px;
  padding: 32px 32px 28px;
  text-align: left;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3);
}
.award-modal-title {
  font-family: 'Urbanist', sans-serif;
  font-weight: 900;
  font-size: clamp(1.6rem, 3vw, 2rem);
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 0 0 22px;
}
.award-modal-empty {
  margin: 8px 0 4px;
}
/* Each section sits in its own subtle tray to add structure on the white modal. */
.award-panel {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 16px 18px 10px 18px;
}
/* Single column by default; splits to students | controls once there's width,
   so a full class shows far more names before the list needs to scroll. */
.award-modal-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
}
.award-controls-col .section-label {
  display: block;
  margin: 0 0 10px;
}
@media (min-width: 800px) {
  .overlay:has(.award-modal) {
    width: min(94vw, 1280px);
  }
  /* Both columns share one height, so the student panel stays full-height
     regardless of class size (it scrolls inside) and the Confirm button lines
     up with the bottom of the list. The controls column is a fixed width so all
     the extra modal width flows to the student list, which then packs into 3-4
     columns (auto-fill) and a full class fits with little or no scrolling. */
  .award-modal-grid {
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 20px;
    align-items: stretch;
    /* Give the card a floor so it uses the height available rather than
       collapsing to content: Notes (flex-grows in its column) gets a proper
       writing area instead of a squashed strip, and the student list gets room
       to breathe. Capped so it never runs away on a tall screen. */
    min-height: min(58vh, 480px);
  }
  .award-who-col {
    display: flex;
    flex-direction: column;
  }
  .award-who-col .award-who-list {
    grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
    flex: 1 1 auto;
    min-height: 0;
    /* Cap keeps a very large class from stretching the modal unbounded; the
       list scrolls past this point. */
    max-height: min(64vh, 540px);
  }
  .award-controls-col {
    display: flex;
    flex-direction: column;
  }
  /* Notes now owns the freed space where the amount controls used to sit, so it
     grows to match the student list height instead of staying a cramped strip. */
  .award-controls-col .award-notes-section {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    margin-bottom: 0;
  }
  .award-controls-col .award-notes-section .award-comment {
    flex: 1 1 auto;
  }
}
/* Short viewports (iPad landscape, small laptops): reclaim vertical space so the
   whole modal + floating bar fits without scrolling. Shrinks the heading, trims
   padding, drops the card height floor (so it sizes to content), and lets the
   student list scroll sooner. Placed after the min-width block so it wins by
   source order where both apply. */
@media (max-height: 820px) {
  .award-modal {
    padding: 18px 24px 16px;
  }
  .award-modal-title {
    font-size: 1.3rem;
    margin-bottom: 12px;
  }
  .award-modal-grid {
    min-height: 0;
  }
  .award-who-col .award-who-list {
    max-height: 40vh;
  }
  #overlay-body:has(.award-action-bar) {
    gap: 10px;
  }
  .award-action-bar {
    padding: 10px 16px;
  }
}
.award-modal-section {
  margin-bottom: 22px;
}
.award-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}
.award-section-head .section-label {
  margin: 0;
}
.award-label-hint {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 500;
  color: var(--muted);
  margin-left: 2px;
}
.award-select-all {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  /* Match the .section-label eyebrow treatment (uppercase, tracked, muted). */
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  user-select: none;
}

/* Nicer custom checkbox, shared by the rows and Select all. */
.award-check {
  appearance: none;
  -webkit-appearance: none;
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  margin: 0;
  border-radius: 6px;
  border: 2px solid var(--border);
  background: var(--surface);
  cursor: pointer;
  display: inline-grid;
  place-content: center;
  transition:
    background 0.15s ease,
    border-color 0.15s ease;
}
.award-check::after {
  content: '';
  width: 5px;
  height: 9px;
  margin-bottom: 2px;
  border: solid #fff;
  border-width: 0 2.5px 2.5px 0;
  transform: rotate(45deg) scale(0);
  transition: transform 0.12s ease;
}
.award-check:checked,
.award-check:indeterminate {
  background: var(--accent);
  border-color: var(--accent);
}
.award-check:checked::after {
  transform: rotate(45deg) scale(1);
}
.award-check:indeterminate::after {
  width: 10px;
  height: 0;
  margin: 0;
  border-width: 0 0 2.5px 0;
  transform: scale(1);
}
.award-check:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.award-who-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
  gap: 6px;
  /* Pack rows at their natural height. In the desktop two-column layout the
     list is flex-grown to fill the full-height tray, and a grid's default
     stretch would otherwise blow a small class's few cards up to fill it. */
  align-content: start;
  max-height: min(260px, 38vh);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 2px;
}
.award-who-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--surface);
  cursor: pointer;
  transition:
    background 0.12s ease,
    border-color 0.12s ease;
}
.award-who-row:hover {
  border-color: #cfd4dc;
}
.award-who-row.is-selected {
  background: rgba(13, 122, 79, 0.08);
  border-color: #b7e0c8;
}
.award-who-name {
  font-size: 0.95rem;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
/* A class with its own display beats [hidden]; pair the filter's hidden toggle
   with an explicit rule so filtered-out rows actually disappear. */
.award-who-row[hidden] {
  display: none;
}
/* Type-to-filter box above the roster, for scanning a large class quickly. */
.award-filter-wrap {
  margin-bottom: 10px;
}
.award-filter {
  width: 100%;
  padding: 10px 14px;
  font: inherit;
  font-size: 0.95rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
  color: var(--ink);
  transition:
    border-color 0.15s ease,
    box-shadow 0.15s ease;
}
.award-filter::placeholder {
  color: var(--muted);
}
.award-filter:focus {
  outline: none;
  border-color: var(--ink);
  box-shadow: 0 0 0 3px rgba(17, 24, 39, 0.08);
}
.award-filter-empty {
  margin: 8px 2px 2px;
  font-size: 0.9rem;
}
/* Running tally beside the heading, so a ticked-but-filtered-out student is
   never a surprise at Confirm time. Inherits the .section-label eyebrow it sits
   inside, so it reads as part of the heading. */
.award-selected-count {
  font-weight: 600;
}

.award-categories {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}
.award-categories button {
  font: inherit;
  font-size: 0.9rem;
  font-weight: 500;
  padding: 8px 14px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
  transition:
    color 0.15s ease,
    background 0.15s ease,
    border-color 0.15s ease;
}
.award-categories button:hover {
  color: var(--ink);
  border-color: #cfd4dc;
}
.award-categories button.is-selected {
  color: var(--ink);
  background: var(--gold);
  border-color: #fff;
  font-weight: 600;
  box-shadow:
    rgba(14, 63, 126, 0.06) 0px 0px 0px 1px,
    var(--tint-row-soft) 0px 2px 2px -1px,
    var(--tint-row-soft) 0px 6px 6px -3px;
}

/* Full-width action bar beneath the grid: Award/Deduct, the amount, and the
   Confirm button on one line. The bar reflects the chosen mode, so the whole
   area reads as Award (green) or Deduct (red) at a glance. */
.award-action-bar {
  display: flex;
  align-items: center;
  z-index: 2;
  gap: 14px;
  flex-wrap: wrap;
  padding: 14px 18px;
  box-shadow: 0 16px 38px rgba(0, 0, 0, 0.22);
  transition:
    background 0.18s ease,
    border-color 0.18s ease;
}
.award-action-bar.is-pos {
  background: #ecfaf2;
  border-color: #b7e0c8;
}
.award-action-bar.is-neg {
  background: #fef2f2;
  border-color: #fbd5d5;
}
.award-action-bar .award-polarity,
.award-action-bar .award-amounts,
.award-action-bar .award-modal-actions {
  margin: 0;
}
/* Symbol-only +/− toggle: compact and language-neutral. */
.award-action-bar .award-polarity {
  flex: 0 0 auto;
}
.award-action-bar .award-polarity button {
  min-width: 54px;
  font-size: 1.3rem;
  padding: 11px 0;
}
.award-action-bar .award-amounts {
  flex: 1 1 280px;
}
.award-action-bar .award-modal-actions {
  flex: 1 1 240px;
}
.award-polarity {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-bottom: 10px;
}
.award-polarity button {
  font: inherit;
  font-weight: 700;
  font-size: 1rem;
  padding: 12px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
  transition:
    color 0.15s ease,
    background 0.15s ease,
    border-color 0.15s ease;
}
.award-polarity button:hover {
  color: var(--ink);
  border-color: #cfd4dc;
}
.award-polarity button[data-award-polarity='pos'].is-active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.award-polarity button[data-award-polarity='neg'].is-active {
  background: var(--error);
  border-color: var(--error);
  color: #fff;
}
.award-amounts {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
}
.award-amounts button {
  font-family: 'Urbanist', sans-serif;
  font-weight: 800;
  font-size: 1.5rem;
  padding: 14px 0;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  transition:
    background 0.15s ease,
    color 0.15s ease,
    transform 0.15s ease,
    border-color 0.15s ease;
}
.award-amounts button:hover {
  border-color: #cfd4dc;
}
.award-amounts.is-pos button.is-selected {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: #fff;
  transform: translateY(-2px);
  box-shadow:
    rgba(13, 122, 79, 0.25) 0px 2px 2px -1px,
    rgba(13, 122, 79, 0.2) 0px 8px 8px -4px;
}
.award-amounts.is-neg button.is-selected {
  background: var(--error);
  color: #fff;
  border-color: #fff;
  transform: translateY(-2px);
  box-shadow:
    rgba(185, 28, 28, 0.2) 0px 2px 2px -1px,
    rgba(185, 28, 28, 0.2) 0px 8px 8px -4px;
}

/* Fourth cell: a "Custom" pill that swaps for a free number field (e.g. +20) so
   classroom awards can keep pace with match swings. The button and input share
   the cell; the is-custom class on the row flips which one shows. */
.award-amount-custom {
  display: grid;
}
/* Scoped under .award-amounts so it outranks `.award-amounts button`
   (font-size: 1.5rem) on specificity — otherwise the "Custom" label inherits
   the big preset size. Beats needing !important. */
.award-amounts .award-custom-btn {
  font-family: 'Urbanist', sans-serif;
  font-weight: 800;
  font-size: 1.1rem;
  padding: 14px 0;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  transition: border-color 0.15s ease;
}
.award-amounts .award-custom-btn:hover {
  border-color: #cfd4dc;
}
.award-custom-input {
  display: none;
  width: 100%;
  text-align: center;
  font-family: 'Urbanist', sans-serif;
  font-weight: 800;
  font-size: 1.5rem;
  padding: 14px 0;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink);
}
.award-amounts.is-custom .award-custom-btn {
  display: none;
}
.award-amounts.is-custom .award-custom-input {
  display: block;
}
/* Selected highlight for the custom field, mirroring the preset selected state. */
.award-amounts.is-custom.is-pos .award-custom-input {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: #fff;
  transform: translateY(-2px);
  box-shadow:
    rgba(13, 122, 79, 0.25) 0px 2px 2px -1px,
    rgba(13, 122, 79, 0.2) 0px 8px 8px -4px;
}
.award-amounts.is-custom.is-neg .award-custom-input {
  background: var(--error);
  color: #fff;
  border-color: #fff;
  transform: translateY(-2px);
  box-shadow:
    rgba(185, 28, 28, 0.2) 0px 2px 2px -1px,
    rgba(185, 28, 28, 0.2) 0px 8px 8px -4px;
}
.award-amounts.is-custom.is-pos .award-custom-input:focus,
.award-amounts.is-custom.is-neg .award-custom-input:focus {
  outline: none;
  filter: brightness(1.03);
}

.award-comment {
  display: block;
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font: inherit;
  line-height: 1.45;
  min-height: 4.5em;
  resize: vertical;
  background: var(--surface);
  color: var(--ink);
  transition:
    border-color 0.15s ease,
    box-shadow 0.15s ease;
}
.award-comment::placeholder {
  color: var(--muted);
}
.award-comment:focus {
  outline: none;
  border-color: var(--ink);
  box-shadow: 0 0 0 3px rgba(17, 24, 39, 0.08);
}
.award-modal-actions {
  display: flex;
  justify-content: center;
}
.award-confirm-btn {
  width: 100%;
  padding: 14px 28px;
  font-size: 1rem;
  font-weight: 700;
  border-radius: var(--radius-pill);
  font-variant-numeric: tabular-nums;
}
.award-confirm-btn.is-deduct:not(:disabled) {
  background: var(--error);
  color: #fff;
}
/* Same raised, tactile shadow as the header buttons (lifts on hover, presses on
   active). `button.` prefix beats the generic .primary interaction styles. */
button.award-confirm-btn:not(:disabled) {
  box-shadow:
    rgba(0, 0, 0, 0.4) 0px 2px 4px,
    rgba(0, 0, 0, 0.3) 0px 7px 13px -3px,
    rgba(0, 0, 0, 0.2) 0px -3px 0px inset;
}
button.award-confirm-btn:not(:disabled):hover,
button.award-confirm-btn:not(:disabled):focus-visible {
  transform: translateY(-1px);
  filter: brightness(1.04);
  box-shadow:
    rgba(0, 0, 0, 0.45) 0px 4px 6px,
    rgba(0, 0, 0, 0.35) 0px 11px 20px -3px,
    rgba(0, 0, 0, 0.2) 0px -3px 0px inset;
}
button.award-confirm-btn:not(:disabled):active {
  transform: translateY(1px);
  filter: brightness(0.98);
  box-shadow:
    rgba(0, 0, 0, 0.4) 0px 1px 2px,
    rgba(0, 0, 0, 0.25) 0px 3px 6px -2px,
    rgba(0, 0, 0, 0.15) 0px -1px 0px inset;
}

/* One-shot confetti over the whole viewport when points are awarded. Reuses the
   season-finale fall keyframe; pieces are built + removed in JS. */
.award-confetti {
  position: fixed;
  inset: 0;
  z-index: 9999;
  overflow: hidden;
  pointer-events: none;
}
.award-confetti i {
  position: absolute;
  top: -16px;
  height: 14px;
  border-radius: 1px;
  opacity: 0;
  animation: finale-confetti-fall var(--dur, 2.6s) linear var(--delay, 0s)
    forwards;
}
@media (prefers-reduced-motion: reduce) {
  .award-confetti {
    display: none;
  }
}
html.is-reduced-motion .award-confetti {
  display: none;
}

/* Award toasts: a bottom-right stack that mirrors the matchday event card (medal
   icon, team, manager, points pill). A batch appears together in fixed slots and
   clears together, so nothing reflows mid-read. Plenty of width — the team name
   leads and may wrap rather than clip. */
.award-toast-stack {
  position: fixed;
  right: 24px;
  bottom: 24px;
  z-index: 10000;
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: flex-end;
  pointer-events: none;
}
.award-toast {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 13px;
  width: min(92vw, 440px);
  padding: 13px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow:
    rgba(0, 0, 0, 0.04) 0px 0px 0px 1px,
    rgba(0, 0, 0, 0.22) 0px 14px 34px -10px;
  animation: award-toast 3.2s ease-in-out forwards;
}
.award-toast-icon {
  display: inline-flex;
  width: 38px;
  height: 38px;
  flex: 0 0 auto;
}
.award-toast-icon img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.award-toast-text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.award-toast-title {
  font-weight: 700;
  color: var(--ink);
  line-height: 1.25;
}
.award-toast-sub {
  font-size: 0.8rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.award-toast-chip {
  display: inline-flex;
  align-items: center;
  align-self: start;
  margin-top: 2px;
  flex: 0 0 auto;
  padding: 3px 10px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  font-size: 0.82rem;
  color: var(--ink);
}
.award-toast-chip strong {
  color: var(--accent);
  font-weight: 800;
}
/* Deduction: red-tinted card and a red points pill, to reinforce the cost. */
.award-toast.is-deduct {
  background: #fef2f2;
  border-color: #fbd5d5;
}
.award-toast.is-deduct .award-toast-chip {
  background: #fff;
  border-color: #fbd5d5;
}
.award-toast.is-deduct .award-toast-chip strong {
  color: var(--error);
}
@keyframes award-toast {
  0% {
    opacity: 0;
    transform: translateY(12px);
  }
  18% {
    opacity: 1;
    transform: translateY(0);
  }
  78% {
    opacity: 1;
    transform: translateY(0);
  }
  100% {
    opacity: 0;
    transform: translateY(-10px);
  }
}
/* Reduced motion: just fade, no rise. */
@media (prefers-reduced-motion: reduce) {
  .award-toast {
    animation-name: award-toast-fade;
  }
}
html.is-reduced-motion .award-toast {
  animation-name: award-toast-fade;
}
@keyframes award-toast-fade {
  0% {
    opacity: 0;
  }
  18% {
    opacity: 1;
  }
  78% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
.manager-bonus-overlay {
  position: relative;
  background: var(--surface);
  border-radius: 16px;
  padding: 36px 40px 32px;
  text-align: center;
}
.overlay-close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  border: none;
  border-radius: var(--radius-md);
  padding: 0 0 4px;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
  box-shadow:
    var(--tint-row-cool) 0px 0px 0px 1px,
    rgba(42, 51, 69, 0.04) 0px 1px 1px -0.5px,
    var(--tint-row) 0px 3px 3px -1.5px,
    var(--tint-row) 0px 6px 6px -3px;
  transition:
    color 0.15s ease,
    background 0.15s ease;
}
.overlay-close:hover {
  color: var(--ink);
  background: var(--border);
}
.manager-bonus-eyebrow {
  margin: 0 0 6px;
  font-size: 0.8rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
}
.manager-bonus-name {
  font-family: 'Urbanist', sans-serif;
  font-weight: 900;
  font-size: clamp(2rem, 4vw, 2.8rem);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 0 0 32px;
}
.manager-bonus-total {
  margin: 0 0 18px;
  font-size: 0.95rem;
  color: var(--muted);
}
.manager-bonus-total strong {
  font-weight: 900;
  color: var(--ink);
  font-size: 1.15rem;
  margin-right: 2px;
}
.manager-bonus-history {
  margin-top: 18px;
  text-align: left;
  border-top: 1px solid var(--border);
  padding-top: 14px;
}
.manager-bonus-history .section-label {
  margin-bottom: 8px;
}
.manager-bonus-history ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: min(360px, 50vh);
  overflow-y: auto;
}
.manager-bonus-history li {
  display: grid;
  grid-template-columns: 40px 1fr auto auto;
  gap: 12px;
  align-items: center;
  font-size: 0.9rem;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
}
.bonus-history-delete {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  width: 28px;
  height: 28px;
  padding: 0;
  border-radius: var(--radius-sm);
  color: var(--muted);
  cursor: pointer;
  transition:
    color 0.15s ease,
    background 0.15s ease;
}
.bonus-history-delete svg {
  display: block;
}
.bonus-history-delete:hover {
  color: var(--error);
  background: rgba(185, 28, 28, 0.08);
}
.manager-bonus-history li:last-child {
  border-bottom: none;
}
.bonus-history-delta {
  font-weight: 900;
  font-size: 1.05rem;
  text-align: center;
}
.bonus-history-delta.is-pos {
  color: var(--accent);
}
.bonus-history-delta.is-neg {
  color: var(--error);
}
.bonus-history-body {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.bonus-history-category {
  display: inline-block;
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  background: var(--bg);
  border: 1px solid var(--border);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--ink);
  flex-shrink: 0;
}
.bonus-history-reason {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--ink);
  min-width: 0;
}
.bonus-history-date {
  font-size: 0.78rem;
}

/* Admin page — internal-only, reachable via /admin */
/* Full-width, light-grey admin app (converging on the Triptico admin layout). */
.admin-page {
  max-width: none;
  margin: 0;
  padding: 0;
  min-height: 100vh;
  background: var(--bg);
}
/* White header band, full width. */
.admin-page .privacy-header {
  margin: 0;
  padding: 18px 32px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.admin-page .privacy-title {
  margin: 0;
  font-family: 'Urbanist', sans-serif;
  font-weight: 900;
  font-size: 1.5rem;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.admin-page .privacy-lede {
  margin: 4px 0 0;
  font-size: 0.9rem;
  color: var(--muted);
}
.admin-section {
  margin: 0;
  padding: 24px 32px;
}
@media (max-width: 720px) {
  .admin-page .privacy-header,
  .admin-section {
    padding-left: 16px;
    padding-right: 16px;
  }
}
.admin-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
  max-width: 360px;
}
.admin-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 0.95rem;
}
.admin-field input {
  font: inherit;
  padding: 10px 12px;
  border: 1px solid rgba(0, 0, 0, 0.18);
  border-radius: var(--radius-md);
  background: #fff;
}
.admin-form button.primary {
  align-self: flex-start;
  margin-top: 4px;
}
.admin-error {
  color: #b00020;
  margin: 0;
  min-height: 1.2em;
  font-size: 0.92rem;
}
.admin-info {
  color: var(--success-strong);
  margin: 0;
  min-height: 1.2em;
  font-size: 0.92rem;
}
.admin-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-bottom: 24px;
  flex-wrap: wrap;
}
.admin-account {
  margin: 0;
  font-size: 0.9rem;
}
.admin-signout-link {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--ink);
  opacity: 0.7;
  text-decoration: underline;
  cursor: pointer;
}
.admin-signout-link:hover {
  opacity: 1;
}
.admin-toolbar-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Stats summary bar */
.admin-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 12px;
  margin-bottom: 24px;
}
.admin-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 18px 12px;
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow:
    rgba(0, 0, 0, 0.4) 0px 2px 4px,
    rgba(0, 0, 0, 0.3) 0px 7px 13px -3px,
    rgba(0, 0, 0, 0.2) 0px -3px 0px inset;
}
/* The Users + Leagues stats deep-link to their tab. */
.admin-stat[data-goto-tab] {
  cursor: pointer;
  transition:
    transform 0.12s ease,
    filter 0.12s ease;
}
.admin-stat[data-goto-tab]:hover {
  filter: brightness(1.06);
  transform: translateY(-1px);
}
.admin-stat[data-goto-tab]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.admin-stat-value {
  font-family: 'Urbanist', sans-serif;
  font-weight: 900;
  font-size: 1.9rem;
  line-height: 1;
  color: var(--accent);
}
.admin-stat-label {
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  text-wrap: balance;
  text-align: center;
}

/* Tabs + unread badges — reuses the app's main-tab segmented control look
   (.tabs-main / .tab-main): a bordered pill panel with the active tab in green. */
.admin-tabs {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
  margin-bottom: 24px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 6px;
  box-shadow: var(--shadow);
}
.admin-tab {
  flex: 1 1 auto;
  background: transparent;
  border: none;
  padding: 8px 16px;
  border-radius: var(--radius-sm);
  font: inherit;
  font-weight: 600;
  font-size: 0.92rem;
  color: var(--muted);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition:
    background 0.1s,
    color 0.1s;
}
.admin-tab:hover {
  color: var(--ink);
}
.admin-tab.is-active {
  background: var(--accent);
  color: var(--accent-ink);
}
.admin-tab.is-active:hover {
  color: var(--accent-ink);
}
.admin-badge {
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--error);
  color: #fff;
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
}

/* Tab panels — only the active one shows */
.admin-tab-panel {
  display: none;
}
.admin-tab-panel.is-active {
  display: block;
}

/* Inbox sub-tabs (Interest / Contact / Feedback) — mirrors the app's .tabs-sub
   (small uppercase, light-yellow active) so it reads as a secondary row. */
.admin-subtabs {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
  margin-bottom: 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 6px;
  box-shadow: var(--shadow);
}
.admin-subtab {
  flex: 1 1 auto;
  background: transparent;
  border: none;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font: inherit;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  transition:
    background 0.1s,
    color 0.1s;
}
.admin-subtab:hover {
  color: var(--ink);
}
.admin-subtab.is-active {
  background: #fde68a;
  color: var(--ink);
}
.admin-subpanel {
  display: none;
}
.admin-subpanel.is-active {
  display: block;
}
.admin-collection {
  margin-bottom: 40px;
}
.admin-count {
  font-weight: 400;
  opacity: 0.6;
  margin-left: 6px;
}
.admin-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: 0 1px 3px rgba(9, 30, 66, 0.04);
}
.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}
.admin-table th,
.admin-table td {
  text-align: left;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
.admin-table th {
  background: var(--bg);
  font-weight: 700;
  font-size: 0.74rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
/* Click-to-sort headers (Teachers + Leagues tables). A neutral ↕ marks sortable
   columns; the active column shows ↑/↓ and darkens. */
.admin-table th.admin-th-sortable {
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.admin-table th.admin-th-sortable::after {
  content: '↕';
  margin-left: 6px;
  opacity: 0.3;
  font-size: 0.9em;
}
.admin-table th.admin-th-sortable:hover,
.admin-table th.admin-th-sortable[aria-sort] {
  color: var(--ink);
}
.admin-table th.admin-th-sortable[aria-sort='ascending']::after {
  content: '↑';
  opacity: 1;
}
.admin-table th.admin-th-sortable[aria-sort='descending']::after {
  content: '↓';
  opacity: 1;
}
.admin-table th.admin-th-sortable:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.admin-table tbody tr:last-child td {
  border-bottom: none;
}
.admin-table tbody tr:hover {
  background: var(--bg);
}
.admin-when {
  white-space: nowrap;
  color: var(--muted);
}
.admin-email a {
  color: var(--accent);
  font-weight: 600;
  text-decoration: none;
}
.admin-email a:hover {
  text-decoration: underline;
}
/* Email-verification status in the Teachers table. Verified is low-key; an
   unverified teacher gets an amber pill so a stuck signup is easy to spot. */
.admin-verified {
  color: var(--muted);
  font-size: 0.82rem;
}
.admin-unverified {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  background: #fff7e6;
  color: var(--warning-strong);
  border: 1px solid var(--warning);
  font-size: 0.78rem;
  font-weight: 700;
  white-space: nowrap;
}
.admin-message {
  white-space: pre-wrap;
  max-width: 420px;
}
.admin-empty {
  margin: 12px 0 0;
  font-style: italic;
  opacity: 0.7;
}
.admin-filter {
  font: inherit;
  font-size: 0.78rem;
  padding: 4px 8px;
  border: 1px solid rgba(0, 0, 0, 0.18);
  border-radius: var(--radius-sm);
  margin-left: 12px;
  text-transform: none;
  letter-spacing: 0;
}
.admin-error-row .admin-when,
.admin-error-row .admin-error-message {
  cursor: pointer;
}
.admin-error-row .admin-error-message:hover,
.admin-error-row .admin-when:hover {
  background: rgba(0, 0, 0, 0.04);
}
.admin-error-message {
  max-width: 360px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.82rem;
}
.admin-url {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.82rem;
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: rgba(0, 0, 0, 0.65);
}
.admin-user {
  font-size: 0.85rem;
  color: rgba(0, 0, 0, 0.65);
}
.admin-actions-col {
  text-align: right;
  white-space: nowrap;
}
.admin-pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: rgba(0, 0, 0, 0.06);
}
.admin-pill--uncaught {
  background: rgba(176, 0, 32, 0.12);
  color: #b00020;
}
.admin-pill--promise {
  background: rgba(212, 119, 0, 0.14);
  color: #8a4b00;
}
.admin-pill--caught {
  background: rgba(10, 108, 44, 0.12);
  color: var(--success-strong);
}
.admin-dismiss-btn {
  font: inherit;
  font-size: 0.8rem;
  padding: 4px 10px;
  border: 1px solid rgba(0, 0, 0, 0.18);
  border-radius: var(--radius-sm);
  background: #fff;
  cursor: pointer;
}
.admin-dismiss-btn:hover {
  background: rgba(0, 0, 0, 0.04);
}
.admin-dismiss-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
/* Icon-only delete on inbox rows — quiet by default, turns red on hover/focus. */
.admin-del-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
  transition:
    color 0.15s ease,
    border-color 0.15s ease,
    background 0.15s ease;
}
.admin-del-btn svg {
  width: 15px;
  height: 15px;
  fill: currentColor;
}
.admin-del-btn:hover,
.admin-del-btn:focus-visible {
  color: var(--error);
  border-color: var(--error);
  background: var(--bg);
}
.admin-del-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.admin-modal-meta {
  margin: 0 0 16px;
  font-size: 0.85rem;
  opacity: 0.7;
}
.admin-modal-label {
  margin: 16px 0 4px;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 700;
  opacity: 0.7;
}
.admin-modal-pre {
  margin: 0;
  padding: 10px 12px;
  background: rgba(0, 0, 0, 0.04);
  border-radius: var(--radius-sm);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.82rem;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 240px;
  overflow: auto;
}
.admin-modal-pre--small {
  font-size: 0.72rem;
  max-height: 80px;
}
#error-modal {
  width: min(94vw, 720px);
  padding: 32px;
}

/* ----- My Team tab (teacher's own entry in the league) ----- */

.my-team-empty,
.my-team-card {
  max-width: 560px;
  margin: 0 auto;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.my-team-empty {
  margin-top: 38px;
}

.my-team-heading {
  font-family: 'Nunito', sans-serif;
  font-weight: 700;
  margin: 0 0 12px;
  font-size: 1.5rem;
  letter-spacing: -0.01em;
}

.my-team-empty p {
  margin: 0 0 12px;
  line-height: 1.5;
}

.my-team-actions {
  margin-top: 20px;
  display: flex;
  justify-content: center;
  gap: 12px;
}
/* The trade block stacks its hint under the button rather than beside it. */
.my-team-trade-actions {
  flex-direction: column;
  align-items: center;
  gap: 10px;
}
.my-team-trade-hint {
  margin: 0;
  text-align: center;
}

.my-team-card-head {
  margin-bottom: 18px;
}
.my-team-card-head .section-label {
  margin-bottom: 6px;
}
.my-team-name {
  margin: 0 0 4px;
  font-size: 1.4rem;
  letter-spacing: -0.01em;
}
.my-team-card-head p {
  margin: 0;
}

.my-team-pending {
  margin: 0 0 18px;
  line-height: 1.5;
}

/* Confirmed-team view — mirrors the student's own-team layout (manager,
   supporting, players, team total) so the teacher gets the same level of
   detail without leaving the dashboard. The block CSS lives under
   #slots-panel.is-locked on the student page; we reach the same look by
   scoping equivalent rules under .my-team-confirmed here. */
.my-team-confirmed {
  display: block;
  max-width: 960px;
  margin: 0 auto;
}
.my-team-confirmed .my-team-heading {
  text-align: left;
  margin: 0 0 14px;
  font-size: 1.6rem;
}
.my-team-confirmed .manager-block {
  display: block;
  padding-bottom: 14px;
}
.my-team-confirmed .supporting-block {
  display: block;
  border-top: 1px solid var(--border);
  padding-top: 14px;
  padding-bottom: 14px;
}
/* Manager + Supporting side by side on wider screens. Each block loses its
   stacked-layout border/padding inside the row; .section-label tightens up
   too so the label sits closer to its value. */
.my-team-confirmed .my-team-top-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  padding-bottom: 14px;
}
.my-team-confirmed .my-team-top-row .manager-block,
.my-team-confirmed .my-team-top-row .supporting-block {
  border-top: none;
  padding: 0;
}
.my-team-confirmed .my-team-top-row .section-label {
  margin-bottom: 2px;
}
@media (max-width: 640px) {
  /* Mobile: stack as before, restore the divider between the two blocks. */
  .my-team-confirmed .my-team-top-row {
    grid-template-columns: 1fr;
    gap: 0;
    padding-bottom: 0;
  }
  .my-team-confirmed .my-team-top-row .manager-block {
    padding-bottom: 14px;
  }
  .my-team-confirmed .my-team-top-row .supporting-block {
    border-top: 1px solid var(--border);
    padding-top: 14px;
    padding-bottom: 14px;
  }
}
.my-team-confirmed .supporting-row {
  cursor: pointer;
}
.my-team-confirmed .players-block,
.my-team-confirmed .team-total {
  border-top: 1px solid var(--border);
  padding-top: 14px;
  padding-bottom: 14px;
}
.my-team-confirmed .team-total {
  display: block;
  text-align: right;
  padding-bottom: 0;
}
.my-team-confirmed .team-total .section-label {
  text-align: left;
}
.my-team-confirmed .slot-row {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 12px;
  max-width: 1124px;
  margin: 0 auto;
  justify-content: center;
}
/* These confirmed-team cards are clickable (open the player), so give them the
   same subtle lift on hover as the TOP PLAYERS cards. The box-shadow already
   comes from .slot.is-filled:hover; this adds the matching translate and cancels
   the green-text hover (the whole-slot data-player-link would tint the name),
   since the lift now carries the affordance. */
.my-team-confirmed .slot.is-filled:hover {
  transform: translateY(-2px);
  color: inherit;
}

/* ----- 404 page ----- */
.notfound {
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 18px;
  padding: 40px 24px;
}
.notfound-img {
  width: min(340px, 70vw);
  height: auto;
}
.notfound h1 {
  margin: 0;
  font-size: clamp(1.6rem, 4vw, 2.2rem);
}
.notfound p {
  margin: 0;
  max-width: 34ch;
  color: var(--muted);
}
.notfound-home {
  margin-top: 6px;
  background: var(--accent);
  color: var(--accent-ink);
  text-decoration: none;
  font-weight: 700;
  padding: 12px 22px;
  border-radius: var(--radius-md);
  transition:
    filter 0.15s ease,
    transform 0.15s ease;
}
.notfound-home:hover {
  filter: brightness(1.05);
  transform: translateY(-1px);
}

/* Child-friendly privacy line on the student page (Children's Code Standard 4:
   transparency in language suited to the age of the child). Quiet and always
   present, never a modal that nags. */
.student-privacy-note {
  margin: 32px auto 8px;
  max-width: 640px;
  text-align: center;
}
.student-privacy-note p {
  margin: 0;
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--muted);
}
