/* ==========================================================================
   Rocker Robotics - site design system
   Palette is sampled from the team logo: South Dakota Mines navy + vegas gold.
   ========================================================================== */

:root {
  /* brand */
  --navy:        #002554;
  --navy-deep:   #001A3C;
  --navy-ink:    #00132C;
  --gold:        #B3A369;
  --gold-bright: #C9BA82;

  /* sponsor levels - metallics, muted so they sit beside the brand gold
     rather than competing with it */
  --tier-platinum: #6E7B8B;
  --tier-gold:     #C9A227;
  --tier-silver:   #A3AAB2;
  --tier-bronze:   #A9613A;

  /* neutrals */
  --ink:         #16191F;
  --body:        #4A5058;
  --muted:       #767C86;
  --line:        #E4E7EB;
  --dq:          #9E3B32;   /* a disqualified team on the scoreboard */
  --surface:     #FFFFFF;
  --surface-alt: #F5F6F8;

  /* type */
  --font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
          'Helvetica Neue', Arial, sans-serif;

  /* layout */
  --shell: 1200px;
  --gutter: clamp(1.25rem, 4vw, 3rem);
  --band: clamp(4rem, 9vw, 7rem);
  --radius: 4px;

  --shadow-sm: 0 1px 3px rgba(0, 19, 44, .08), 0 1px 2px rgba(0, 19, 44, .06);
  --shadow-md: 0 10px 30px rgba(0, 19, 44, .10), 0 2px 8px rgba(0, 19, 44, .06);
  --shadow-lg: 0 22px 55px rgba(0, 19, 44, .16);

  --ease: cubic-bezier(.22, .61, .36, 1);
}

/* --------------------------------------------------------------- base ---- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 1rem;
  line-height: 1.65;
  color: var(--body);
  background: var(--surface);
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }

h1, h2, h3, h4 {
  margin: 0;
  color: var(--ink);
  line-height: 1.15;
  font-weight: 500;
  letter-spacing: -.01em;
}

p { margin: 0 0 1rem; }
p:last-child { margin-bottom: 0; }

a { color: var(--navy); text-decoration: none; }
a:hover { color: var(--gold); }

:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 3px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--navy);
  color: #fff;
  padding: .75rem 1.25rem;
}
.skip-link:focus { left: 0; color: #fff; }

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* ------------------------------------------------------------ buttons ---- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .85rem 1.9rem;
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-size: .95rem;
  font-weight: 500;
  letter-spacing: .01em;
  cursor: pointer;
  transition: background .18s var(--ease), color .18s var(--ease),
              border-color .18s var(--ease), transform .18s var(--ease);
}
.btn:hover { transform: translateY(-1px); }

.btn-sm { padding: .55rem 1.2rem; font-size: .875rem; }

.btn-solid  { background: var(--gold); color: var(--navy-ink); }
.btn-solid:hover  { background: var(--gold-bright); color: var(--navy-ink); }

.btn-navy   { background: var(--navy); color: #fff; }
.btn-navy:hover   { background: var(--navy-deep); color: #fff; }

.btn-ghost  { border-color: rgba(255,255,255,.65); color: #fff; }
.btn-ghost:hover  { background: #fff; border-color: #fff; color: var(--navy-ink); }

.btn-outline { border-color: var(--navy); color: var(--navy); }
.btn-outline:hover { background: var(--navy); color: #fff; }

/* ------------------------------------------------------------- header ---- */

.site-header {
  /* sticky, not fixed: it occupies layout space, so page content can never
     scroll underneath it. The solid background is unconditional. */
  position: sticky;
  top: 0;
  z-index: 100;
  background: #fff;
  border-bottom: 1px solid var(--line);
  transition: box-shadow .28s var(--ease);
}

.header-inner {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  min-height: 92px;
}

.brand { margin-right: auto; display: flex; align-items: center; }
.brand img {
  height: 60px;
  width: auto;
}

.site-nav { display: flex; align-items: center; gap: 1.75rem; }
.site-nav ul {
  display: flex;
  align-items: center;
  gap: 1.6rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.site-nav a {
  position: relative;
  font-size: .95rem;
  font-weight: 500;
  color: var(--navy);
  padding: .35rem 0;
  transition: color .18s var(--ease);
}
.site-nav a::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 2px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .22s var(--ease);
}
.site-nav a:hover { color: var(--gold); }
.site-nav a:hover::after { transform: scaleX(1); }

/* build.py stamps <body data-page="...">; light up the matching link */
body[data-page="about"]     .site-nav a[data-nav="about"]::after,
body[data-page="projects"]  .site-nav a[data-nav="projects"]::after,
body[data-page="news"]      .site-nav a[data-nav="news"]::after,
body[data-page="gallery"]   .site-nav a[data-nav="gallery"]::after,
body[data-page="calendar"]  .site-nav a[data-nav="calendar"]::after,
body[data-page="sponsors"]  .site-nav a[data-nav="sponsors"]::after,
body[data-page="resources"] .site-nav a[data-nav="resources"]::after { transform: scaleX(1); }

.nav-cta { flex: none; }

/* lifts off the page once you scroll, so it reads as floating above content */
.site-header.is-stuck { box-shadow: var(--shadow-md); }

/* mobile toggle */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
}
.nav-toggle-bar {
  display: block;
  height: 2px;
  width: 26px;
  background: var(--navy);
  transition: transform .25s var(--ease), opacity .2s var(--ease);
}
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

@media (max-width: 960px) {
  .nav-toggle { display: flex; }

  .site-nav {
    /* anchored to the header itself, so it follows the header's real height
       instead of a hard-coded offset that drifts when the logo changes size */
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 1rem var(--gutter) 1.75rem;
    background: var(--navy);
    box-shadow: var(--shadow-lg);
    transform: translateY(-130%);
    transition: transform .32s var(--ease);
    z-index: -1;
  }
  .site-nav.is-open { transform: translateY(0); }

  .site-nav ul { flex-direction: column; align-items: stretch; gap: 0; }
  .site-nav li { border-bottom: 1px solid rgba(255,255,255,.12); }
  .site-nav a { display: block; padding: .95rem 0; color: #fff; }
  .site-nav a:hover { color: var(--gold-bright); }
  .site-nav a::after { display: none; }
  .nav-cta { margin-top: 1.25rem; justify-content: center; }
  /* the open nav is a navy panel, so a navy button on it would be invisible */
  .site-nav .nav-scoreboard {
    background: transparent;
    border-color: rgba(255, 255, 255, .65);
    color: #fff;
  }
  .site-nav .nav-scoreboard:hover {
    background: #fff;
    border-color: #fff;
    color: var(--navy-ink);
  }
  .nav-scoreboard + .nav-cta { margin-top: .75rem; }

  .brand img { height: 48px; }
  .header-inner { min-height: 76px; }
}

/* --------------------------------------------------------------- hero ---- */

.hero {
  position: relative;
  display: flex;
  align-items: center;
  min-height: min(78vh, 760px);
  padding: 5rem 0;
  background-size: cover;
  background-position: center;
  background-color: var(--navy-ink);
  color: #fff;
  isolation: isolate;
}
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(to bottom,
      rgba(0, 19, 44, .78) 0%,
      rgba(0, 19, 44, .52) 45%,
      rgba(0, 19, 44, .74) 100%);
}

.hero-inner { max-width: 46rem; }

.hero-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  margin-bottom: 1.5rem;
  padding: .4rem .9rem;
  border: 1px solid rgba(179, 163, 105, .55);
  border-radius: 999px;
  background: rgba(0, 19, 44, .35);
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--gold-bright);
}
.hero-eyebrow .dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--gold);
}

.hero h1 {
  margin: 0 0 1.25rem;
  font-size: clamp(2.75rem, 8vw, 6.25rem);
  font-weight: 300;
  letter-spacing: -.025em;
  color: #fff;
}

.hero-meta {
  margin: 0 0 1.75rem;
  font-size: clamp(1rem, 1.6vw, 1.15rem);
  color: rgba(255, 255, 255, .86);
}
.hero-meta strong { color: var(--gold-bright); font-weight: 600; }

.hero-actions { display: flex; flex-wrap: wrap; gap: .9rem; }

.hero-scroll {
  position: absolute;
  left: 50%;
  bottom: 1.75rem;
  transform: translateX(-50%);
  color: rgba(255, 255, 255, .7);
  font-size: 1.5rem;
  animation: nudge 2.4s var(--ease) infinite;
}
@keyframes nudge {
  0%, 100% { transform: translate(-50%, 0); }
  50%      { transform: translate(-50%, 8px); }
}
@media (prefers-reduced-motion: reduce) { .hero-scroll { animation: none; } }

/* ---------------------------------------------------------- page head --- */

/* Sub-page banner. Shorter than the landing hero, because these pages are
   about reading rather than arriving. Works with or without a photo. */
.page-head {
  position: relative;
  padding-block: clamp(3.5rem, 8vw, 6rem);
  background: var(--navy);
  color: #fff;
  isolation: isolate;
}
.page-head.has-image {
  background-size: cover;
  background-position: center;
  background-color: var(--navy-ink);
}
.page-head.has-image::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(to bottom,
      rgba(0, 19, 44, .88) 0%,
      rgba(0, 19, 44, .78) 60%,
      rgba(0, 19, 44, .90) 100%);
}

.page-head-inner { max-width: 46rem; }

.page-head h1 {
  margin: 0;
  font-size: clamp(2.25rem, 5.5vw, 3.75rem);
  font-weight: 300;
  letter-spacing: -.025em;
  color: #fff;
}
.page-head p {
  margin: 1.1rem 0 0;
  font-size: clamp(1rem, 1.5vw, 1.15rem);
  color: rgba(255, 255, 255, .82);
}
.page-head p strong { color: var(--gold-bright); font-weight: 600; }

/* the shared .eyebrow is gold on white; over the banner it needs lifting */
.eyebrow-light { color: var(--gold-bright); }

/* ------------------------------------------------------------ sections --- */

.band { padding-block: var(--band); }
.band-alt { background: var(--surface-alt); }

.band-head { max-width: 46rem; margin-bottom: clamp(2.25rem, 4vw, 3.25rem); }
.band-head.center { margin-inline: auto; text-align: center; }
/* a band that is nothing but its own heading and a paragraph or two - the
   margin below exists to separate the heading from what follows it, and
   here nothing does */
.band-head:only-child { margin-bottom: 0; }

.band-head h2 {
  font-size: clamp(1.9rem, 3.6vw, 2.6rem);
  font-weight: 500;
}
.band-head p {
  margin-top: .9rem;
  font-size: 1.05rem;
  color: var(--muted);
}

.eyebrow {
  display: block;
  margin-bottom: .7rem;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--gold);
}

/* ---------------------------------------------------------------- grid --- */

.grid { display: grid; gap: 1.75rem; }
/* min() so a narrow phone gets a single column that fits, rather than a track
   wider than its container - auto-fit alone will not shrink below the minimum */
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(min(290px, 100%), 1fr)); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(min(400px, 100%), 1fr)); }

/* --------------------------------------------------------- robot cards --- */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  transition: transform .28s var(--ease), box-shadow .28s var(--ease),
              border-color .28s var(--ease);
}
.card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-md);
  border-color: transparent;
}

.card-media {
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--surface-alt);
  overflow: hidden;
}
.card-media img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform .5s var(--ease);
}
.card:hover .card-media img { transform: scale(1.045); }

.card-tag {
  position: absolute;
  top: .85rem; left: .85rem;
  padding: .3rem .75rem;
  border-radius: 3px;
  background: rgba(0, 19, 44, .82);
  color: var(--gold-bright);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
}

/* How many photos are inside, on the gallery page's album covers. Sits in the
   opposite corner from .card-tag so the two never collide on a narrow card. */
.card-count {
  position: absolute;
  top: .85rem; right: .85rem;
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .3rem .7rem;
  border-radius: 3px;
  background: rgba(0, 19, 44, .82);
  color: rgba(255, 255, 255, .88);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .06em;
}
.card-count i { color: var(--gold); font-size: .8rem; }

/* stand-in for a robot we do not have photography for yet */
.card-media.is-placeholder {
  display: grid;
  place-items: center;
  background:
    repeating-linear-gradient(-45deg,
      rgba(255,255,255,.03) 0 12px, transparent 12px 24px),
    linear-gradient(145deg, var(--navy) 0%, var(--navy-ink) 100%);
  color: rgba(255, 255, 255, .5);
  text-align: center;
}
.card-media.is-placeholder i { font-size: 2.5rem; color: var(--gold); opacity: .65; }
.card-media.is-placeholder span {
  display: block;
  margin-top: .6rem;
  font-size: .78rem;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.card-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 1.6rem 1.6rem 1.75rem;
}
.card-body h3 { font-size: 1.4rem; font-weight: 500; }
.card-body p { margin: .7rem 0 0; font-size: .96rem; }

.card-link {
  margin-top: auto;
  padding-top: 1.15rem;
  font-size: .9rem;
  font-weight: 600;
  color: var(--navy);
  letter-spacing: .02em;
}
.card-link i { transition: transform .22s var(--ease); }

/* the whole card is the click target, so the markup stays a plain <article> */
.card .card-link[href]::after { content: ''; position: absolute; inset: 0; }
.card-link.is-inert { color: var(--muted); cursor: default; }
.card:hover .card-link { color: var(--gold); }
.card:hover .card-link i { transform: translateX(4px); }

/* the date range under a robot's name on the robots page */
.card-meta {
  margin: .35rem 0 0;
  font-size: .82rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--muted);
}
.card-meta + p { margin-top: .7rem; }

/* ---------------------------------------------------------- filter bar --- */

/* The robots page filters its card grid in the browser. With JS off there is
   nothing to drive the buttons, so the whole bar stays hidden and the page is
   simply the full list - which is what it was before the filters existed. */
.filter-bar { display: none; }
.js .filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.5rem;
  margin-bottom: clamp(1.75rem, 3vw, 2.5rem);
  padding-bottom: 1.35rem;
  border-bottom: 1px solid var(--line);
}

.filter-pills { display: flex; flex-wrap: wrap; gap: .5rem; margin-right: auto; }

.filter-pill {
  padding: .5rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--body);
  font: inherit;
  font-size: .875rem;
  font-weight: 500;
  cursor: pointer;
  transition: background .2s var(--ease), border-color .2s var(--ease),
              color .2s var(--ease);
}
.filter-pill:hover { border-color: var(--navy); color: var(--navy); }
.filter-pill[aria-pressed="true"] {
  background: var(--navy);
  border-color: var(--navy);
  color: #fff;
}

.filter-count { margin: 0; font-size: .875rem; color: var(--muted); }

/* a filter that matches nothing still has to say so */
.filter-empty {
  margin: 0;
  padding: 3rem 0;
  text-align: center;
  color: var(--muted);
}
.link-button {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-weight: 600;
  color: var(--navy);
  text-decoration: underline;
  cursor: pointer;
}
.link-button:hover { color: var(--gold); }

/* .card is display:flex, which would otherwise win over the hidden attribute */
.grid > [hidden] { display: none; }

/* ------------------------------------------------------ feature banner --- */

.feature {
  position: relative;
  display: flex;
  align-items: center;
  min-height: min(78vh, 700px);
  padding-block: var(--band);
  background-size: cover;
  background-position: center;
  background-color: var(--navy-ink);
  color: #fff;
  isolation: isolate;
}
.feature::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(105deg,
    rgba(0, 19, 44, .90) 0%,
    rgba(0, 19, 44, .72) 48%,
    rgba(0, 19, 44, .38) 100%);
}
.feature-inner { max-width: 40rem; }
.feature h2 {
  font-size: clamp(2rem, 5vw, 3.4rem);
  font-weight: 300;
  letter-spacing: -.02em;
  color: #fff;
}
.feature p {
  margin: 1.15rem 0 0;
  font-size: 1.06rem;
  color: rgba(255, 255, 255, .84);
}
.feature .btn { margin-top: 2rem; }

.feature-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 2.5rem;
  margin-top: 2.5rem;
  padding-top: 1.75rem;
  border-top: 1px solid rgba(255, 255, 255, .18);
}
.feature-stats div { min-width: 6rem; }
.feature-stats dt {
  font-size: clamp(1.8rem, 3vw, 2.4rem);
  font-weight: 300;
  color: var(--gold-bright);
  line-height: 1.1;
}
.feature-stats dd {
  margin: .35rem 0 0;
  font-size: .82rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .7);
}

/* ---------------------------------------------------------- info cards --- */

.info-card {
  display: flex;
  flex-direction: column;
  padding: 2rem 1.9rem 2.1rem;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  /* the stripe is the team's gold everywhere except the sponsorship levels,
     which set --tier to their own metallic - see "sponsor levels" below */
  border-top: 3px solid var(--tier, var(--gold));
  transition: transform .28s var(--ease), box-shadow .28s var(--ease);
}
.info-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); }
.info-card .icon {
  margin-bottom: 1.1rem;
  font-size: 1.6rem;
  color: var(--navy);
}
.info-card h3 { font-size: 1.3rem; font-weight: 500; }
.info-card p { margin-top: .75rem; font-size: .96rem; }
/* the competition cards carry a series/years line under the heading */
.info-card .info-card-meta {
  margin-top: .35rem;
  font-size: .82rem;
  font-weight: 600;
  letter-spacing: .06em;
  color: var(--muted);
}
.info-card .info-card-meta + p { margin-top: .6rem; }
.info-card .card-link { padding-top: 1.35rem; }

/* meeting times block */
.meet-list { margin: 0; padding: 0; list-style: none; font-size: .95rem; }
.meet-list li { display: flex; gap: .75rem; padding: .5rem 0; border-bottom: 1px solid var(--line); }
.meet-list li:last-child { border-bottom: 0; }
.meet-list dt, .meet-list .when { flex: none; min-width: 6.5rem; font-weight: 600; color: var(--ink); }

/* A robot's details are the same list with much longer values: a team of
   seventeen names, a sentence of features. Two columns leave those too narrow
   on a phone, so below this width the label sits on its own line above the
   value instead. The meeting times are short enough that they never need it,
   which is why this is a class of its own rather than a change to .meet-list. */
@media (max-width: 560px) {
  .spec-list li { display: block; }
  .spec-list li .when { display: block; margin-bottom: .15rem; }
}

/* lists of links inside a card */

/* The resources pages are, almost entirely, a card with several links in it:
   a datasheet, a CAD file, a tutorial, a pinout. This is that list. The
   chevron is markup rather than a ::before glyph, the same way .card-link
   carries its own, so the list still reads sensibly if Font Awesome does not
   load. Anything after the link - "(~13 min)", "old F: drive path" - goes in
   a .note and flows inline after it. */
.link-list {
  margin: 1.1rem 0 0;
  padding: 0;
  list-style: none;
  font-size: .95rem;
}
.link-list li { position: relative; padding-left: 1.4rem; }
.link-list li + li { margin-top: .55rem; }
.link-list li > .fa {
  position: absolute;
  left: 0;
  top: .42em;
  font-size: .82em;
  color: var(--gold);
}
.link-list a { font-weight: 600; }
.link-list .note { color: var(--muted); }

/* A line of plain instructions among the links - an install path, a warning -
   set apart from them without becoming another card. */
.link-note {
  margin: 1.1rem 0 0;
  padding-left: 1.4rem;
  border-left: 2px solid var(--line);
  font-size: .9rem;
  color: var(--muted);
}

/* ------------------------------------------------------ split sections --- */

/* Text beside a photo. .split-reverse puts the photo first on wide screens;
   both orders stack text-then-photo once there is no room for two columns. */
.split {
  display: grid;
  grid-template-columns: 1fr minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}
.split-reverse .split-text { order: 2; }
.split-reverse .split-media { order: 1; }

.split-text h2 {
  font-size: clamp(1.9rem, 3.6vw, 2.6rem);
  font-weight: 500;
}
.split-text h2 + p { margin-top: 1.25rem; }
.split-text p { font-size: 1.05rem; }
.split-text .card-link {
  /* inline-flex drops the whitespace before the chevron, so set it back */
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  margin-top: .5rem;
}

.split-media { margin: 0; }
.split-media img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}
.split-media figcaption {
  margin-top: .9rem;
  font-size: .9rem;
  color: var(--muted);
}

@media (max-width: 880px) {
  .split { grid-template-columns: 1fr; }
  .split-reverse .split-text,
  .split-reverse .split-media { order: 0; }
  .split-media img { aspect-ratio: 16 / 10; }
}

/* ------------------------------------------------------- album pages --- */

/* One photo album: /gallery/<album>. Built from _src/album.html, once per
   folder under content/albums/. */

/* The way back to the gallery, above the album title in the banner. Sits in
   the flow rather than floating, so it never lands on top of the heading on a
   narrow screen. */
.back-link {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  margin-bottom: 1.35rem;
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: rgba(255, 255, 255, .78);
  text-decoration: none;
  transition: color .2s var(--ease);
}
.back-link:hover, .back-link:focus-visible { color: var(--gold-bright); }
.back-link .fa { font-size: 1rem; }

/* The date and school year under an album's title. */
.page-head-meta {
  margin: .85rem 0 0;
  font-size: .9rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: rgba(255, 255, 255, .7);
}
/* .page-head p is body copy and sets its own larger top margin; the intro
   under this line should not also get one */
.page-head-meta + p { margin-top: .75rem; }

/* The photographs. Every tile is the same shape whatever the photo behind it,
   so the grid stays a grid - the full frame is one click away regardless. */
.photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr));
  gap: 1.15rem;
}

.photo {
  display: block;
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius);
  background: var(--surface-alt);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: box-shadow .3s var(--ease), transform .3s var(--ease);
}
.photo img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform .5s var(--ease);
}
.photo:hover, .photo:focus-visible { box-shadow: var(--shadow-md); }
.photo:hover img { transform: scale(1.05); }

/* The magnifier only appears on a device that can hover: on a touch screen it
   would sit there permanently, covering a corner of every photo. */
@media (hover: hover) {
  .photo::after {
    content: '\f00e';                       /* fa-search-plus */
    font-family: FontAwesome;
    position: absolute;
    right: .6rem; bottom: .6rem;
    display: grid;
    place-items: center;
    width: 2rem; height: 2rem;
    border-radius: 50%;
    background: rgba(0, 19, 44, .78);
    color: #fff;
    font-size: .8rem;
    opacity: 0;
    transform: translateY(.35rem);
    transition: opacity .25s var(--ease), transform .25s var(--ease);
  }
  .photo:hover::after, .photo:focus-visible::after {
    opacity: 1;
    transform: none;
  }
}

/* ---- the overlay ----------------------------------------------------- */

/* Built by site.js and appended to <body>. It does not exist at all with JS
   off, where each tile is simply a link to the photo. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  grid-template-rows: 1fr auto;
  padding: clamp(1rem, 4vw, 3rem);
  background: rgba(0, 12, 28, .96);
  opacity: 0;
  visibility: hidden;
  /* visibility is a discrete property: given a duration it would flip halfway
     through, leaving the overlay unfocusable for the first half of the fade.
     So it switches at once on the way in, and waits out the fade on the way
     back, which is what keeps the closed overlay out of the tab order. */
  transition: opacity .25s var(--ease), visibility 0s linear .25s;
}
.lightbox.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity .25s var(--ease), visibility 0s;
}

/* Stops the page behind from scrolling under the overlay. */
body.has-lightbox { overflow: hidden; }

.lightbox-stage {
  display: grid;
  place-items: center;
  min-height: 0;                            /* let the image shrink to fit */
}
.lightbox-stage img {
  max-width: 100%;
  max-height: 100%;
  width: auto; height: auto;
  object-fit: contain;
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}

.lightbox-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: .35rem 1rem;
  padding-top: 1rem;
  text-align: center;
  color: rgba(255, 255, 255, .82);
}
.lightbox-caption { margin: 0; font-size: .95rem; }
.lightbox-count {
  margin: 0;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--gold-bright);
}

/* Close, previous, next. Big enough to be a comfortable touch target, and
   never so large they cover the photo they are next to. */
.lightbox button {
  position: absolute;
  display: grid;
  place-items: center;
  width: 2.9rem; height: 2.9rem;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, .22);
  border-radius: 50%;
  background: rgba(255, 255, 255, .08);
  color: #fff;
  font-size: 1.2rem;
  cursor: pointer;
  transition: background .2s var(--ease), border-color .2s var(--ease);
}
.lightbox button:hover, .lightbox button:focus-visible {
  background: rgba(255, 255, 255, .18);
  border-color: var(--gold-bright);
}
.lightbox-close { top: clamp(.75rem, 2vw, 1.5rem); right: clamp(.75rem, 2vw, 1.5rem); }
.lightbox-prev  { top: 50%; left: clamp(.5rem, 2vw, 1.5rem); transform: translateY(-50%); }
.lightbox-next  { top: 50%; right: clamp(.5rem, 2vw, 1.5rem); transform: translateY(-50%); }

/* A one-photo album has nothing to step through. */
.lightbox[data-single] .lightbox-prev,
.lightbox[data-single] .lightbox-next { display: none; }

@media (prefers-reduced-motion: reduce) {
  .photo, .photo img, .photo::after, .lightbox { transition: none; }
}

/* -------------------------------------------------------- easter eggs --- */

/* Three links carried over from the old site that deliberately look like
   nothing. Each is the only route to the page it opens, so none can be
   dropped without stranding that page.

   The news page hid one in a sliver of whitespace under the banner, and the
   gallery page hid one under the last row of albums. */
.egg-link { display: block; height: 3px; }

/* The landing page's sits in the very bottom-right corner of the page, below
   the footer rather than above it. It lives outside every band so that body is
   its containing block, which is what puts it at the foot of the whole
   document instead of the foot of a section. */
body[data-page="home"] { position: relative; }

.egg-link.egg-corner {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 40px;
  height: 10px;
}

/* --------------------------------------------------------- news posts --- */

/* The topic and date line under the headline of the featured post. The cards
   in the archive below it use the plainer .card-meta instead - a gold chip on
   every card would compete with the .card-tag already sitting on the photo. */
.post-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .75rem;
  margin: 1rem 0 0;
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--muted);
}
/* .split-text h2 + p sets a larger gap for body copy; the meta line sits
   tighter under the headline than a paragraph would */
.split-text .post-meta { margin-top: 1rem; font-size: .875rem; }
.split-text .post-meta + p { margin-top: 1.1rem; }

.post-tag {
  padding: .3rem .75rem;
  border-radius: 3px;
  background: var(--navy);
  color: var(--gold-bright);
  font-size: .72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
}

/* --------------------------------------------------- news write-ups --- */

/* One story: /news/<post>. Built from _src/post.html, once per folder
   under content/posts/. Everything here is the body of the write-up; the
   banner, the photo grid and the cards at the foot are shared with the
   album pages and styled above. */

/* A column of running text, held to a readable measure rather than the
   full 1200px shell - these pages are paragraphs, not a layout. */
.post-body {
  max-width: 46rem;
  font-size: 1.05rem;
}
.post-body > p { margin-bottom: 1.2rem; }

.post-body h2 {
  margin: 2.75rem 0 1.1rem;
  font-size: clamp(1.4rem, 2.6vw, 1.85rem);
  font-weight: 500;
}
/* the first thing in the column has the band's own padding above it */
.post-body > :first-child { margin-top: 0; }

.post-list {
  margin: 0 0 1.2rem;
  padding: 0;
  list-style: none;
}
.post-list li { position: relative; padding-left: 1.35rem; }
.post-list li + li { margin-top: .5rem; }
.post-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: .62em;
  width: .45rem;
  height: .45rem;
  border-radius: 50%;
  background: var(--gold);
}

/* A picture inside the story. Width is left to the file: the photographs
   fill the column, while the CAD renders and board layouts the team drops
   in at a few hundred pixels stay their own size and sit in the middle,
   rather than being blown up to fit. */
.post-figure {
  margin: 1.75rem 0 2rem;
  text-align: center;
}
.post-figure img {
  margin-inline: auto;
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  background: var(--surface-alt);
}
.post-figure figcaption {
  margin-top: .8rem;
  font-size: .9rem;
  color: var(--muted);
}

/* ------------------------------------------------------------ tag list --- */

/* The disciplines that go into a robot, as a row of labels. */
.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: .55rem;
  margin: 1.75rem 0 0;
  padding: 0;
  list-style: none;
}
.tag-list li {
  padding: .4rem .85rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  font-size: .85rem;
  font-weight: 500;
  color: var(--body);
}
.band-alt .tag-list li { background: var(--surface); }

/* -------------------------------------------------------------- roster --- */

/* Officers and advisors: a role and a name, nothing else. Deliberately not
   cards - there are no photos, and a card around two lines reads as padding. */
.roster {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 0 2.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.person {
  padding: 1.1rem 0;
  border-top: 2px solid var(--line);
}
.person-role {
  display: block;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--gold);
}
.person-name {
  display: block;
  margin-top: .3rem;
  font-size: 1.15rem;
  color: var(--ink);
}

/* -------------------------------------------------------- calendar page --- */

/* The Google Calendar grid and the "next up" list, side by side. The grid is
   given the width: Google's own embed starts dropping detail below roughly
   700px, so the column beside it is kept to a fixed narrow track and the two
   stack early rather than both being squeezed. */
.calendar-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 20rem;
  gap: clamp(1.75rem, 3.5vw, 3rem);
  align-items: start;
}

/* The embed has no intrinsic aspect ratio and ignores a percentage height on
   an auto-height parent, so the frame has to set an explicit box for it to
   fill. The min/max keep it from becoming a letterbox on a wide screen or
   unusably short on a small one. */
.calendar-frame {
  position: relative;
  aspect-ratio: 4 / 3;
  min-height: 30rem;
  max-height: 42rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}
.calendar-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.calendar-subscribe {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .9rem 1.25rem;
  margin-top: 1.35rem;
}
.calendar-subscribe .btn { flex: none; gap: .5rem; }
.calendar-subscribe p {
  flex: 1 1 18rem;
  margin: 0;
  font-size: .875rem;
  color: var(--muted);
}

/* ---- the next few events -------------------------------------------- */

.calendar-side {
  padding: 1.5rem;
  border: 1px solid var(--line);
  border-top: 2px solid var(--gold);
  border-radius: var(--radius);
  background: var(--surface-alt);
}
.calendar-side h3 {
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--navy);
}

.upcoming {
  margin: 1.15rem 0 0;
  padding: 0;
  list-style: none;
}
.upcoming li {
  display: flex;
  gap: .9rem;
  padding: .85rem 0;
  border-top: 1px solid var(--line);
}
.upcoming li:first-child { border-top: 0; padding-top: 0; }
.upcoming li:last-child { padding-bottom: 0; }

/* the date chip down the left of each row */
.event-date {
  flex: none;
  width: 3rem;
  padding: .3rem 0;
  border-radius: var(--radius);
  background: var(--navy);
  color: #fff;
  text-align: center;
  line-height: 1.2;
}
.event-day { display: block; font-size: 1.15rem; font-weight: 600; }
.event-month {
  display: block;
  font-size: .65rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--gold-bright);
}

.event-body { min-width: 0; }
.event-name {
  display: block;
  font-size: .95rem;
  font-weight: 500;
  color: var(--ink);
}
.event-when {
  display: block;
  margin-top: .15rem;
  font-size: .82rem;
  color: var(--muted);
}

/* Carries the loading line, and stays in place as the failure and
   nothing-scheduled message - so this column is never blank. */
.upcoming-note {
  margin: 1.15rem 0 0;
  font-size: .875rem;
  color: var(--muted);
}

/* The list is deliberately not sticky. Sticky would let it travel only as far
   as the bottom of its own grid row and then stop dead, which reads as an inch
   of drift rather than as a panel that follows you - worse than not moving at
   all. It sits still beside the grid instead. */

/* 1160px is where the calendar column, after the shell padding, the 20rem
   list beside it and the gap between them, stops being about 700px wide -
   which is the width below which Google's month view starts crowding its
   day columns. Rather than let it get narrower, hand it the whole width. */
@media (max-width: 1159px) {
  .calendar-layout { grid-template-columns: 1fr; }
  .calendar-frame { min-height: 26rem; }
}

@media (max-width: 560px) {
  .calendar-frame { aspect-ratio: 3 / 4; max-height: none; }
}

/* ------------------------------------------------------ sponsor levels --- */

/* The four sponsorship levels: the list of them on /sponsors, and the cards
   describing what each one gets on /sponsors/support-us.

   Each level owns a colour, set once as --tier on the block and read by
   everything inside it - the rule above a level, the stripe on a card, the
   bullets in its benefit list. One declaration per level, rather than four
   copies of every rule that needs the colour. */

.tier-platinum { --tier: var(--tier-platinum); }
.tier-gold     { --tier: var(--tier-gold); }
.tier-silver   { --tier: var(--tier-silver); }
.tier-bronze   { --tier: var(--tier-bronze); }

/* ---- the levels on the sponsors page --------------------------------- */

/* One row per level: what the level is on the left, who is in it on the
   right. The coloured rule across the top is all that separates one level
   from the next, so the four read as a single list rather than as four
   boxes competing for attention. */
.tier {
  display: grid;
  grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  margin-top: 3rem;
  padding-top: 1.5rem;
  border-top: 3px solid var(--tier, var(--gold));
}
.tier:first-child { margin-top: 0; }

.tier-name { font-size: 1.5rem; font-weight: 500; }
.tier-amount {
  display: block;
  margin-top: .4rem;
  font-size: .82rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}
.tier-perk { margin-top: .85rem; font-size: .95rem; }

/* Every logo gets the same box whatever shape it arrives in, so a wide
   wordmark and a square badge sit on one line without either towering over
   the other. object-fit keeps them from being stretched to fill it. */
.sponsor-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.sponsor { width: 13.5rem; max-width: 100%; }

.sponsor-frame {
  display: grid;
  place-items: center;
  height: 9rem;
  padding: 1.5rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: transform .28s var(--ease), box-shadow .28s var(--ease);
}
a.sponsor-frame:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); }
.sponsor-frame img { max-height: 100%; width: auto; object-fit: contain; }

.sponsor-name {
  display: block;
  margin-top: .7rem;
  text-align: center;
  font-size: .875rem;
  color: var(--muted);
}

/* A level nobody has taken yet. Dashed rather than solid, so it reads as a
   gap in the wall of logos rather than as a sponsor whose name happens to
   be "this level is open". */
.tier-open {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .35rem 1.25rem;
  /* about the width of the two logos a level would hold, so an empty level
     reads as a space waiting to be filled rather than as an announcement */
  max-width: 28.5rem;
  margin: 0;
  padding: 1.5rem 1.75rem;
  border: 1px dashed #CBD1D8;
  border-radius: var(--radius);
  color: var(--muted);
}
.tier-open .card-link {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  margin: 0;
  padding: 0;
}
.tier-open .card-link:hover { color: var(--gold); }
.tier-open .card-link:hover i { transform: translateX(4px); }

@media (max-width: 880px) {
  .tier { grid-template-columns: 1fr; }
}

/* ---- what each level gets, on the support-us page -------------------- */

/* These are .info-cards, and .info-card's stripe already reads --tier, so
   the level classes above colour them with nothing further added here. */
.benefit-list {
  margin: 1.1rem 0 0;
  padding: 0;
  list-style: none;
  font-size: .95rem;
}
.benefit-list li { position: relative; padding-left: 1.35rem; }
.benefit-list li + li { margin-top: .6rem; }
.benefit-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: .58em;
  width: .45rem;
  height: .45rem;
  border-radius: 50%;
  background: var(--tier, var(--gold));
}

/* ---------------------------------------------------------- scoreboard --- */

/* The header button. It ships with the hidden attribute and site.js takes it
   off only while the scoring sheet says the scoreboard is open, so this has to
   beat .btn's own display:inline-flex or a closed scoreboard would still show
   a button all year. */
.btn[hidden] { display: none; }

/* .site-nav a sets its own colour and is more specific than .btn-navy, so the
   button needs saying again from inside the nav or the label comes out navy on
   navy. The sliding gold underline every nav link gets is wrong on a button,
   so it is turned off here too. */
.site-nav .nav-scoreboard {
  gap: .55rem;
  color: #fff;
}
.site-nav .nav-scoreboard:hover { color: #fff; }
.site-nav .nav-scoreboard::after { display: none; }

.live-dot {
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: 50%;
  background: var(--gold-bright);
  animation: pulse 2.2s var(--ease) infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: .45; transform: scale(.8); }
}
@media (prefers-reduced-motion: reduce) { .live-dot { animation: none; } }

.scoreboard-status {
  margin: 0 0 1.25rem;
  font-size: .9rem;
  font-weight: 500;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}

/* the off-season state: the sheet is reachable and says it is closed */
.scoreboard-closed {
  padding: clamp(2.5rem, 6vw, 4rem) 1.5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-alt);
  text-align: center;
}
.scoreboard-closed .fa {
  font-size: 1.75rem;
  color: var(--gold);
}
.scoreboard-closed h3 { margin: 1rem 0 .6rem; font-size: 1.4rem; }
.scoreboard-closed p { max-width: 38rem; margin-inline: auto; color: var(--muted); }
.scoreboard-closed .btn { margin-top: 1.5rem; }

/* ---- the podium ---- */

.podium-heading {
  margin-bottom: 1rem;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--gold);
}

.podium {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 1rem;
  margin: 0 0 2rem;
  padding: 0;
  list-style: none;
}

.podium-card {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto;
  column-gap: 1rem;
  align-items: center;
  padding: 1.25rem 1.4rem;
  border: 1px solid var(--line);
  border-top: 3px solid var(--tier, var(--gold));
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}
.podium-card.is-rank-1 { --tier: var(--tier-gold); }
.podium-card.is-rank-2 { --tier: var(--tier-silver); }
.podium-card.is-rank-3 { --tier: var(--tier-bronze); }

.podium-place {
  grid-row: 1 / 3;
  display: grid;
  place-items: center;
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  background: var(--tier, var(--gold));
  color: #fff;
  font-size: 1.15rem;
  font-weight: 700;
}
.podium-team {
  font-weight: 600;
  line-height: 1.3;
  color: var(--ink);
}
.podium-score {
  font-size: 1.05rem;
  font-weight: 500;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* ---- the table ---- */

/* Six rounds plus a total is wider than a phone and there is no honest way
   round that, so the table scrolls sideways on its own and the team column
   stays put while it does - otherwise you scroll to a column and no longer
   know whose row you are reading. */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  -webkit-overflow-scrolling: touch;
}

.score-table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

.score-table th,
.score-table td {
  padding: .8rem 1rem;
  text-align: right;
  white-space: nowrap;
  border-bottom: 1px solid var(--line);
}
.score-table tbody tr:last-child td { border-bottom: 0; }

.score-table th { background: var(--surface-alt); padding: 0; }

.score-table .col-team {
  position: sticky;
  left: 0;
  z-index: 1;
  text-align: left;
  white-space: normal;
  min-width: 11rem;
  max-width: 18rem;
  font-weight: 600;
  color: var(--ink);
  background: var(--surface);
  box-shadow: 1px 0 0 var(--line);
}
.score-table thead .col-team { z-index: 2; background: var(--surface-alt); }
.score-table .col-total .score { font-size: 1.1rem; font-weight: 700; color: var(--ink); }

/* every heading is a sort button, so it has to fill the cell it sits in */
.score-table .sort {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .1rem;
  width: 100%;
  padding: .75rem 1rem;
  border: 0;
  background: none;
  font: inherit;
  color: var(--navy);
  text-align: right;
  cursor: pointer;
  transition: color .18s var(--ease);
}
.score-table .col-team .sort { align-items: flex-start; text-align: left; }
.score-table .sort:hover { color: var(--gold); }

.score-table .sort-label {
  font-size: .9rem;
  font-weight: 600;
  letter-spacing: .02em;
}
.score-table .sort-sub {
  font-size: .72rem;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}
.score-table .sort.is-sorted .sort-label { color: var(--gold); }
.score-table .sort.is-sorted .sort-label::after {
  content: '';
  display: inline-block;
  margin-left: .4rem;
  border: .3em solid transparent;
  border-top-color: currentColor;
  transform: translateY(.15em);
}
.score-table th[aria-sort="ascending"] .sort-label::after {
  border-top-color: transparent;
  border-bottom-color: currentColor;
  transform: translateY(-.15em);
}

.score-table .score { display: block; font-weight: 500; color: var(--ink); }
.score-table .threw {
  display: block;
  margin-top: .1rem;
  font-size: .74rem;
  letter-spacing: .04em;
  color: var(--muted);
}

/* the leaders. The tint has to be repeated on the sticky team cell, which
   paints its own background over whatever the row would otherwise show. */
.score-table tbody .is-top td { --tint: rgba(179, 163, 105, .10); background: var(--tint); }
.score-table tbody .is-rank-1 td { --tint: rgba(201, 162, 39, .13); }
.score-table tbody .is-rank-2 td { --tint: rgba(163, 170, 178, .16); }
.score-table tbody .is-rank-3 td { --tint: rgba(169, 97, 58, .11); }
.score-table tbody .is-top .col-team {
  background: linear-gradient(var(--tint), var(--tint)), var(--surface);
  box-shadow: inset 3px 0 0 var(--tier, var(--gold)), 1px 0 0 var(--line);
}
.score-table tbody .is-rank-1 .col-team { --tier: var(--tier-gold); }
.score-table tbody .is-rank-2 .col-team { --tier: var(--tier-silver); }
.score-table tbody .is-rank-3 .col-team { --tier: var(--tier-bronze); }

/* a team the judges put out. Everything it threw stays in the table - only
   the total is replaced - so the row is tinted and stepped back rather than
   struck through, which would make the rounds look retracted too. */
.score-table tbody .is-dq td { --tint: rgba(158, 59, 50, .06); background: var(--tint); }
.score-table tbody .is-dq .col-team {
  background: linear-gradient(var(--tint), var(--tint)), var(--surface);
  box-shadow: inset 3px 0 0 var(--dq), 1px 0 0 var(--line);
}
.score-table tbody .is-dq .score { color: var(--muted); font-weight: 400; }
.score-table tbody .is-dq .col-total .score {
  color: var(--dq);
  font-weight: 700;
  letter-spacing: .08em;
}

/* ---- under the table ---- */

.scoreboard-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1.25rem;
}
/* display:flex above would otherwise win over the hidden attribute, and the
   closed and not-set-up states both hide this */
.scoreboard-foot[hidden] { display: none; }

.scoreboard-updated { margin: 0; font-size: .875rem; color: var(--muted); }
.scoreboard-foot .btn { gap: .5rem; }
.scoreboard-foot .btn[disabled] { opacity: .5; pointer-events: none; }

.scoreboard-note {
  max-width: 46rem;
  margin: 1.75rem 0 0;
  font-size: .9rem;
  color: var(--muted);
}
.scoreboard-noscript { margin: 0; }

/* ----------------------------------------------------------- cta band ---- */

.cta {
  position: relative;
  padding-block: var(--band);
  background: var(--navy-ink);
  color: #fff;
  text-align: center;
  overflow: hidden;
}
.cta::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(70% 120% at 50% -10%, rgba(179,163,105,.20) 0%, transparent 62%);
}
.cta > * { position: relative; }
.cta h2 {
  max-width: 26ch;
  margin-inline: auto;
  font-size: clamp(1.9rem, 4.2vw, 3rem);
  font-weight: 300;
  letter-spacing: -.02em;
  color: #fff;
}
.cta p {
  max-width: 52ch;
  margin: 1.15rem auto 0;
  color: rgba(255, 255, 255, .78);
}
.cta-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .9rem;
  justify-content: center;
  margin-top: 2.25rem;
}

/* ------------------------------------------------------------- footer ---- */

.site-footer { background: var(--navy-ink); color: rgba(255,255,255,.72); }

.footer-inner {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 2fr);
  gap: clamp(2rem, 5vw, 4rem);
  padding-block: clamp(3rem, 6vw, 4.5rem);
}
@media (max-width: 820px) { .footer-inner { grid-template-columns: 1fr; } }

.footer-brand img {
  height: 52px;
  width: auto;
  filter: brightness(0) invert(1);
  opacity: .95;
}
.footer-brand p { margin-top: 1.1rem; max-width: 30ch; font-size: .95rem; }

.footer-links {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 2rem;
}
.footer-links h3 {
  margin-bottom: .9rem;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--gold);
}
.footer-links ul { margin: 0; padding: 0; list-style: none; }
.footer-links li { margin-bottom: .55rem; font-size: .95rem; }
.footer-links a { color: rgba(255,255,255,.75); }
.footer-links a:hover { color: var(--gold-bright); }
.footer-place { color: rgba(255,255,255,.5); line-height: 1.6; }

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: center;
  justify-content: space-between;
  padding-block: 1.4rem;
  border-top: 1px solid rgba(255,255,255,.12);
  font-size: .88rem;
}
.footer-bottom p { margin: 0; }

.social { display: flex; gap: .4rem; margin: 0; padding: 0; list-style: none; }
.social a {
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  border-radius: 50%;
  background: rgba(255,255,255,.07);
  color: rgba(255,255,255,.8);
  font-size: 1rem;
  transition: background .2s var(--ease), color .2s var(--ease);
}
.social a:hover { background: var(--gold); color: var(--navy-ink); }
.social-icon { width: 1.15em; height: 1.15em; fill: currentColor; display: block; }

/* --------------------------------------------------------- animations ---- */

.js .reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
}
.js .reveal.is-visible { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; transition: none; }
  .card:hover, .info-card:hover, .btn:hover { transform: none; }
}
