:root {
  --bg: #f4f5f7;
  --card: #ffffff;
  --text: #1c1f26;
  --muted: #6b7280;
  --accent: #1d6f42;
  --accent-dark: #144f2f;
  --border: #e3e5e9;
  --total-bg: #eef6f0;
  --gold-bg: #f4c542;
  --gold-text: #3b2c00;
  --silver-bg: #cdd3db;
  --silver-text: #2e3238;
  --bronze-bg: #dda06a;
  --bronze-text: #3a2410;
  --poop-bg: #6b4423;
  --poop-text: #ffffff;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  padding: 0 16px 48px;
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  /* A photographic-style "stadium at night" backdrop: two warm stadium-
     light flares glowing near the top corners, over a dark night sky
     that eases down into a green turf horizon, with faint yard-line
     ticks across the lower/turf band. Fixed so the whole scene stays
     put while the page scrolls — background-size covers the full
     viewport so the same composition is always in view no matter the
     scroll position. This is a single always-on look rather than one
     that swaps with light/dark mode, since the scene is inherently a
     night shot; see the light-text + shadow rules below for the page
     content that sits directly on this backdrop instead of inside a
     card. */
  background-color: #0a1a13;
  background-image:
    repeating-linear-gradient(
      90deg,
      rgba(255, 255, 255, 0.12) 0,
      rgba(255, 255, 255, 0.12) 2px,
      transparent 2px,
      transparent 110px
    ),
    radial-gradient(ellipse 620px 380px at 10% 6%, rgba(255, 244, 214, 0.55), rgba(255, 244, 214, 0) 68%),
    radial-gradient(ellipse 620px 380px at 90% 4%, rgba(255, 244, 214, 0.5), rgba(255, 244, 214, 0) 68%),
    linear-gradient(180deg, #05090f 0%, #081b18 34%, #103b26 60%, #1d5c34 100%);
  background-repeat: repeat-x, no-repeat, no-repeat, no-repeat;
  background-position: bottom left, top left, top right, top left;
  background-size: 100% 42%, 100% 100%, 100% 100%, 100% 100%;
  background-attachment: fixed, fixed, fixed, fixed;
}

.site-header {
  max-width: 960px;
  margin: 0 auto;
  padding: 40px 0 8px;
  text-align: center;
}

.site-header h1 {
  margin: 0;
  font-family: "Anton", "Arial Narrow", Impact, sans-serif;
  font-weight: 400;
  font-size: clamp(2.2rem, 6vw, 3.4rem);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  /* Honors an actual line break typed into the Page Title cell (Alt+Enter
     in Google Sheets/Excel) as a real line break here, instead of the
     browser collapsing it to a space and wrapping wherever it feels like.
     Long lines still wrap normally on their own if they don't fit. */
  white-space: pre-line;
  /* Sits directly on the stadium backdrop rather than inside a card, so
     it's given a fixed light color + a solid dark shadow (in addition to
     the decorative flag-colored glow) to stay legible over both the dark
     sky and bright turf portions of that backdrop. */
  color: #fbfbf8;
  text-shadow: 0 0 20px rgba(206, 17, 38, 0.45), 0 0 34px rgba(0, 99, 65, 0.4), 0 2px 8px rgba(0, 0, 0, 0.9);
  line-height: 1.05;
}

/* Flag-stripe divider between sections (banner, podium, commish
   message, standings, footer). Placed as the first thing INSIDE each
   show/hide-toggled section so it only appears when that section
   actually does — no orphaned stripes when a section is hidden. */
.section-divider {
  margin: 0 auto 24px;
  text-align: center;
  font-size: 1.1rem;
  letter-spacing: 0.3em;
  line-height: 1;
  flex-shrink: 0;
}

.subtitle {
  margin: 10px 0 0;
  color: #f1f2ee;
  text-shadow: 0 1px 5px rgba(0, 0, 0, 0.85);
  font-size: 0.95rem;
}

.banner {
  max-width: 960px;
  margin: 20px auto 0;
}

.banner a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--accent);
  color: #fff;
  text-decoration: none;
  padding: 16px 20px;
  border-radius: 10px;
  font-weight: 600;
  transition: background 0.15s ease;
}

.banner a:hover {
  background: var(--accent-dark);
}

.banner-main {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  row-gap: 4px;
}

.banner-countdown {
  font-family: "Space Mono", "Courier New", Courier, monospace;
  font-weight: 700;
  font-size: 0.82rem;
  letter-spacing: 0.02em;
  background: rgba(255, 255, 255, 0.2);
  padding: 3px 10px;
  border-radius: 999px;
  white-space: nowrap;
  transition: font-size 0.15s ease, padding 0.15s ease;
}

/* Once the deadline passes, script.js swaps the countdown's text for
   "Contest locked" and adds this class -- bigger pill, flashing to
   catch the eye, standing in alone since the banner's own "click here
   to enter" text hides itself at the same time. */
.banner-countdown-locked {
  font-size: 1.05rem;
  padding: 6px 16px;
  animation: banner-countdown-flash 1.1s ease-in-out infinite;
}

@keyframes banner-countdown-flash {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}

@media (prefers-reduced-motion: reduce) {
  .banner-countdown-locked {
    animation: none;
  }
}

.banner-arrow {
  font-size: 1.1rem;
  flex-shrink: 0;
}

main {
  max-width: 1100px;
  margin: 32px auto 0;
}

/* Weekly podium — top 3 finishers of the most recently played week,
   with photos (or a default silhouette) from the sheet's Photo column. */
.podium-section {
  text-align: center;
  margin-bottom: 32px;
}

.podium-header {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 10px;
  margin-bottom: 16px;
}

.podium-header h2 {
  margin: 0;
  font-size: 1.1rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #f1f2ee;
  text-shadow: 0 1px 5px rgba(0, 0, 0, 0.85);
}

.podium-week-label {
  font-size: 0.85rem;
  font-weight: 700;
  color: #bdf0cf;
  text-shadow: 0 1px 5px rgba(0, 0, 0, 0.85);
}

.podium {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 18px;
}

.podium-slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 130px;
}

.podium-photo-wrap {
  position: relative;
  margin-bottom: 8px;
}

.podium-photo {
  display: block;
  width: 84px;
  height: 84px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--card);
  border: 3px solid var(--border);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}

.podium-slot-1 .podium-photo {
  width: 108px;
  height: 108px;
  border-color: var(--gold-bg);
}

.podium-slot-2 .podium-photo {
  border-color: var(--silver-bg);
}

.podium-slot-3 .podium-photo {
  border-color: var(--bronze-bg);
}

.podium-silhouette .sil-bg {
  fill: var(--border);
}

.podium-silhouette .sil-fg {
  fill: var(--card);
}

.podium-name {
  font-weight: 700;
  font-size: 0.92rem;
  margin-bottom: 8px;
  max-width: 130px;
  overflow-wrap: break-word;
  color: #fbfbf8;
  text-shadow: 0 1px 5px rgba(0, 0, 0, 0.85);
}

.podium-step {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px 8px 0 0;
  font-weight: 800;
}

.podium-place {
  font-size: 0.95rem;
  white-space: nowrap;
}

.podium-slot-1 .podium-step {
  height: 92px;
  background: var(--gold-bg);
  color: var(--gold-text);
}

.podium-slot-2 .podium-step {
  height: 62px;
  background: var(--silver-bg);
  color: var(--silver-text);
}

.podium-slot-3 .podium-step {
  height: 46px;
  background: var(--bronze-bg);
  color: var(--bronze-text);
}

/* Optional "Winner's Quote" line under the podium (set from the
   sheet), boxed up in its own opaque card — like the standings table
   and Commish window — rather than sitting bare on the stadium
   backdrop, so it reads like a little highlighted code/quote block.
   Flanked by a pair of gold laurel branches, mirror images of each
   other, like a classic film-festival "award laurel." */
.winner-quote-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  max-width: 660px;
  margin: 32px auto 0;
}

.winner-quote-card {
  position: relative;
  max-width: 560px;
  margin: 0;
  padding: 14px 20px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
  text-align: center;
  overflow: hidden;
}

.winner-quote-label {
  display: block;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 4px;
}

.winner-quote-text {
  display: block;
  font-style: italic;
  font-size: 1.05rem;
  color: var(--text);
}

.winner-quote-text::before {
  content: "\201C";
}

.winner-quote-text::after {
  content: "\201D";
}

.laurel {
  flex-shrink: 0;
  width: 46px;
  height: auto;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.4));
}

.laurel-right {
  transform: scaleX(-1);
}

.laurel-stem {
  fill: none;
  stroke: #a8790a;
  stroke-width: 2;
  stroke-linecap: round;
}

.laurel-leaf {
  fill: #e0b52c;
  stroke: #a8790a;
  stroke-width: 0.6;
}

/* A slow diagonal "sheen" that sweeps all the way across the item,
   then pauses off to the side before sweeping again — used on the 1st
   place podium photo and on the Winner's Quote card (both opaque
   surfaces, so an overlay box reads fine on them). It's a single
   bright diagonal band (::before), clipped to the item's own shape by
   overflow:hidden on this wrapper, and screen-blended so it brightens
   whatever's underneath rather than whiting it out. Each usage below
   sets its own shape/size and a slightly different animation-delay so
   the two don't sweep in lockstep. (The "Season Standings" heading
   used to reuse this too, but as see-through gradient text rather
   than a solid surface, the overlay's own box showed as a visible
   rectangle outside the letters -- it now gets its shine a different
   way, see .standings-heading-inner below.) */
.lens-flare {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 5;
}

.lens-flare::before {
  content: "";
  position: absolute;
  top: -60%;
  left: -45%;
  width: 55%;
  height: 220%;
  background: linear-gradient(
    100deg,
    transparent 0%,
    transparent 35%,
    rgba(255, 255, 255, 0.85) 50%,
    rgba(255, 233, 168, 0.5) 58%,
    transparent 75%,
    transparent 100%
  );
  mix-blend-mode: screen;
  animation: lens-flare-sweep 5s ease-in-out infinite;
}

@keyframes lens-flare-sweep {
  0% { left: -45%; }
  50% { left: 115%; }
  100% { left: 115%; }
}

@media (prefers-reduced-motion: reduce) {
  .lens-flare::before {
    animation: none;
    display: none;
  }
}

.lens-flare-podium {
  border-radius: 50%;
}

.lens-flare-quote {
  border-radius: 10px;
}

.lens-flare-quote::before {
  animation-delay: 1.6s;
}

/* "The Dumpster" — whoever finished last in the most recent contest,
   shown peeking out of a dumpster with a poop-emoji crown. Sits
   directly on the stadium backdrop like the podium heading above it,
   so it gets the same light-text + shadow treatment. */
.dumpster-section {
  text-align: center;
  margin-bottom: 32px;
}

.dumpster-header {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 10px;
  margin-bottom: 16px;
}

.dumpster-heading {
  margin: 0;
  font-size: 1.1rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #f1f2ee;
  text-shadow: 0 1px 5px rgba(0, 0, 0, 0.85);
}

.dumpster-week-label {
  font-size: 0.85rem;
  font-weight: 700;
  color: #bdf0cf;
  text-shadow: 0 1px 5px rgba(0, 0, 0, 0.85);
}

.dumpster-block {
  width: 220px;
  margin: 0 auto;
}

.dumpster-scene {
  position: relative;
  width: 220px;
  height: 210px;
  margin: 0 auto;
}

.dumpster-graphic {
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1;
  display: block;
}

.dumpster-graphic .dg-body,
.dumpster-graphic .dg-lid,
.dumpster-graphic .dg-handle {
  fill: var(--accent);
  stroke: var(--accent-dark);
}

.dumpster-graphic .dg-rim {
  fill: var(--accent-dark);
}

.dumpster-graphic .dg-ridge {
  stroke: var(--accent-dark);
}

.dumpster-graphic .dg-wheel {
  fill: #1a1a1a;
}

.dumpster-photo-row {
  position: absolute;
  bottom: 55px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  display: flex;
  justify-content: center;
  gap: 8px;
}

.dumpster-photo,
.dumpster-photo-silhouette {
  width: 92px;
  height: 92px;
  border-radius: 50%;
  object-fit: cover;
  border: 3px solid #fff;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.4);
  background: var(--card);
  display: block;
  flex-shrink: 0;
}

.dumpster-photo-silhouette .sil-bg {
  fill: var(--border);
}

.dumpster-photo-silhouette .sil-fg {
  fill: var(--card);
}

.dumpster-crown-stack {
  position: absolute;
  bottom: 138px;
  left: 50%;
  transform: translateX(-50%);
  line-height: 1;
  z-index: 3;
}

.dumpster-poop-emoji {
  position: absolute;
  top: 8px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1;
  font-size: 34px;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.4));
}

.dumpster-crown-emoji {
  position: relative;
  z-index: 2;
  display: block;
  font-size: 42px;
  clip-path: inset(0 0 45% 0);
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.5));
}

.dumpster-name {
  margin-top: 12px;
  font-weight: 800;
  color: #fbfbf8;
  text-shadow: 0 1px 5px rgba(0, 0, 0, 0.85);
}

/* Optional "Loser's Quote" line under The Dumpster (set from the
   sheet), boxed up the same way as the Winner's Quote card — but with
   a swirling green gas haze inside instead of laurels (see .gas-cloud,
   below). */
.loser-quote-wrap {
  max-width: 560px;
  margin: 46px auto 0;
}

.loser-quote-card {
  margin: 0;
  padding: 14px 20px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
  text-align: center;
  position: relative;
  z-index: 1;
  overflow: hidden;
}

/* A slow-drifting greenish gas haze inside the card — a few soft,
   blurred blobs, each wandering along its own loose loop so they
   never quite line up, sitting behind the text (negative z-index puts
   it under the card's own in-flow content regardless of DOM order)
   and clipped to the card's rounded corners by the overflow:hidden
   above. Plain semi-transparent fills rather than a blend mode, so it
   reads the same greenish haze over both the light and dark card. */
.gas-cloud {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

.gas-blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(18px);
}

.gas-blob-1 {
  width: 40%;
  aspect-ratio: 1;
  left: -8%;
  top: -55%;
  background: rgba(143, 191, 47, 0.55);
  animation: gas-drift-1 9s ease-in-out infinite;
}

.gas-blob-2 {
  width: 46%;
  aspect-ratio: 1;
  left: 36%;
  top: -15%;
  background: rgba(182, 224, 67, 0.5);
  animation: gas-drift-2 12s ease-in-out infinite;
}

.gas-blob-3 {
  width: 42%;
  aspect-ratio: 1;
  right: -8%;
  bottom: -65%;
  background: rgba(143, 191, 47, 0.45);
  animation: gas-drift-3 10.5s ease-in-out infinite;
}

@keyframes gas-drift-1 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50% { transform: translate(18%, 12%) scale(1.15); }
}

@keyframes gas-drift-2 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50% { transform: translate(-14%, 16%) scale(0.9); }
}

@keyframes gas-drift-3 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50% { transform: translate(-16%, -10%) scale(1.1); }
}

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

.loser-quote-label {
  display: block;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 4px;
}

.loser-quote-text {
  display: block;
  font-style: italic;
  font-size: 1.05rem;
  color: var(--text);
}

.loser-quote-text::before {
  content: "\201C";
}

.loser-quote-text::after {
  content: "\201D";
}

@media (max-width: 520px) {
  .podium {
    gap: 10px;
  }

  .podium-slot {
    width: 90px;
  }

  .podium-photo {
    width: 60px;
    height: 60px;
  }

  .podium-slot-1 .podium-photo {
    width: 76px;
    height: 76px;
  }

  .podium-name {
    font-size: 0.76rem;
  }

  .podium-place {
    font-size: 0.82rem;
  }

  .dumpster-block,
  .dumpster-scene {
    width: 170px;
  }

  .dumpster-scene {
    height: 168px;
  }

  .dumpster-graphic {
    width: 170px;
    height: 124px;
  }

  .dumpster-photo-row {
    bottom: 42px;
  }

  .dumpster-photo,
  .dumpster-photo-silhouette {
    width: 72px;
    height: 72px;
  }

  .dumpster-crown-stack {
    bottom: 106px;
  }

  .dumpster-poop-emoji {
    top: 6px;
    font-size: 28px;
  }

  .dumpster-crown-emoji {
    font-size: 34px;
  }

  .winner-quote-wrap {
    gap: 0;
    margin-top: 26px;
  }

  .laurel {
    width: 30px;
  }

  .winner-quote-card,
  .loser-quote-card {
    padding: 12px 14px;
  }

  .loser-quote-wrap {
    margin-top: 34px;
  }
}

/* The standings table (heading, legend and table -- NOT the Current
   Leader photo panel next to it) opens like a pair of mechanical bay
   doors as you scroll down to it: two metal panels meet in the
   middle over the content, then slide apart -- top one up, bottom
   one down -- to reveal it. script.js only arms this (.js-door-armed,
   which is what actually hides the doors' content underneath up
   front) once the standings have real rows in them, and only when
   JS + IntersectionObserver + prefers-reduced-motion all allow it,
   so with JS off or motion reduced the table's just there already --
   no doors, nothing to trip over. This is now the direct flex child
   of .standings-layout (the Current Leader photo panel is the other
   one, sitting outside the doors), so it carries the same
   flex-sizing/shrink rules .standings-section used to have on its
   own -- see below. */
.standings-door-wrap {
  position: relative;
  overflow: hidden;
  flex: 1 1 auto;
  min-width: 0;
  /* NOTE: deliberately no touch-action override here. A touch-action
     set on this wrap would also constrain its descendants (per spec,
     the effective touch-action of an element is the intersection of
     its own and all its ancestors' values) -- an earlier pan-y-only
     version of this rule ended up blocking horizontal swipes on the
     .table-scroll box nested inside, so the standings table couldn't
     be scrolled sideways on mobile. Leaving this at the default
     (auto) lets normal scrolling -- vertical page scroll AND
     horizontal table scroll -- pass through untouched; the doors
     never capture pointer events themselves since they're
     pointer-events:none (see .standings-door below).  */
}

.standings-door {
  position: absolute;
  left: 0;
  right: 0;
  height: 50%;
  z-index: 5;
  pointer-events: none;
  display: none;
  /* Promotes each door to its own compositor layer before the
     animation starts, instead of only once it's already moving —
     avoids a jank/scroll-stutter some mobile browsers show when a
     transform-animation kicks off inside an overflow:hidden box. */
  will-change: transform;
  background:
    repeating-linear-gradient(
      0deg,
      rgba(255, 255, 255, 0.09) 0,
      rgba(255, 255, 255, 0.09) 2px,
      transparent 2px,
      transparent 15px
    ),
    linear-gradient(180deg, #9a9fa8, #565a62);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.4);
}

.standings-door::after {
  /* The hazard-stripe seam where the two doors meet in the middle. */
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 10px;
  background: repeating-linear-gradient(
    45deg,
    #f4c430 0,
    #f4c430 10px,
    #1a1a1a 10px,
    #1a1a1a 20px
  );
  box-shadow: 0 0 6px rgba(0, 0, 0, 0.6);
}

.standings-door-top {
  top: 0;
  transform-origin: top;
  border-bottom: 2px solid #2c2e33;
}

.standings-door-top::after {
  bottom: -2px;
}

.standings-door-bottom {
  bottom: 0;
  transform-origin: bottom;
  border-top: 2px solid #2c2e33;
}

.standings-door-bottom::after {
  top: -2px;
}

.standings-door-wrap.js-door-armed .standings-door {
  display: block;
}

.standings-door-wrap.door-play .standings-door-top {
  animation: standings-door-open-up 2.6s cubic-bezier(0.6, 0, 0.3, 1) 1s forwards;
}

.standings-door-wrap.door-play .standings-door-bottom {
  animation: standings-door-open-down 2.6s cubic-bezier(0.6, 0, 0.3, 1) 1s forwards;
}

/* "THE STANDINGS", spray-painted across the closed doors so there's
   something to read while they're shut -- sits in front of both
   panels (higher z-index), fades out right as they start sliding
   apart so it feels like it's being carried away with them. */
.standings-door-label {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 6;
  transform: translate(-50%, -50%) rotate(-15deg);
  pointer-events: none;
  display: none;
  font-family: "Permanent Marker", "Segoe Print", "Comic Sans MS", cursive;
  font-size: clamp(2.4rem, 10.5vw, 4.2rem);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  white-space: nowrap;
  color: #ffffff;
  /* Layered shadows stand in for a rough spray-can edge: a tight
     black "overspray" ring close to the letters, then a couple of
     softer, offset dark-red passes further out like the can wasn't
     held quite steady. */
  text-shadow:
    -1px -1px 0 #1a1a1a,
    1px -1px 0 #1a1a1a,
    -1px 1px 0 #1a1a1a,
    1px 1px 0 #1a1a1a,
    0 0 6px rgba(0, 0, 0, 0.55),
    2px 3px 0 rgba(120, 20, 10, 0.3),
    -3px 2px 0 rgba(120, 20, 10, 0.2),
    0 0 18px rgba(255, 255, 255, 0.45);
  /* A faint mist of overspray dots bleeding past the letters. */
  filter: drop-shadow(0 0 10px rgba(255, 255, 255, 0.3));
}

.standings-door-label::before {
  content: "";
  position: absolute;
  inset: -27px -39px;
  z-index: -1;
  background-image: radial-gradient(circle, rgba(255, 255, 255, 0.2) 1.5px, transparent 1.6px);
  background-size: 9px 9px;
  -webkit-mask-image: radial-gradient(ellipse at center, #000 45%, transparent 78%);
  mask-image: radial-gradient(ellipse at center, #000 45%, transparent 78%);
  pointer-events: none;
}

.standings-door-wrap.js-door-armed .standings-door-label {
  display: block;
}

.standings-door-wrap.door-play .standings-door-label {
  animation: standings-door-label-fade 0.5s ease-in forwards;
  animation-delay: 0.85s;
}

@keyframes standings-door-label-fade {
  0% { opacity: 1; transform: translate(-50%, -50%) rotate(-15deg) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -50%) rotate(-15deg) scale(1.06); }
}

@media (max-width: 480px) {
  .standings-door-label {
    letter-spacing: 0.01em;
  }
}

/* Both end a hair past a plain -100%/100% (and fade out right at the
   very end) so no sliver of the hazard-stripe seam is left peeking
   past the wrap's overflow:hidden edge from sub-pixel rounding. */
@keyframes standings-door-open-up {
  0% { transform: translateY(0); opacity: 1; }
  92% { transform: translateY(-108%); opacity: 1; }
  100% { transform: translateY(-112%); opacity: 0; }
}

@keyframes standings-door-open-down {
  0% { transform: translateY(0); opacity: 1; }
  92% { transform: translateY(108%); opacity: 1; }
  100% { transform: translateY(112%); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .standings-door-wrap.js-door-armed .standings-door,
  .standings-door-wrap.js-door-armed .standings-door-label {
    display: none;
  }
}

.standings-layout {
  display: flex;
  align-items: flex-start;
  gap: 24px;
}

.photo-panel {
  flex: 0 0 220px;
  /* Without this, a flex item's automatic minimum width is its
     content's un-wrapped width -- so the "Current Leader" label
     below (which used to force itself onto one line) could stretch
     this whole column, and the photo with it, well past 220px. */
  min-width: 0;
}

.photo-panel img {
  display: block;
  width: 100%;
  border-radius: 10px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.08);
}

/* Shown in place of the photo when the current leader doesn't have a
   matching profpic_ file uploaded yet. */
.leader-photo-silhouette {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  border-radius: 10px;
  background: var(--card);
  border: 1px solid var(--border);
}

.leader-photo-silhouette .sil-bg {
  fill: var(--border);
}

.leader-photo-silhouette .sil-fg {
  fill: var(--card);
}

.leader-block {
  text-align: center;
  margin-top: 18px;
  margin-bottom: 10px;
}

.leader-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--gold-bg);
}

/* Same curved laurel-branch artwork as the Winner's Quote laurels
   (see .laurel-stem / .laurel-leaf), just re-sized to flank the
   "Current Leader" label instead. */
.leader-wreath {
  width: clamp(24px, 5.5vw, 28px);
  height: auto;
  flex-shrink: 0;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.4));
}

.leader-wreath-right {
  transform: scaleX(-1);
}

/* The label reads as the "headline" of this panel, in the exact same
   gold-foil treatment as the "Season Standings" heading it sits next
   to (see .standings-heading-inner) -- same typeface, same gradient,
   just smaller since this is the secondary panel next to it rather
   than the section's own heading. */
.leader-label {
  font-family: "Anton", "Arial Narrow", Impact, sans-serif;
  font-weight: 400;
  font-size: clamp(1.05rem, 3.4vw, 1.3rem);
  letter-spacing: 0.03em;
  line-height: 1.1;
  text-transform: uppercase;
  background: linear-gradient(
    180deg,
    #fff8dc 0%,
    #f4dfa0 15%,
    #e0b52c 35%,
    #a8790a 55%,
    #e0b52c 75%,
    #fff8dc 100%
  );
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  text-shadow: 0 2px 3px rgba(0, 0, 0, 0.45);
}

.leader-name {
  margin-top: 6px;
  font-family: "Anton", "Arial Narrow", Impact, sans-serif;
  font-weight: 400;
  font-size: clamp(1.1rem, 5.5vw, 1.4rem);
  letter-spacing: 0.02em;
  overflow-wrap: break-word;
  color: #fbfbf8;
  text-shadow: 0 1px 5px rgba(0, 0, 0, 0.85);
}

.standings-section {
  /* .standings-door-wrap (its new parent) is the actual flex child of
     .standings-layout now and carries the flex/min-width rules this
     used to have -- this just needs to fill that wrapper. */
  width: 100%;
  min-width: 0;
}

@media (max-width: 700px) {
  .standings-layout {
    flex-direction: column;
    /* The row layout's align-items: flex-start (above) is meant for
       sitting the photo panel and standings section side by side --
       in column mode it has the side effect of letting a flex child
       size itself to its own content's width instead of the
       container's width, so a wide table could grow the whole
       section past the screen edge (clipped by
       .standings-door-wrap's overflow:hidden, with nothing left to
       actually scroll). Stretching instead keeps every child pinned
       to the container's actual width, so .table-scroll's own
       overflow-x: auto is what handles a too-wide table, not the
       page silently growing offscreen. */
    align-items: stretch;
  }

  .photo-panel {
    flex-basis: auto;
    width: 100%;
    max-width: 280px;
    margin: 0 auto;
  }
}

.standings-section h2 {
  text-align: center;
  margin-bottom: 10px;
}

/* Shiny gold "Season Standings" heading — a vertical gold-foil gradient
   clipped to the text for the fill, plus a diagonal sweep of light
   layered as a SECOND background image on this same element (rather
   than a separate overlay box, like the Winner's Quote card uses) --
   background-clip: text applies to every background layer here, so
   the moving sweep is clipped to the letter shapes themselves and
   never shows as a rectangle outside them. */
.standings-heading-inner {
  display: inline-block;
  padding: 2px 6px;
  font-family: "Anton", "Arial Narrow", Impact, sans-serif;
  font-weight: 400;
  font-size: clamp(1.6rem, 6vw, 2.3rem);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  background-image:
    linear-gradient(
      100deg,
      transparent 0%,
      transparent 42%,
      rgba(255, 255, 255, 0.95) 50%,
      rgba(255, 233, 168, 0.65) 58%,
      transparent 68%,
      transparent 100%
    ),
    linear-gradient(
      180deg,
      #fff8dc 0%,
      #f4dfa0 15%,
      #e0b52c 35%,
      #a8790a 55%,
      #e0b52c 75%,
      #fff8dc 100%
    );
  background-size: 300% 100%, 100% 100%;
  background-position: -120% 0, 0 0;
  background-repeat: no-repeat;
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  text-shadow: 0 2px 3px rgba(0, 0, 0, 0.45);
  animation: standings-heading-shine 5s ease-in-out infinite;
}

@keyframes standings-heading-shine {
  0% { background-position: -120% 0, 0 0; }
  50% { background-position: 220% 0, 0 0; }
  100% { background-position: 220% 0, 0 0; }
}

@media (prefers-reduced-motion: reduce) {
  .standings-heading-inner {
    animation: none;
    background-position: 0 0, 0 0;
  }
}

.legend {
  margin: 0 0 12px;
  color: #f1f2ee;
  text-shadow: 0 1px 5px rgba(0, 0, 0, 0.85);
  font-size: 0.82rem;
}

.table-scroll {
  overflow-x: auto;
  border-radius: 10px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.04);
  -webkit-overflow-scrolling: touch;
}

table {
  width: 100%;
  border-collapse: collapse;
  background: var(--card);
}

thead th {
  text-align: left;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

tbody td {
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

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

.coach-cell {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 600;
}

.coach-avatar {
  display: block;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  background: var(--card);
  border: 1px solid var(--border);
}

.coach-avatar-silhouette .sil-bg {
  fill: var(--border);
}

.coach-avatar-silhouette .sil-fg {
  fill: var(--card);
}

.week-cell {
  text-align: center;
  color: var(--text);
}

/* Coach and Total are the first two columns and are both pinned to the
   left edge of .table-scroll, so they stay visible while the week
   columns scroll horizontally underneath them. Total's left offset is
   the Coach column's measured width (--coach-col-width, set by
   pinTotalBesideCoach in script.js). Both need opaque backgrounds so
   scrolled cells don't show through, and Total carries an inset right
   edge shadow as the divider because collapsed borders don't travel
   with sticky cells. */
.coach-col {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--card);
}

.total-cell {
  position: sticky;
  left: var(--coach-col-width, 0);
  z-index: 1;
  text-align: center;
  font-weight: 700;
  background: var(--total-bg);
  box-shadow: inset -1px 0 0 var(--border), 6px 0 8px -6px rgba(0, 0, 0, 0.25);
}

thead th.coach-col,
thead th.total-cell {
  z-index: 2;
}

.status-message {
  text-align: center;
  color: var(--muted);
  padding: 28px 14px;
  white-space: normal;
}

tr.rank-1 .coach-cell { color: #8a6d00; }
tr.rank-2 .coach-cell { color: #5b6068; }
tr.rank-3 .coach-cell { color: #8a4a1c; }

/* Weekly place ribbons (1st/2nd/3rd for that week only) */
.place-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  border-radius: 999px;
  font-weight: 700;
  font-size: 0.85em;
  white-space: nowrap;
}

.place-badge.place-1 { background: var(--gold-bg); color: var(--gold-text); }
.place-badge.place-2 { background: var(--silver-bg); color: var(--silver-text); }
.place-badge.place-3 { background: var(--bronze-bg); color: var(--bronze-text); }
.place-badge.place-last { background: var(--poop-bg); color: var(--poop-text); }

/* Season-total trophies (top 3 overall, always follows sort order) */
.trophy-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 11px;
  border-radius: 999px;
  font-weight: 800;
  font-size: 1em;
}

.trophy-badge.trophy-1 { background: var(--gold-bg); color: var(--gold-text); }
.trophy-badge.trophy-2 { background: var(--silver-bg); color: var(--silver-text); }
.trophy-badge.trophy-3 { background: var(--bronze-bg); color: var(--bronze-text); }
.trophy-badge.trophy-last { background: var(--poop-bg); color: var(--poop-text); }

/* Commish message — a Windows 98-style email window, deliberately a
   fixed retro look regardless of site theme (light or dark), since
   that's the whole bit. */
.commish-section {
  max-width: 1100px;
  margin: 0 auto 32px;
}

/* The Commish's message "arrives" in a kraft-paper envelope that
   flies onto the page and pops its flap open as you scroll to it,
   then fades away to reveal the Win98 message window underneath.
   Both the envelope and the actual message window sit stacked in the
   same spot (the wrap's height is set by the window, the envelope is
   absolutely positioned over it) so nothing jumps around as one
   replaces the other.

   script.js only arms this (adds .js-envelope-armed, which is what
   actually hides the window/shows the envelope up front) once the
   section has real content and is about to be revealed, and only
   when JS + IntersectionObserver + prefers-reduced-motion all allow
   it — so with JS off, or motion reduced, the message window is just
   there already, no envelope, no animation, nothing to trip over. */
.commish-envelope-wrap {
  position: relative;
  max-width: 700px;
  margin: 0 auto;
}

.envelope {
  position: absolute;
  inset: 0;
  z-index: 3;
  opacity: 0;
  pointer-events: none;
  perspective: 700px;
}

.commish-envelope-wrap.js-envelope-armed .envelope {
  opacity: 1;
  transform: translateY(-160px) scale(0.55) rotate(-9deg);
}

.commish-envelope-wrap.js-envelope-armed .commish-letter {
  opacity: 0;
  transform: translateY(18px) scale(0.92);
}

/* Plain white paper + a solid black outline, like a classic Windows
   98 "new mail" desktop icon rather than a fancy wax-sealed letter --
   no cream/yellow tint, no seal, sharp corners. */
.envelope-back {
  position: absolute;
  inset: 0;
  background: #fdfdfd;
  border: 3px solid #000;
  box-shadow: 0 12px 26px rgba(0, 0, 0, 0.4);
}

/* The flap's triangular shape + its diagonal fold lines are drawn by
   an actual SVG polygon (below) rather than a CSS clip-path + border
   -- clip-path trims a box's rectangular border along with the box,
   it doesn't add a border tracing the new cut edges, so that earlier
   approach silently drew no visible diagonal line at all. The div
   here just positions that SVG and carries the 3D rotateX flip. */
.envelope-flap {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 58%;
  transform-origin: top center;
  transform: rotateX(0deg);
  backface-visibility: hidden;
}

.envelope-flap svg {
  display: block;
  width: 100%;
  height: 100%;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.3));
}

/* An original shield seal (red/white/blue, a leaping player silhouette
   reaching for the ball -- not any real team or league's mark) sitting
   right where the flap's point meets the envelope. It's a child of the
   flap itself, so it lifts and rotates away together with it when the
   letter opens, like a wax seal breaking. */
.envelope-seal {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 15%;
  min-width: 34px;
  max-width: 56px;
  transform: translate(-50%, 45%);
  z-index: 2;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.35));
}

.envelope-seal svg {
  display: block;
  width: 100%;
  height: auto;
}

.commish-letter {
  position: relative;
  z-index: 1;
}

.commish-envelope-wrap.envelope-play .envelope {
  animation:
    envelope-land 0.6s cubic-bezier(0.22, 0.9, 0.32, 1.2) forwards,
    envelope-vanish 0.45s ease-in 1.55s forwards;
}

.commish-envelope-wrap.envelope-play .envelope-flap {
  animation: envelope-flap-open 0.45s ease-in forwards;
  animation-delay: 0.85s;
}

.commish-envelope-wrap.envelope-play .commish-letter {
  animation: envelope-letter-reveal 0.55s ease-out forwards;
  animation-delay: 1.25s;
}

@keyframes envelope-land {
  0% { opacity: 1; transform: translateY(-160px) scale(0.55) rotate(-9deg); }
  60% { transform: translateY(6px) scale(1.03) rotate(1deg); }
  100% { opacity: 1; transform: translateY(0) scale(1) rotate(0deg); }
}

@keyframes envelope-flap-open {
  from { transform: rotateX(0deg); }
  to { transform: rotateX(-165deg); }
}

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

@keyframes envelope-letter-reveal {
  from { opacity: 0; transform: translateY(18px) scale(0.92); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .commish-envelope-wrap.js-envelope-armed .envelope {
    opacity: 0;
    transform: none;
  }

  .commish-envelope-wrap.js-envelope-armed .commish-letter {
    opacity: 1;
    transform: none;
  }

  .commish-envelope-wrap.envelope-play .envelope,
  .commish-envelope-wrap.envelope-play .envelope-flap,
  .commish-envelope-wrap.envelope-play .commish-letter {
    animation: none;
  }
}

.win98-window {
  max-width: 700px;
  margin: 0 auto;
  background: #c0c0c0;
  border-top: 2px solid #fff;
  border-left: 2px solid #fff;
  border-right: 2px solid #000;
  border-bottom: 2px solid #000;
  box-shadow:
    inset -1px -1px 0 #808080,
    inset 1px 1px 0 #dfdfdf,
    2px 3px 10px rgba(0, 0, 0, 0.35);
  font-family: Tahoma, "Segoe UI", Verdana, sans-serif;
}

.win98-titlebar {
  background: linear-gradient(90deg, #000080, #1084d0);
  color: #fff;
  font-weight: bold;
  font-size: 0.82rem;
  padding: 4px 4px 4px 8px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.win98-title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.win98-title::before {
  content: "\2709  ";
}

.win98-controls {
  display: flex;
  gap: 2px;
  flex-shrink: 0;
}

.win98-btn {
  width: 17px;
  height: 15px;
  background: #c0c0c0;
  border-top: 1px solid #fff;
  border-left: 1px solid #fff;
  border-right: 1px solid #000;
  border-bottom: 1px solid #000;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.65rem;
  font-weight: bold;
  color: #000;
  line-height: 1;
  font-family: Tahoma, sans-serif;
}

.win98-body {
  margin: 2px;
  background: #fff;
  border-top: 1px solid #808080;
  border-left: 1px solid #808080;
  border-right: 1px solid #fff;
  border-bottom: 1px solid #fff;
}

.email-headers {
  background: #ece9d8;
  border-bottom: 1px solid #aca899;
  padding: 8px 14px;
  font-size: 0.82rem;
  line-height: 1.7;
  color: #000;
}

.email-headers div {
  display: flex;
  gap: 6px;
}

.email-label {
  font-weight: bold;
  width: 66px;
  flex-shrink: 0;
  white-space: nowrap;
}

.email-body {
  padding: 18px 20px 24px;
  font-family: "Times New Roman", Georgia, serif;
  font-size: 1.05rem;
  line-height: 1.7;
  color: #111;
}

.email-message-text {
  white-space: pre-wrap;
  word-break: break-word;
  margin: 0 0 18px;
}

.email-closing {
  margin: 0;
}

.email-signature {
  display: block;
  width: 200px;
  height: auto;
  /* A couple of blank-line-ish gaps between "The All Powerful," and
     the signature image, like there'd be room to actually sign.
     Nudged left slightly so the pen stroke lines up with the "T" of
     "The All Powerful," above it rather than reading as indented. */
  margin: 24px 0 0 -10px;
}

@media (max-width: 520px) {
  .email-body {
    font-size: 0.98rem;
    padding: 16px 14px 20px;
  }

  .email-signature {
    width: 160px;
  }
}

.site-footer {
  max-width: 960px;
  margin: 32px auto 0;
  text-align: center;
  color: #f1f2ee;
  text-shadow: 0 1px 5px rgba(0, 0, 0, 0.85);
  font-size: 0.8rem;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #14161a;
    --card: #1d2027;
    --text: #f2f3f5;
    --muted: #9aa0aa;
    --border: #2b2f38;
    --total-bg: #1a2620;
  }
}
