/* NDPC 2027 — palette drawn from the conference flyer.

   Colour is expressed entirely through the custom properties below. The token
   names are ROLES, not literal colours: --black is "the page background" and
   --white is "the emphasised text colour", so they invert in the light theme
   rather than staying literally black and white. Nothing outside this block
   should carry a hard-coded colour, otherwise it would survive the theme swap
   and be wrong in one of the two themes.

   Dark is the default because it matches the conference flyer. */

:root {
  /* Soft charcoals with a slight cool cast, rather than pure black — easier on
     the eyes over long reading, and it lets the surfaces above the page
     background actually read as raised panels instead of near-invisible steps. */
  --black: #17171A;
  --surface: #212127;
  --surface-2: #2B2B33;
  --gold: #F5B800;
  --gold-bright: #FFD34D;
  --white: #FFFFFF;
  --body: #EDEDF2;
  --muted: #B9B9C6;
  --red: #D62828;
  --red-bright: #FF6B5E;
  --green: #4C7A34;
  --green-bright: #7FD25C;
  --border: #43434E;

  /* Text printed ON a gold fill (buttons, skip link). On the flyer's bright
     gold that is black; the light theme's darker gold needs white instead, so
     it cannot simply be --black. */
  --on-gold: #000000;

  /* Countdown band gradient and card wash, previously hard-coded. */
  --band-top: #26262E;
  --band-bottom: #1B1B20;
  --card-wash: rgba(255, 255, 255, 0.05);

  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, "Noto Sans", sans-serif;

  --wrap: 1080px;
  --space: 1rem;
}

/* ---------- Light theme ----------

   The brand gold #F5B800 scores only 1.79:1 on white, far below the 4.5:1 WCAG
   AA threshold for text, so the light theme uses a darker amber. Every text and
   background pair was measured; the ratios are recorded in README.md. */

[data-theme="light"] {
  /* A warm off-white ground rather than pure #FFF, and text softened well
     short of black. Maximum contrast is not the goal above the AA threshold:
     pure white behind near-black text glares, so the page sits a little below
     both extremes while every pair still clears 4.5:1 by a wide margin.
     Cards are LIGHTER than the page here, which reads as raised on a warm
     ground where a darker panel would read as a hole. */
  --black: #F6F2EA;         /* page background */
  --surface: #FBF8F3;       /* cards, header, footer */
  --surface-2: #EDE7DC;     /* table headers, captions */
  --gold: #8C5000;          /* headings, borders — 5.76:1 on the page */
  --gold-bright: #6B4000;   /* links, hover — 7.97:1 */
  --white: #241F19;         /* emphasised text — 14.64:1 */
  --body: #3A342C;          /* body text — 11.01:1 */
  --muted: #6B6358;         /* secondary text — 5.30:1 */
  --red: #B3261E;
  --red-bright: #8E1C16;
  --green: #3F6B29;
  --green-bright: #2F5220;
  --border: #DDD5C7;

  --on-gold: #FFFFFF;       /* white on #8C5000 — 6.44:1 */

  --band-top: #FBF8F3;
  --band-bottom: #EDE7DC;
  --card-wash: rgba(0, 0, 0, 0.025);
}

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--black);
  color: var(--body);
  font-family: var(--font);
  font-size: 1rem;          /* 16px minimum */
  line-height: 1.65;
}

/* Keyboard focus is always visible, on every interactive element. */
:focus-visible {
  outline: 3px solid var(--gold-bright);
  outline-offset: 3px;
  border-radius: 2px;
}

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

/* Available to screen readers, removed from the visual layout. Used where a
   section needs a heading for the document outline but showing one would be
   redundant next to the content it labels. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

a { color: var(--gold-bright); }
a:hover { color: var(--white); }

h1, h2, h3, h4 {
  color: var(--gold);
  line-height: 1.2;
  margin: 0 0 0.6em;
  font-weight: 800;
}

h1 { font-size: clamp(1.75rem, 5vw, 2.75rem); }
h2 { font-size: clamp(1.35rem, 3.6vw, 1.9rem); }
h3 { font-size: clamp(1.1rem, 2.8vw, 1.35rem); }

p { margin: 0 0 1.1em; }

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 var(--space);
}

/* Skip link */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--gold);
  color: var(--on-gold);
  padding: 0.75rem 1.25rem;
  font-weight: 700;
  z-index: 100;
}
.skip-link:focus {
  left: 0;
  color: var(--on-gold);
}

/* ---------- Header ---------- */

.site-header {
  border-bottom: 3px solid var(--gold);
  background: var(--surface);
}

.header-inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding-top: 1rem;
  padding-bottom: 1rem;
  flex-wrap: wrap;
}

/* The logo's wordmark is solid white, which disappears on a light background,
   so the light theme swaps in a variant with dark lettering. `content` on a
   replaced element substitutes the bitmap while leaving the <img> alt text —
   the accessible name — untouched, so both files share one <img> in the markup.
   The two files are the same 800x677 so the swap causes no reflow. */
[data-theme="light"] .site-logo,
[data-theme="light"] .hero-logo {
  content: url("../assets/ndpc-logo-light.png");
}

/* The link is the flex child now; the image inside it just fills the width. */
.site-logo-link {
  flex: 0 0 auto;
  display: block;
  line-height: 0;
  border-radius: 6px;
}

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

.site-logo {
  width: 114px;
  height: auto;
  display: block;
}

.brand-text { flex: 1 1 12rem; min-width: 0; }

.site-name {
  margin: 0;
  font-size: clamp(1.4rem, 4.5vw, 2rem);
  font-weight: 800;
  color: var(--gold);
  letter-spacing: 0.02em;
}

.site-tagline {
  margin: 0.15rem 0 0;
  color: var(--white);
  font-style: italic;
  font-size: 1rem;
}

/* ---------- Theme toggle ----------

   The only control in the header. Square and icon-only so it costs little
   width at 360px, where it shares one row with the logo and the wordmark. */

.theme-toggle {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;   /* 44px — the minimum comfortable touch target */
  height: 2.75rem;
  padding: 0;
  background: transparent;
  color: var(--gold);
  border: 2px solid var(--gold);
  border-radius: 6px;
  cursor: pointer;
  font: inherit;
}

@media (hover: hover) {
  .theme-toggle:hover {
    background: var(--gold);
    color: var(--on-gold);
  }
}

.theme-toggle:active {
  background: var(--gold);
  color: var(--on-gold);
}

.theme-toggle svg {
  width: 1.35rem;
  height: 1.35rem;
  display: block;
}

/* Exactly one of the two icons shows, decided by the active theme rather than
   by JS, so the icon can never drift out of sync with the theme. */
.theme-toggle .icon-moon { display: none; }
.theme-toggle .icon-sun { display: block; }

[data-theme="light"] .theme-toggle .icon-moon { display: block; }
[data-theme="light"] .theme-toggle .icon-sun { display: none; }

/* ---------- Nav ---------- */

.site-nav {
  background: var(--black);
  border-bottom: 1px solid var(--border);
}

.nav-list {
  list-style: none;
  /* `margin: 0` and `padding: 0` here would override the centring and gutter
     that .wrap provides, leaving the nav flush against the viewport edge
     while every other element stays within the 1080px column. */
  margin: 0 auto;
  padding: 0 var(--space);
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
}

/* Each link carries 1rem of its own side padding, which would push the first
   item's TEXT a further 1rem left of the headings below. Pulling the first
   link back by that amount lines the nav text up with the page content. */
@media (min-width: 721px) {
  .nav-list > li:first-child {
    margin-left: -1rem;
  }
}

.nav-list a {
  display: block;
  padding: 0.85rem 1rem;
  color: var(--white);
  text-decoration: none;
  font-weight: 600;
  border-bottom: 4px solid transparent;
}

.nav-list a:hover {
  color: var(--gold-bright);
  border-bottom-color: var(--red-bright);
}

.nav-list a[aria-current="page"] {
  color: var(--gold);
  border-bottom-color: var(--gold);
}

/* Seven items need 743px to stay on one row, but the horizontal nav appears at
   721px — a 22px band where it wrapped to two rows. Tightening the side
   padding across the narrow end of the desktop range buys about 78px, well
   clear of the breakpoint. The first-child offset tracks the padding, or the
   nav text stops lining up with the headings below it. */
@media (min-width: 721px) and (max-width: 820px) {
  .nav-list a {
    padding-left: 0.65rem;
    padding-right: 0.65rem;
  }

  .nav-list > li:first-child {
    margin-left: -0.65rem;
  }
}

/* ---------- Main ---------- */

main { padding: 2.5rem 0 3rem; }

/* A full-bleed hero is the first thing in <main>, so main's top padding would
   show as a strip of page background above it. */
main > .hero:first-child { margin-top: -2.5rem; }

.lede {
  font-size: 1.15rem;
  color: var(--white);
}

.subhead {
  color: var(--white);
  font-size: clamp(1.1rem, 3vw, 1.4rem);
  font-weight: 600;
  margin-top: -0.4em;
}

/* ---------- Anniversary lockup ----------

   One flat sentence beside the logo read as a stray caption. Set as three
   ranged-left lines behind a gold rule — the same left-accent language the
   fact cards and notes use elsewhere — it reads as a deliberate mark and
   holds its own next to the logo at any width. */

.anniversary {
  margin: 0;
  border-left: 5px solid var(--gold);
  padding-left: 0.9rem;
}

.anniversary span { display: block; }

.anniversary-kicker {
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.anniversary-years {
  font-size: clamp(1.6rem, 6vw, 2.2rem);
  font-weight: 800;
  line-height: 1.1;
  color: var(--gold);
}

.anniversary-range {
  font-size: clamp(0.95rem, 2.6vw, 1.1rem);
  font-weight: 600;
  color: var(--white);
}

section { margin-bottom: 2.5rem; }

.facts {
  margin: 0 0 2rem;
  display: grid;
  gap: 1rem;
}

@media (min-width: 620px) {
  .facts { grid-template-columns: 1fr 1fr; }
}

.facts > div {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 5px solid var(--green);
  padding: 1rem 1.1rem;
}

.facts dt {
  color: var(--gold);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.95rem;
  margin-bottom: 0.25rem;
}

.facts dd { margin: 0; color: var(--white); }

/* ---------- Buttons ---------- */

/* An actions row is its own block, not a continuation of the paragraph above
   it, so it is centred rather than hung off the left margin — a lone button
   under a full-width column read as stranded there. */
.actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: stretch;
  gap: 0.75rem;
  margin: 2rem 0;
}

/* inline-flex with a min-height rather than inline-block with padding: two
   buttons side by side then match in height even when one label wraps and the
   other does not, which is what made the pairs look misaligned. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 3rem;
  padding: 0.7rem 1.4rem;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.25;
  text-align: center;
  text-decoration: none;
  border-radius: 8px;
  border: 2px solid var(--gold);
  background: var(--gold);
  color: var(--on-gold);
}

/* Hover belongs to pointers that can hover; on a touch screen it sticks
   after the tap. */
@media (hover: hover) {
  .btn:hover {
    background: var(--gold-bright);
    border-color: var(--gold-bright);
    color: var(--on-gold);
  }
}

.btn:active {
  background: var(--gold-bright);
  border-color: var(--gold-bright);
  color: var(--on-gold);
}

.btn-secondary {
  background: transparent;
  color: var(--gold);
  border-color: var(--gold);
}

@media (hover: hover) {
  .btn-secondary:hover {
    background: var(--gold);
    color: var(--on-gold);
  }
}

.btn-secondary:active {
  background: var(--gold);
  color: var(--on-gold);
}

/* Inside a split the row belongs to a text column and lines up with that
   column's text; centred, it floated in the middle of the column with the
   heading and paragraphs ranged left around it. Paired with the stacking
   breakpoint below: once the buttons stop stacking they range left here. */
@media (min-width: 561px) {
  .split .actions { justify-content: flex-start; }
}

/* Below roughly 560px two buttons no longer fit side by side. Stacking them to
   a shared width reads as one tidy column, where wrapping left them ragged;
   the cap keeps them off the screen edges, which a full-width gold slab did
   not. */
@media (max-width: 560px) {
  .actions {
    flex-direction: column;
    align-items: center;
  }

  .actions .btn {
    width: 100%;
    max-width: 20rem;
  }
}

/* ---------- Flyer ---------- */

.flyer {
  margin: 2rem 0 0;
}

/* Inside a .split the figure is already in a column, so it needs no extra
   margin above and should not outgrow a comfortable reading height. */
.split .flyer { margin: 0; }

.split .flyer img { max-width: 420px; }

.flyer img {
  margin: 0 auto;
  border: 3px solid var(--gold);
  max-width: 640px;
  width: 100%;
}

.flyer figcaption {
  margin-top: 0.75rem;
  color: var(--muted);
  font-size: 0.95rem;
  text-align: center;
}

/* ---------- Section bands ----------

   Full-bleed alternating backgrounds give the page a rhythm that plain stacked
   headings and paragraphs cannot. The band breaks out of .wrap to span the
   viewport; an inner .wrap re-establishes the reading column. Using padding
   (not margin) means adjacent bands meet with no gap.

   100vw would overflow when a scrollbar is present, so the width comes from
   the container itself and the negative margin pulls it out to each edge. */

.band {
  margin-inline: calc(50% - 50vw);
  padding-block: clamp(2.5rem, 6vw, 4rem);
  padding-inline: 0;
  width: 100vw;
  max-width: 100vw;
  /* `section` carries a bottom margin sitewide; zeroing it here lets two bands
     meet edge to edge instead of showing a strip of page background between. */
  margin-bottom: 0;
}

/* Space between a band and the ordinary content around it, without reopening
   a gap where two bands are adjacent. */
.band + :not(.band) { padding-top: clamp(2rem, 5vw, 3rem); }
:not(.band) + .band { margin-top: clamp(2rem, 5vw, 3rem); }

.band > .wrap > :first-child { margin-top: 0; }
.band > .wrap > :last-child { margin-bottom: 0; }

.band-surface {
  background: var(--surface);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}

/* The accent band is the page's loudest note; used sparingly, once per page.
   Its edges are a hairline rather than a heavy gold rule: several bands can
   meet on one page, and thick rules at every seam read as stripes. */
.band-accent {
  background: linear-gradient(180deg, var(--band-top) 0%, var(--band-bottom) 100%);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}

/* ---------- Section headings with an icon ----------

   The icon is decorative: the heading text already names the section, so the
   SVG is aria-hidden and adds emphasis rather than meaning. */

.section-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1rem;
}

.section-head h2,
.section-head h3 { margin: 0; }

.section-icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  color: var(--gold);
  border: 2px solid var(--gold);
  border-radius: 50%;
}

.section-icon svg {
  width: 1.5rem;
  height: 1.5rem;
  display: block;
}

/* ---------- Stat strip ---------- */

.stats {
  list-style: none;
  /* Inside a .band the band's own padding sets the spacing, but on a plain
     page the strip needs its own room beneath it or the next section butts
     straight against the cards. */
  margin: 0 0 clamp(2rem, 5vw, 3rem);
  padding: 0;
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(2, 1fr);
  text-align: center;
}

/* The band supplies the spacing there, so the strip adds none of its own. */
.band .stats { margin-bottom: 0; }

@media (min-width: 720px) {
  .stats { grid-template-columns: repeat(4, 1fr); }
}

.stat {
  padding: 1.1rem 0.75rem;
  background: var(--card-wash);
  border: 1px solid var(--border);
  border-radius: 8px;
}

.stat-value {
  display: block;
  font-size: clamp(1.9rem, 5vw, 3rem);
  font-weight: 800;
  line-height: 1.05;
  color: var(--gold);
  font-variant-numeric: tabular-nums;
}

.stat-label {
  display: block;
  margin-top: 0.35rem;
  font-size: 0.9rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ---------- Feature cards ---------- */

.feature-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1.25rem;
  grid-template-columns: 1fr;
}

@media (min-width: 620px) {
  .feature-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 920px) {
  .feature-grid.cols-3 { grid-template-columns: repeat(3, 1fr); }
}

.feature {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 5px solid var(--gold);
  border-radius: 6px;
  padding: 1.2rem 1.3rem;
}

/* On a surface-coloured band the cards need a different ground to stay
   distinct from it. */
.band-surface .feature { background: var(--surface-2); }

.feature-icon {
  color: var(--gold);
  margin-bottom: 0.65rem;
}

.feature-icon svg { width: 40px; height: 40px; display: block; }

.feature h3 {
  margin: 0 0 0.35rem;
  font-size: 1.15rem;
}

.feature p {
  margin: 0;
  color: var(--body);
}

/* ---------- Alternating image + text rows ---------- */

.split {
  display: grid;
  gap: 1.5rem;
  align-items: center;
}

@media (min-width: 800px) {
  .split { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2.5rem; }

  /* Flips the visual order so consecutive rows alternate sides. The DOM order
     is unchanged, so the reading and tab order stay correct. */
  .split.reverse > :first-child { order: 2; }
}

.split img {
  width: 100%;
  height: auto;
  border: 3px solid var(--gold);
  border-radius: 4px;
}

/* A cutaway render rather than a photograph: it has no frame edge of its own,
   so a border would fence off empty background. It is capped in height instead
   and centred in its column. */
.split .split-media {
  border: 0;
  border-radius: 0;
  width: auto;
  max-width: 100%;
  max-height: 26rem;
  margin: 0 auto;
}


.split-body > :first-child { margin-top: 0; }
.split-body > :last-child { margin-bottom: 0; }

/* ---------- Steps / timeline ---------- */

.steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1rem;
}

@media (min-width: 760px) {
  .steps { grid-template-columns: repeat(3, 1fr); }
}

.step {
  position: relative;
  padding: 1.1rem 1.2rem 1.2rem 3.4rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
}

.band-surface .step { background: var(--surface-2); }

/* The number is decorative ornament; the step's own heading carries meaning. */
.step-num {
  position: absolute;
  left: 1rem;
  top: 1.1rem;
  width: 1.85rem;
  height: 1.85rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--gold);
  color: var(--on-gold);
  font-weight: 800;
  font-size: 0.95rem;
}

.step h3 { margin: 0 0 0.3rem; font-size: 1.08rem; }
.step p { margin: 0; }

/* ---------- Pull quote ---------- */

.pull-quote {
  margin: 0;
  border-left: 5px solid var(--gold);
  padding: 0.4rem 0 0.4rem 1.25rem;
}

.pull-quote p {
  font-size: clamp(1.15rem, 2.6vw, 1.5rem);
  font-style: italic;
  font-weight: 600;
  color: var(--white);
  text-wrap: balance;
  margin: 0 0 0.5rem;
}

.pull-quote figcaption {
  color: var(--gold);
  font-weight: 700;
  font-size: 0.95rem;
}

/* ---------- Link cards (lodging, and any image + blurb + link set) ----------

   The whole card is clickable: the link is stretched over it with a pseudo
   element, which keeps a single focusable link and real link text for screen
   readers rather than wrapping the card in an <a> full of block content. */

.card-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1.25rem;
  grid-template-columns: 1fr;
}

@media (min-width: 640px) {
  .card-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 940px) {
  .card-grid.cols-3 { grid-template-columns: repeat(3, 1fr); }
}

.link-card,
.friend-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: 4px solid var(--gold);
  border-radius: 6px;
  overflow: hidden;
}

.band-surface .link-card { background: var(--surface-2); }

.link-card > img {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  background: var(--surface-2);
}

/* Cropping a cutaway render to the card's 16:10 would cut through the room, so
   this variant fits the whole image inside the frame instead. A transparent
   render on a card the same colour as the page reads as though it is floating
   loose, so the image area gets its own slightly recessed ground and a rule
   separating it from the text below. */
.link-card > img.fit {
  object-fit: contain;
  padding: 0.75rem;
  background: var(--black);
  border-bottom: 1px solid var(--border);
}

/* A grid holding a single card would otherwise stretch it across the full
   column; this keeps a lone card at a card's width. */
.card-grid.single {
  grid-template-columns: minmax(0, 32rem);
}

.link-card-body {
  padding: 1rem 1.1rem 1.2rem;
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
}

.link-card h3,
.friend-card h3 {
  margin: 0 0 0.35rem;
  font-size: 1.12rem;
}

/* The logo above is centred on its plate, so the name and link below it are
   centred too — left-aligned text under a centred mark reads as a misalignment
   rather than a choice. Only the Friends cards do this; the lodging and venue
   cards carry a paragraph of description, which reads better ranged left. */
.friend-card .link-card-body {
  text-align: center;
}

/* The link is a flex child, so centring the text is not enough to move the
   box itself onto the card's centre line. */
.friend-card .card-link {
  align-self: center;
}

.link-card p {
  margin: 0 0 0.9rem;
  color: var(--body);
  font-size: 0.98rem;
}

/* Pushes the link to the bottom so cards of unequal text still line up. */
.link-card .card-link { margin-top: auto; font-weight: 700; }

.link-card .card-link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.link-card:hover {
  border-color: var(--gold);
  background: var(--surface-2);
}

.band-surface .link-card:hover { background: var(--surface); }

/* The stretched link means the card, not the text, receives focus styling. */
.link-card:focus-within {
  outline: 3px solid var(--gold-bright);
  outline-offset: 3px;
}

.link-card .card-link:focus-visible { outline: none; }

/* Marks a link that leaves the site. This is a ::before because .card-link
   already spends its ::after on the stretched hit area covering the card. */
.ext::before {
  content: "↗ ";
  font-size: 0.9em;
}

/* ---------- Friends of NDPC ----------

   Partner logos are supplied as artwork drawn for a white backdrop, so the
   plate behind them stays literally white in BOTH themes. It is a hard
   #FFFFFF rather than the --white token, which is a text role and inverts:
   in the light theme --white resolves to near-black, which would swallow the
   logo it is meant to hold up. This is the same reasoning, and the same
   value, as the sponsor plate on .logo-row li.

   No partner logo is in the repository yet. These rules are written ahead of
   the files so that dropping one in is markup only, as with the .person-card
   rules that wait on presenter photos. */

.friend-plate {
  background: #FFFFFF;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  /* 140px of artwork plus the padding, so the tallest logo sets the height
     and the plates line up across the row. */
  min-height: 172px;
  border-bottom: 1px solid var(--border);
}

.friend-plate img {
  max-width: 100%;
  max-height: 140px;
  width: auto;
  height: auto;
}

/* Caps a logo whose source file is small, so the plate's full width cannot
   scale it past its native size into blur. DWC's file is 140x139, so this is
   exactly its native width. */
.friend-plate img.is-small { max-width: 140px; }

/* ---------- Photo banner ----------

   A wide photograph used as a section closer rather than as content to study.
   Held back in opacity so it reads as atmosphere; brought to full strength on
   hover and on keyboard focus for anyone who wants to look properly. */

/* ---------- Banner with an overlaid card ----------

   Below 900px the card sits beneath the banner: there is not enough width to
   lay a readable card over the photograph without burying it. */

.banner-stage {
  margin-bottom: clamp(2rem, 5vw, 3rem);
  display: grid;
  gap: 1.25rem;
}

@media (min-width: 900px) {
  .banner-stage {
    position: relative;
    display: block;
  }

  /* The photograph is a wide 2.5:1 crop, which leaves a short banner for the
     card to sit in. Cropping it taller gives the card room to be a usable
     size; object-position keeps the seating, not the ceiling, in frame. */
  .banner-stage .photo-banner img {
    height: 32rem;
    object-fit: cover;
    object-position: center 62%;
  }

  .banner-card {
    position: absolute;
    top: 50%;
    right: clamp(1.5rem, 4vw, 3rem);
    transform: translateY(-50%);
    width: min(29rem, 44%);
    /* Lifts the card off the photograph so it reads as a separate surface. */
    box-shadow: 0 10px 34px rgb(0 0 0 / 0.5);
  }

  /* The card must stay shorter than the photograph it sits on, so its image
     is given a fixed band rather than the usual 16:10. The render is trimmed
     tight to its subject, so it needs little padding to breathe. */
  .banner-card img.fit {
    aspect-ratio: auto;
    height: 13rem;
    padding: 0.4rem 0.4rem 0;
  }

  /* The card covers the right-hand side, so the caption is pulled clear of it
     rather than running underneath. */
  .banner-stage .photo-banner figcaption {
    right: min(29rem, 44%);
    padding-right: clamp(1rem, 3vw, 2rem);
  }
}

.photo-banner {
  position: relative;
  margin: 0;
  border-radius: 6px;
  border: 1px solid var(--border);
  overflow: hidden;
  /* The caption sits on the photo, so the frame must be dark underneath it:
     the image is dimmed toward this, not toward the page colour. */
  background: #000;
}

.photo-banner img {
  width: 100%;
  display: block;
  opacity: 0.55;
}

/* The dark theme sits the photo on near-black, where the same fade reads much
   stronger, so it needs less of it than the light theme does. */
[data-theme="light"] .photo-banner img { opacity: 0.68; }

.photo-banner figcaption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: clamp(1.5rem, 5vw, 2.5rem) clamp(1rem, 3vw, 1.75rem)
           clamp(0.9rem, 2.5vw, 1.25rem);
  /* A gradient scrim rather than a flat bar: it keeps the text legible over
     whatever happens to be in the lower part of the photograph without
     boxing it off. */
  background: linear-gradient(180deg, rgb(0 0 0 / 0) 0%, rgb(0 0 0 / 0.75) 60%);
  color: #FFFFFF;
  font-size: clamp(0.95rem, 2vw, 1.1rem);
  font-weight: 600;
  text-shadow: 0 1px 3px rgb(0 0 0 / 0.8);
}

/* ---------- Section divider ----------

   A rule with a diamond centred on it, for separating two sections that would
   otherwise run together. Purely decorative, so it is hidden from assistive
   technology — the headings on either side already mark the boundary. */

.divider {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin: clamp(2.5rem, 6vw, 4rem) 0;
  color: var(--gold);
}

.divider::before,
.divider::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--border), transparent);
}

.divider span {
  flex: 0 0 auto;
  width: 0.6rem;
  height: 0.6rem;
  transform: rotate(45deg);
  background: currentColor;
}

/* ---------- Venue photo ---------- */

.venue-photo {
  margin: 1.5rem 0;
}

.venue-photo img {
  border: 3px solid var(--gold);
  width: 100%;
}

.venue-photo figcaption {
  margin-top: 0.6rem;
  color: var(--muted);
  font-size: 0.95rem;
}

/* ---------- Tables ---------- */

.table-scroll {
  overflow-x: auto;
  margin-bottom: 2rem;
  border: 1px solid var(--border);
}

table {
  width: 100%;
  border-collapse: collapse;
  min-width: 32rem;
  background: var(--surface);
}

caption {
  caption-side: top;
  text-align: left;
  color: var(--gold);
  font-weight: 800;
  font-size: 1.15rem;
  padding: 0.85rem 1rem;
  background: var(--surface-2);
  border-bottom: 2px solid var(--gold);
}

th, td {
  padding: 0.75rem 1rem;
  text-align: left;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}

thead th {
  color: var(--gold);
  background: var(--surface-2);
  font-size: 1rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

tbody th {
  color: var(--white);
  font-weight: 700;
}

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

td { color: var(--body); }

.amount { color: var(--gold-bright); font-weight: 700; white-space: nowrap; }

/* ---------- Schedule ---------- */

.schedule {
  list-style: none;
  margin: 0 0 1.25rem;
  padding: 0;
}

.schedule li {
  background: var(--surface);
  border-left: 5px solid var(--gold);
  padding: 0.85rem 1.1rem;
  margin-bottom: 0.6rem;
  color: var(--white);
  font-size: 1.05rem;
  font-weight: 600;
}

/* ---------- Notes & callouts ---------- */

.note {
  background: var(--surface);
  border-left: 5px solid var(--red);
  padding: 1rem 1.1rem;
  margin: 0 0 1.25rem;
  color: var(--white);
}

.callout {
  border: 3px solid var(--gold);
  background: var(--surface);
  padding: 1.25rem 1.35rem;
  margin: 2rem 0;
}

.callout h2 { margin-top: 0; }

.subtotal {
  color: var(--white);
  border-left: 5px solid var(--green);
  background: var(--surface);
  padding: 1rem 1.1rem;
}

.signoff {
  color: var(--white);
  font-weight: 700;
  font-style: normal;
  margin-top: 1.5rem;
}

/* ---------- Person cards (presenters) ----------
   Example markup:

   <ul class="person-grid">
     <li class="person-card">
       <img class="person-photo" src="assets/presenters/example.jpg"
            width="400" height="400" alt="Portrait of Firstname Lastname.">
       <div class="person-body">
         <p class="person-name">Firstname Lastname</p>
         <p class="person-role">Presenter Role</p>
         <p class="person-location">City, State</p>
       </div>
     </li>
   </ul>
------------------------------------------------ */

.person-grid {
  list-style: none;
  margin: 0 0 2rem;
  padding: 0;
  display: grid;
  gap: 1.25rem;
  grid-template-columns: 1fr;
}

@media (min-width: 480px) {
  .person-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 780px) {
  .person-grid { grid-template-columns: repeat(3, 1fr); }
}

.person-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: 4px solid var(--gold);
}

.person-photo {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  background: var(--surface-2);
}

.person-body { padding: 0.9rem 1rem 1.1rem; }

.person-name {
  margin: 0 0 0.15rem;
  color: var(--gold);
  font-weight: 800;
  font-size: 1.1rem;
}

.person-role {
  margin: 0 0 0.15rem;
  color: var(--white);
  font-weight: 600;
}

.person-location {
  margin: 0;
  color: var(--muted);
  font-size: 0.95rem;
}

/* ---------- Presentation areas (program page) ---------- */

.area-grid {
  list-style: none;
  margin: 0 0 2rem;
  padding: 0;
  display: grid;
  gap: 1.25rem;
  grid-template-columns: 1fr;
}

@media (min-width: 560px) {
  .area-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 880px) {
  .area-grid { grid-template-columns: repeat(4, 1fr); }
}

.area-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: 4px solid var(--gold);
  padding: 1.1rem 1.15rem 1.25rem;
}

/* currentColor in the SVG resolves to this, so the icons follow the theme. */
.area-icon {
  color: var(--gold);
  margin-bottom: 0.6rem;
}

.area-icon svg {
  width: 48px;
  height: 48px;
  display: block;
}

.area-name {
  margin: 0 0 0.3rem;
  color: var(--gold);
  font-weight: 800;
  font-size: 1.1rem;
  line-height: 1.25;
}

.area-desc {
  margin: 0;
  color: var(--body);
  font-size: 0.98rem;
}

/* ---------- Sponsor logo wall ---------- */

/* Hidden until there are logos to show, so the section never renders empty. */
.logo-wall.is-empty { display: none; }

.logo-tier { margin-bottom: 2rem; }

.logo-tier h3 {
  border-bottom: 2px solid var(--gold);
  padding-bottom: 0.4rem;
  margin-bottom: 1rem;
}

.logo-row {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.25rem;
}

.logo-row li {
  /* Sponsor logos are supplied as artwork designed for a white backdrop, so
     this stays literally white in both themes — it is not the --white text
     role, which inverts. */
  background: #FFFFFF;
  border-radius: 4px;
  padding: 0.75rem 1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 80px;
  flex: 0 1 auto;
}

.logo-row img {
  max-height: 70px;
  width: auto;
}

/* ---------- Misc ---------- */

.schedule-note {
  color: var(--muted);
  font-style: italic;
  margin-bottom: 0.9rem;
}

.contact-email {
  font-size: 1.25rem;
  font-weight: 700;
  background: var(--surface);
  border-left: 5px solid var(--gold);
  padding: 1rem 1.1rem;
}

/* ---------- Hero (home page) ----------

   A full-bleed banner spanning the viewport. It is dimmed in the dark theme so
   the page below does not have to compete with a full-strength illustration. */

.hero {
  margin-inline: calc(50% - 50vw);
  width: 100vw;
  max-width: 100vw;
  margin-bottom: clamp(1.5rem, 4vw, 2.5rem);
  border-bottom: 3px solid var(--gold);
  /* The banner is dark artwork, so the frame around a short viewport reads as
     part of it rather than as a gap. */
  background: var(--band-bottom);
}

/* A short way back from a page reached from another, sitting above its
   heading. The arrow is part of the link text so it is never read as a
   separate control. */
.backlink {
  margin: 0 0 0.75rem;
  font-weight: 600;
}

/* ---------- Announcement video ----------

   Sits directly under the hero, framed to match it. The element carries no
   controls attribute and is made inert to pointer and keyboard input: it is
   driven entirely by scroll position (see js/main.js), so there is nothing for
   a visitor to operate. The <h2> above it is visually hidden, which keeps the
   section in the document outline without printing a redundant heading. */

.video-stage {
  margin: 0 0 clamp(1.5rem, 4vw, 2.5rem);
  padding: clamp(1rem, 3vw, 2rem) var(--space);
  /* The video's own artwork is light cream, so it needs a ground that frames
     it deliberately in both themes rather than floating on the page colour. */
  background: var(--band-bottom);
  border-bottom: 1px solid var(--border);
  display: flex;
  justify-content: center;
}

.announcement {
  display: block;
  width: 100%;
  max-width: 880px;
  height: auto;
  aspect-ratio: 16 / 9;
  border-radius: 8px;
  background: #000;
  /* No controls are rendered, so nothing here should invite interaction: the
     element ignores clicks and is skipped by the keyboard entirely. */
  pointer-events: none;
  box-shadow: 0 8px 30px rgb(0 0 0 / 0.35);
}

/* Safari renders its own overlay play button on iOS for a video it considers
   user-startable; this removes the affordance so the frame stays clean. */
.announcement::-webkit-media-controls,
.announcement::-webkit-media-controls-start-playback-button {
  display: none !important;
  -webkit-appearance: none;
}

.hero-banner img {
  width: 100%;
  height: auto;
  display: block;
  /* Dialled back so the overlaid logo reads clearly. The illustration is
     atmosphere here, not the thing being looked at. */
  opacity: 0.62;
}

/* Dimming works against the dark theme's near-black ground, but on a light
   page the same fade just washes the artwork out, so it stays at full
   strength there. */
[data-theme="light"] .hero-banner img {
  opacity: 1;
}

/* ---------- Title block ----------

   The page title and the logo sit side by side beneath the banner. The logo is
   decorative here — the <h1> next to it already names the conference, and the
   header carries the logo too — so its alt is empty. */

/* On a phone the heading needs the full column width, but the two short lines
   under it do not — stacking the logo below them left it marooned in the
   middle of the screen with a wide empty margin either side. The grid keeps
   the heading full width and tucks the logo into the space beside the subhead
   and theme line instead. Above 760px the logo moves to the right of both
   rows, which is the original desktop layout. */
.title-block {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    "title title"
    "text  logo";
  column-gap: 1.25rem;
  align-items: start;
  margin-bottom: 1.5rem;
}

.title-block > h1 { grid-area: title; }
.title-block-text { grid-area: text; min-width: 0; align-self: center; }
.hero-logo { grid-area: logo; align-self: center; }

@media (min-width: 760px) {
  .title-block {
    grid-template-areas:
      "title logo"
      "text  logo";
    column-gap: 2rem;
    align-items: center;
  }
}

.title-block-text > :last-child { margin-bottom: 0; }

.hero-logo {
  /* Sized to sit beside the text rather than to fill the column. */
  width: clamp(104px, 30vw, 150px);
  height: auto;
}

@media (min-width: 760px) {
  .hero-logo { width: clamp(150px, 26vw, 260px); }
}

/* ---------- Countdown band ---------- */

/* Full-bleed: breaks out of .wrap to span the viewport edge to edge. */
.countdown-band {
  margin: 0 calc(50% - 50vw);
  padding: clamp(1.75rem, 5vw, 2.5rem) clamp(0.5rem, 3vw, 1.5rem)
           clamp(2rem, 5vw, 2.75rem);
  width: 100vw;
  max-width: 100vw;
  background: linear-gradient(180deg, var(--band-top) 0%, var(--band-bottom) 100%);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  text-align: center;
}

.countdown-title {
  margin: 0 0 clamp(1rem, 3vw, 1.5rem);
  font-size: clamp(0.85rem, 2.6vw, 1.4rem);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--gold);
  text-wrap: balance;
}

.countdown-units {
  display: grid;
  /* Equal columns keep each number in its own lane, so a wide value such as a
     three-digit day count can never crowd its neighbour. auto-fit spreads
     however many units the markup provides. */
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  align-items: stretch;
  gap: clamp(0.5rem, 2vw, 1.5rem);
  max-width: 1200px;
  margin: 0 auto;
}

.countdown-unit {
  position: relative;
  min-width: 0;
  padding: clamp(0.7rem, 1.8vw, 1.35rem) clamp(0.15rem, 0.8vw, 0.75rem)
           clamp(0.6rem, 1.6vw, 1.1rem);
  background: var(--card-wash);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}

/* A gold hairline across the top of each tile, brightest at the centre —
   catches the light like the edge of a flip-clock card. */
.countdown-unit::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--gold), transparent);
  opacity: 0.7;
}

.countdown-value {
  display: block;
  /* Scales with the viewport so the digits genuinely fill the width. */
  font-size: clamp(1.9rem, 9vw, 7rem);
  line-height: 1.05;
  font-weight: 800;
  /* A condensed face gives big numerals a display character the system font
     lacks. Only names that genuinely ship on a platform are listed — a stack
     of hopeful guesses silently falls through to the system font and changes
     nothing. "Arial Narrow" is present on macOS and Windows; "Liberation Sans
     Narrow" is its metric-compatible counterpart on Linux. */
  font-family: "Arial Narrow", "Liberation Sans Narrow", "Nimbus Sans Narrow",
    var(--font);
  /* Condensed faces set tight; a little tracking keeps the digits readable at
     this size. */
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  /* Tabular figures keep the digits from jittering as they tick. */
  font-feature-settings: "tnum" 1;

  /* Gold gradient through the numerals rather than flat text colour. */
  background: linear-gradient(180deg,
    var(--white) 0%,
    var(--white) 42%,
    var(--gold) 78%,
    var(--gold-bright) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* The gradient replaces the glyph colour, so a shadow has to be drawn behind
     the text box rather than on the glyphs themselves. */
  filter: drop-shadow(0 2px 10px rgb(0 0 0 / 0.35));
}

/* background-clip: text is very widely supported, but if it is not the digits
   would render transparent and vanish. This restores a solid colour first and
   only applies the gradient where the browser can honour it. */
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .countdown-value {
    background: none;
    color: var(--white);
  }
}

/* Each tick swaps the number's text; this plays as it lands, so the digits
   read as flipping over rather than silently changing. The JS adds the class
   and removes it on animationend. */
@keyframes countdown-flip {
  0%   { transform: translateY(-42%) rotateX(58deg); opacity: 0; }
  55%  { transform: translateY(4%)   rotateX(-9deg); opacity: 1; }
  100% { transform: translateY(0)    rotateX(0);     opacity: 1; }
}

.countdown-value.is-ticking {
  animation: countdown-flip 420ms cubic-bezier(0.2, 0.9, 0.3, 1.1);
  transform-origin: 50% 0;
}

.countdown-label {
  display: block;
  margin-top: 0.5rem;
  font-size: clamp(0.62rem, 1.7vw, 1rem);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
  color: var(--gold);
}

.countdown-date {
  margin: 1.75rem 0 0;
  color: var(--white);
  /* The band has room beneath the tiles, and this line is the actual date the
     countdown is counting to — worth reading at a glance, not a footnote. */
  font-size: clamp(1.1rem, 3vw, 1.75rem);
  font-weight: 700;
  text-wrap: balance;
}

.countdown-here {
  /* Breaks out of the four-column grid so the message is one centred line
     rather than inheriting a column's narrow measure. */
  grid-column: 1 / -1;
  margin: 0;
  font-size: clamp(1.5rem, 6vw, 4rem);
  font-weight: 800;
  color: var(--gold);
  text-align: center;
  text-wrap: balance;
}

/* Once the date arrives the band is no longer a countdown: drop the card
   grid so the message is not laid out in columns. */
.countdown-band.is-here .countdown-units {
  display: block;
}

.countdown-band.is-here .countdown-title {
  /* The heading text is swapped in JS; just give it a little more room. */
  margin-bottom: clamp(1.25rem, 3vw, 1.75rem);
}

/* ---------- Map link ---------- */

.map-link {
  display: inline-block;
  margin-top: 0.4rem;
  font-weight: 700;
}

/* ---------- Register date ---------- */

.event-date {
  color: var(--gold);
  font-size: 1.2rem;
  font-weight: 800;
  margin-bottom: 1.4rem;
}

/* ---------- Footer ---------- */

.site-footer {
  border-top: 3px solid var(--gold);
  background: var(--surface);
  padding: 2rem 0;
  margin-top: 2rem;
}

.footer-motto {
  color: var(--gold);
  font-weight: 800;
  text-align: center;
  margin: 0 0 0.75rem;
  font-size: 1.05rem;
}

.footer-contact {
  text-align: center;
  color: var(--white);
  margin: 0;
}

/* ---------- Tab bar (phones) ----------

   Below 721px the site navigates from a fixed bar at the bottom of the screen,
   where a thumb already rests, instead of a menu button at the top. The bar is
   laid out here and only switched on inside the mobile block below, so nothing
   about it can leak into the desktop layout. */

.tabbar { display: none; }

.tabbar-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
}

/* Five equal columns. `min-width: 0` lets a long label shrink rather than
   push the bar wider than the screen. */
.tabbar-list > li {
  flex: 1 1 0;
  min-width: 0;
  position: relative;
}

.tabbar-link {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.2rem;
  width: 100%;
  min-height: 3.25rem;
  padding: 0.45rem 0.15rem 0.4rem;
  background: transparent;
  border: 0;
  border-radius: 10px;
  font: inherit;
  font-size: 0.7rem;
  font-weight: 600;
  line-height: 1.1;
  color: var(--muted);
  text-decoration: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

@media (hover: hover) {
  .tabbar-link:hover { color: var(--gold-bright); }
}

.tabbar-link:active { background: var(--surface-2); }

.tabbar-icon {
  width: 1.45rem;
  height: 1.45rem;
  display: block;
}

.tabbar-label {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The current tab is named by colour AND by a short bar above the icon, so it
   does not rely on colour alone. */
.tabbar-link[aria-current="page"],
.tabbar-link.is-current,
.tabbar-more[aria-expanded="true"] {
  color: var(--gold);
}

.tabbar-link[aria-current="page"]::before,
.tabbar-link.is-current::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 1.75rem;
  height: 3px;
  border-radius: 0 0 3px 3px;
  background: var(--gold);
}

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

/* The overflow sheet opens upward from the More tab, pinned to the right edge
   of the screen above the bar. */
.tabbar-sheet {
  position: absolute;
  right: var(--space);
  bottom: 100%;
  margin-bottom: 0.5rem;
  min-width: 11rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
  overflow: hidden;
}

.tabbar-sheet[hidden] { display: none; }

.tabbar-sheet ul {
  list-style: none;
  margin: 0;
  padding: 0.3rem;
}

.tabbar-sheet a {
  display: block;
  padding: 0.75rem 0.9rem;
  border-radius: 8px;
  color: var(--white);
  text-decoration: none;
  font-weight: 600;
}

@media (hover: hover) {
  .tabbar-sheet a:hover { background: var(--surface-2); color: var(--gold-bright); }
}

.tabbar-sheet a:active { background: var(--surface-2); }

.tabbar-sheet a[aria-current="page"] { color: var(--gold); }

/* ---------- Mobile ---------- */

@media (max-width: 720px) {
  /* The horizontal nav under the header is replaced wholesale by the tab bar,
     rather than being hidden behind a button. */
  .site-nav { display: none; }

  .tabbar {
    display: block;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 50;
    background: var(--surface);
    border-top: 1px solid var(--border);
    box-shadow: 0 -6px 18px rgba(0, 0, 0, 0.22);
    /* Keeps the tabs clear of the iPhone home indicator. */
    padding: 0 0.25rem env(safe-area-inset-bottom);
  }

  /* The bar floats over the page, so the last of the footer would sit under it
     without room reserved here. */
  body { padding-bottom: calc(4rem + env(safe-area-inset-bottom)); }

  /* The header stays in reach while scrolling, which is what the bar at the
     bottom implies: navigation is always one tap away at either edge. */
  .site-header {
    position: sticky;
    top: 0;
    z-index: 40;
    border-bottom-width: 2px;
  }

  /* One tidy row: logo, wordmark, theme toggle. Nothing wraps to a second
     line, which is what left the Menu button stranded under the logo before. */
  .header-inner {
    flex-wrap: nowrap;
    gap: 0.7rem;
    padding-top: 0.6rem;
    padding-bottom: 0.6rem;
  }

  .site-logo { width: 62px; }

  /* The last section's own bottom margin, main's bottom padding and the
     footer's top margin stacked up to roughly 120px of empty space between
     the flyer's Download button and the footer rule. Two of the three shrink
     here; the section keeps its rhythm with the sections above it. */
  main { padding-bottom: 1rem; }

  /* The last section has no sibling below it to be separated from, so most of
     its bottom margin is doing nothing but pushing the footer away. */
  main > .wrap:last-child > section:last-child { margin-bottom: 1rem; }

  .site-footer {
    margin-top: 1rem;
    padding: 1.75rem 0;
  }

  .brand-text { flex: 1 1 auto; }

  .site-name { font-size: 1.2rem; }

  .site-tagline {
    font-size: 0.78rem;
    line-height: 1.3;
    margin-top: 0.1rem;
  }

}

@media (max-width: 400px) {
  .header-inner { gap: 0.55rem; }

  .site-logo { width: 54px; }

  .site-name { font-size: 1.1rem; }

  /* Below roughly 380px the five labels would start to clip, so they shrink a
     touch before they ever ellipsise. */
  .tabbar-link { font-size: 0.66rem; }

  .theme-toggle {
    width: 2.5rem;
    height: 2.5rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
