/* ==========================================================================
   KSKQ Community Radio — single page
   Palette and forms are taken from the painted radio in
   KSKQ--design--for-layers--export.png; copy is from kskq-site-copy.pdf.
   ========================================================================== */

:root {
  --ink:        #2c2117;
  --ink-soft:   #5d4b39;
  --ink-faint:  #8a7660;
  --cream:      #f7efe1;
  --cream-2:    #efe3cd;
  --paper:      #fffaf1;
  --orange:     #ef8c1c;   /* the KSKQ letterforms */
  --orange-dk:  #cf6f08;
  --sky:        #7cc3e5;   /* the "Community Radio" strip */
  --teal:       #1d5464;
  --tan:        #c9a77c;   /* the radio cabinet */
  --rule:       rgba(92,74,56,.18);
  --shadow:     0 1px 2px rgba(44,33,23,.06), 0 8px 24px -12px rgba(44,33,23,.28);

  /* Geometry of the artwork: every overlay below is a percentage of these. */
  --art-w: 600;
  --art-h: 394;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font: 400 17px/1.65 Roboto, "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: "Roboto Slab", Georgia, serif;
  line-height: 1.15;
  margin: 0 0 .5em;
  letter-spacing: -.01em;
}
h2 { font-size: clamp(1.6rem, 3.2vw, 2.3rem); }
h3 { font-size: 1.15rem; }
p  { margin: 0 0 1em; }

a { color: var(--teal); text-decoration-color: rgba(29,84,100,.35); text-underline-offset: 3px; }
a:hover { color: var(--orange-dk); }

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

.wrap { width: min(1120px, 100% - 3rem); margin-inline: auto; }
.center { text-align: center; }
.muted  { color: var(--ink-soft); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink); color: #fff; padding: .7rem 1.1rem;
}
.skip:focus { left: 0; }

:focus-visible { outline: 3px solid var(--orange); outline-offset: 3px; border-radius: 4px; }

/* ============================ buttons ============================ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  font: 600 .95rem/1 Roboto, sans-serif; letter-spacing: .02em;
  padding: .8rem 1.25rem; border-radius: 999px; border: 1.5px solid transparent;
  text-decoration: none; cursor: pointer; transition: transform .12s, background .18s, color .18s;
}
.btn:active { transform: translateY(1px); }
.btn-donate { background: var(--orange); color: #fff; box-shadow: var(--shadow); }
.btn-donate:hover { background: var(--orange-dk); color: #fff; }
.btn-solid { background: var(--teal); color: #fff; }
.btn-solid:hover { background: #16414e; color: #fff; }
.btn-ghost { border-color: var(--rule); color: var(--ink); background: transparent; }
.btn-ghost:hover { border-color: var(--ink-soft); color: var(--ink); background: rgba(255,255,255,.6); }
.btn-block { display: flex; width: 100%; }

/* ============================ header ============================ */
.site-header {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: 1.5rem;
  padding: .7rem clamp(1rem, 4vw, 2.5rem);
  background: rgba(247,239,225,.88);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--rule);
}
/* flex:none — without it the header player squeezes the logo out of shape */
.brand { flex: none; }
/* Kept at the original 38px box for layout — a flex row's height is driven
   by items' margin boxes, and a negative margin-block here turned out not
   to shrink that the way it does in normal block flow, so the toolbar just
   grew by the same amount the logo did. transform: scale() never
   participates in layout at all, so this is the version that actually
   leaves the toolbar's height alone. */
.brand img { height: 38px; width: auto; transform: scale(1.16); transform-origin: 0% 50%; }
/* Seven items now — the gap gives way first so the bar keeps the header
   player and Donate on one line down to the 860px hamburger breakpoint. */
.site-nav { display: flex; gap: clamp(.8rem, 1.5vw, 1.4rem); margin-left: auto; }
.site-nav a {
  font: 500 .93rem/1 Roboto, sans-serif; color: var(--ink-soft);
  text-decoration: none; padding: .4rem 0; border-bottom: 2px solid transparent;
}
.site-nav a:hover { color: var(--ink); border-bottom-color: var(--orange); }
/* the menu choice that leads to whatever you have scrolled into */
.site-nav a[aria-current] { color: var(--ink); border-bottom-color: var(--orange); }
/* A bigger button wasn't really on the table without reflowing the whole
   bar, but a bigger, all-caps label reads as a bigger button and grows the
   pill itself too, since its padding is relative and there's nothing fixing
   its width. */
.site-header .btn-donate {
  padding: .6rem 1.1rem;
  font-size: 1.05rem; text-transform: uppercase; letter-spacing: .04em;
}

/* --- compact player in the header --- */
.hdr-player {
  display: flex; align-items: center; gap: .6rem; flex: none;
  max-width: 0; opacity: 0; visibility: hidden; overflow: hidden;
  transform: translateX(-6px);
  transition: max-width .32s cubic-bezier(.2,.8,.3,1), opacity .22s ease,
              transform .32s ease, visibility .32s;
}
.site-header.has-player .hdr-player {
  max-width: 15rem; opacity: 1; visibility: visible; transform: none;
}
.hdr-play {
  width: 34px; height: 34px; flex: none; border: 0; border-radius: 50%;
  background: var(--orange); color: #fff; cursor: pointer;
  display: grid; place-items: center; -webkit-tap-highlight-color: transparent;
  transition: background .18s;
}
.hdr-play:hover { background: var(--orange-dk); }
.hdr-play .ico {
  width: 0; height: 0; margin-left: 2px; border-style: solid;
  border-width: 5.5px 0 5.5px 9px;
  border-color: transparent transparent transparent currentColor;
}
.hdr-play.is-playing .ico {
  width: 9px; height: 11px; border: 0; margin-left: 0;
  background: linear-gradient(to right, currentColor 0 3px, transparent 3px 6px, currentColor 6px 9px);
}

/* level meter — same analyser as the bars behind the logo */
.hdr-meter {
  display: flex; align-items: flex-end; gap: 2px;
  height: 20px; width: 46px; flex: none;
}
.hdr-meter i {
  flex: 1; height: 8%; border-radius: 1px;
  background: linear-gradient(to top, var(--orange-dk), #f6b45f 70%, #ffd79a);
  opacity: .35; transition: height .08s linear, opacity .3s ease;
}
.site-header.is-live .hdr-meter i { opacity: 1; }

.hdr-label {
  font: 700 .72rem/1 "Courier Prime", monospace; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-soft); white-space: nowrap;
  text-decoration: none; border-bottom: 1px dotted rgba(90,80,66,.45);
  padding-bottom: 2px;
}
.hdr-label:hover, .hdr-label:focus-visible {
  color: var(--ink); border-bottom-color: var(--orange);
}
/* Hidden while the full nav row is competing for the bar. Once the links fold
   into the hamburger there is room again, and the status word is also the link
   back to the radio, so it comes back — until the bar runs out of room for
   real, at which point Donate and the hamburger outrank it. */
@media (min-width: 861px) and (max-width: 1040px) { .hdr-label { display: none; } }
/* Below this the label starts shouldering the hamburger off the bar. */
@media (max-width: 479px) { .hdr-label { display: none; } }

/* --- section cue: names the menu choice you have scrolled into --- */
.section-cue {
  position: fixed; right: clamp(1rem, 4vw, 2.5rem); top: 5rem; z-index: 30;
  display: flex; flex-direction: row-reverse; align-items: center; gap: .45rem;
  padding: .34rem .5rem .34rem .6rem;
  background: rgba(255,250,241,.85); backdrop-filter: blur(8px);
  border: 1px solid var(--rule); border-right: 3px solid var(--orange);
  border-radius: 3px; box-shadow: 0 6px 14px -12px rgba(44,33,23,.9);
  font: 700 .68rem/1 "Courier Prime", monospace; letter-spacing: .18em;
  text-transform: uppercase; color: var(--ink); white-space: nowrap;
  opacity: 0; transform: translateX(8px); pointer-events: none;
  transition: opacity .28s ease, transform .28s ease;
}
.section-cue.is-on { opacity: 1; transform: none; }
.cue-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--orange); }
@media (prefers-reduced-motion: reduce) {
  .section-cue { transform: none; transition: opacity .28s ease; }
}
@media (max-width: 560px) {
  .section-cue { font-size: .58rem; padding: .28rem .4rem .28rem .45rem; letter-spacing: .14em; }
}

/* --- hamburger --- */
.nav-toggle {
  display: none; width: 44px; height: 44px; flex: none; margin-left: .25rem;
  border: 1px solid var(--rule); border-radius: 10px; background: transparent;
  cursor: pointer; place-items: center; -webkit-tap-highlight-color: transparent;
}
.nav-toggle:hover { border-color: var(--ink-soft); }
.nav-toggle .bars { position: relative; display: block; width: 20px; height: 2px; }
.nav-toggle .bars,
.nav-toggle .bars::before,
.nav-toggle .bars::after {
  background: var(--ink); border-radius: 2px;
  transition: transform .22s ease, opacity .16s ease, background .16s ease;
}
.nav-toggle .bars::before,
.nav-toggle .bars::after {
  content: ""; position: absolute; left: 0; width: 100%; height: 2px;
}
.nav-toggle .bars::before { top: -6px; }
.nav-toggle .bars::after  { top:  6px; }
.site-header.nav-open .nav-toggle .bars { background: transparent; }
.site-header.nav-open .nav-toggle .bars::before { top: 0; transform: rotate(45deg); }
.site-header.nav-open .nav-toggle .bars::after  { top: 0; transform: rotate(-45deg); }

@media (max-width: 860px) {
  .nav-toggle { display: grid; }
  .site-header { gap: .6rem; }
  .site-header .btn-donate { margin-left: auto; }

  /* The nav becomes a panel under the bar. It stays in the DOM and keeps its
     tab order; visibility (not display) is toggled so it can animate and so
     nothing inside is focusable while closed. */
  .site-nav {
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; gap: 0;
    padding: .35rem clamp(1rem, 4vw, 2.5rem) 1rem;
    background: var(--paper);
    border-bottom: 1px solid var(--rule);
    box-shadow: 0 14px 26px -18px rgba(44,33,23,.5);
    opacity: 0; visibility: hidden; transform: translateY(-8px);
  }
  /* The fade is armed only once the menu has been used. Without that, dragging
     the window past this breakpoint hands the panel a transition and an
     opacity of 1 inherited from the desktop bar, so it fades out on screen —
     a flash of a menu nobody opened. */
  .site-header.nav-anim .site-nav {
    transition: opacity .2s ease, transform .2s ease, visibility .2s;
  }
  .site-header.nav-open .site-nav {
    opacity: 1; visibility: visible; transform: none;
  }
  .site-nav a {
    padding: .78rem 0; font-size: 1.02rem; color: var(--ink);
    border-bottom: 1px solid var(--rule);
  }
  .site-nav a:last-child { border-bottom: 0; }
  .site-nav a:hover { border-bottom-color: var(--rule); color: var(--orange-dk); }
}

/* Below this the bar cannot hold logo + play + meter + Donate + hamburger.
   The meter is the expendable one; the play control is not. */
@media (max-width: 560px) { .hdr-meter { display: none; } }

@media (max-width: 420px) {
  .brand img { height: 30px; transform: scale(1.13); }
  .site-header .btn-donate { padding: .55rem .85rem; font-size: .85rem; text-transform: uppercase; letter-spacing: .03em; }
}

/* 320 px handsets: logo + play + Donate + hamburger only just fit. */
@media (max-width: 380px) {
  .site-header { padding-left: .75rem; padding-right: .75rem; gap: .45rem; }
  .brand img { height: 26px; transform: scale(1.15); }
}

/* ============================ hero ============================ */
.hero {
  position: relative;
  /* Top padding trimmed another 40% (was clamp(1.5rem, 3.4vw, 2.6rem)), to put
     more of the player above the fold. Every value scaled by the same .6 so the
     breakpoint where the vw term takes over does not move. Bottom is unchanged. */
  padding: clamp(.9rem, 2.04vw, 1.56rem) 1.5rem clamp(3rem, 7vw, 5rem);
  text-align: center;
  background:
    radial-gradient(120% 90% at 50% 0%, var(--paper) 0%, var(--cream) 58%, var(--cream-2) 100%);
  overflow: hidden;
}
.hero-inner { width: min(760px, 100%); margin-inline: auto; }

/* ---------------- pledge-drive ribbon ---------------- */
/* Classic corner-ribbon, but position:fixed so it stays put while the page
   scrolls instead of leaving with .hero. A fixed descendant ignores an
   ancestor's overflow:hidden unless that ancestor also has a transform (or
   similar) creating a containing block, so .hero's own clipping — which is
   what cropped this cleanly before — no longer applies. .pledge-ribbon-clip
   is a dedicated fixed, overflow:hidden box just for this. It starts at the
   viewport's own top-right corner, sized generously so the rotated band
   never reaches its edges; the band's own top/right offsets are what
   actually clear the sticky header (~61-67px tall across breakpoints). */
/* Left corner now, and drawn ON TOP of the header (z-index above its 40)
   rather than tucked behind it — draping over the header the way a sale
   ribbon drapes over a product photo's corner, not emerging from under it. */
.pledge-ribbon-clip {
  position: fixed; top: 0; left: 0; width: 320px; height: 320px;
  overflow: hidden; z-index: 45; pointer-events: none;
}
/* [hidden] must win over the block below: an author display:block would
   otherwise beat the UA stylesheet's [hidden]{display:none} and the ribbon
   would show up even without ?loadoverlay=1. */
.pledge-ribbon[hidden] { display: none; }
.pledge-ribbon {
  position: absolute; top: 30px; left: -76px; width: 280px;
  transform: rotate(-45deg); pointer-events: auto;
  display: block; text-align: center; text-decoration: none;
  background: linear-gradient(180deg, var(--orange), var(--orange-dk));
  color: #fff9ee; padding: .6rem 0;
  font: 800 .95rem/1.1 "Roboto Slab", serif; letter-spacing: .05em;
  text-transform: uppercase;
  box-shadow: 0 3px 10px rgba(44,33,23,.35);
}
.pledge-ribbon:hover { filter: brightness(1.06); }
/* Small tucked-corner triangles at both visible ends, so the flat strip
   reads as a folded ribbon rather than a rectangle laid on top. */
.pledge-ribbon::before, .pledge-ribbon::after {
  content: ""; position: absolute; top: 100%; width: 0; height: 0;
  border-style: solid;
}
.pledge-ribbon::before {
  left: 0; border-width: 5px 5px 0 0;
  border-color: transparent var(--orange-dk) transparent transparent;
}
.pledge-ribbon::after {
  right: 0; border-width: 5px 0 0 5px;
  border-color: transparent transparent transparent var(--orange-dk);
}
@media (max-width: 480px) {
  /* Shrinking .pledge-ribbon-clip too seemed tidy but isn't safe: with the
     band's rotated footprint this close to the wrap's own edges, the wrap's
     overflow:hidden started cutting into the visible text. The wrap costs
     nothing extra at full size — pointer-events:none, no background — so it
     stays put and only the band itself scales down. */
  .pledge-ribbon { top: 26px; left: -84px; width: 230px; font-size: .8rem; }
}

.hero h1 {
  font-size: clamp(2.1rem, 6vw, 3.5rem); font-weight: 800;
  margin-bottom: .6rem;
}
.lede {
  font-size: clamp(1rem, 2.2vw, 1.15rem); color: var(--ink-soft);
  max-width: 56ch; margin-inline: auto;
}

/* ---------------- the radio ---------------- */
/* Top margin halved (was clamp(1.5rem, 4vw, 2.5rem)). It collapses with the
   lede's own bottom margin, so this value is the gap. */
/* zero-height scroll target above the radio; the offset clears the sticky bar */
.tuner-anchor { display: block; height: 0; scroll-margin-top: 5.5rem; }
.radio-stage { margin: clamp(.75rem, 2vw, 1.25rem) auto .5rem; width: min(600px, 100%); }

.radio {
  position: relative;
  aspect-ratio: var(--art-w) / var(--art-h);
  isolation: isolate;
}
.radio-art { width: 100%; height: 100%; user-select: none; -webkit-user-drag: none; }

/* --- dial screen glow (x124-357, y108-238 of 600x394) --- */
.screen-glow {
  position: absolute; left: 20.67%; top: 27.41%; width: 38.83%; height: 32.99%;
  border-radius: 14% / 20%;
  background: radial-gradient(70% 70% at 50% 45%, rgba(255,196,92,.95), rgba(255,150,30,.35) 55%, transparent 75%);
  mix-blend-mode: screen; opacity: 0; pointer-events: none;
  transition: opacity .7s ease;
}
.radio[data-state="playing"] .screen-glow { opacity: .55; animation: flicker 5s ease-in-out infinite; }
.radio[data-state="loading"] .screen-glow { opacity: .3; animation: pulse-glow 1.1s ease-in-out infinite; }

@keyframes flicker { 0%,100%{opacity:.5} 45%{opacity:.62} 70%{opacity:.46} }
@keyframes pulse-glow { 0%,100%{opacity:.16} 50%{opacity:.42} }

/* --- muted: grey the dial screen ---
   Screen interior measured off the artwork at x 122-366, y 105-233; the
   luminance edge is where the dark screen meets the tan bezel. inset() is
   top/right/bottom/left as a share of the full 600x394 image. */
.screen-mono {
  position: absolute; inset: 0; width: 100%; height: 100%;
  filter: grayscale(1) brightness(.74) contrast(.92);
  clip-path: inset(26.65% 39% 40.61% 20.33% round 4% / 6.1%);
  opacity: 0; pointer-events: none;
  transition: opacity .28s ease;
}
.radio.is-muted .screen-mono { opacity: 1; }

/* --- the right speaker cone, live (cone centre 482,187 r56) ---
   A copy of the artwork cropped to the cone by a circular wrapper, so it can
   scale independently of the cabinet. Percentages: the wrapper is the 112px
   cone box; the image inside is 600/112 of that, shifted back into place.
   --thump is written by the analyser and is 1 when nothing is playing. */
.knob-live {
  position: absolute; left: 71%; top: 33.25%; width: 18.67%; height: 28.43%;
  border-radius: 50%; overflow: hidden; pointer-events: none;
  opacity: 0; transition: opacity .45s ease;
  transform: scale(var(--thump, 1));
  will-change: transform;
}
.radio[data-state="playing"] .knob-live { opacity: 1; }
.radio.is-muted .knob-live { opacity: .35; transform: none; }
.knob-live img {
  position: absolute; width: 535.71%; max-width: none; height: auto;
  left: -380.36%; top: -116.96%;
  filter: brightness(1.16) saturate(1.45);
}
.knob-glow {
  position: absolute; inset: 0; border-radius: 50%;
  background: radial-gradient(circle at 50% 44%,
              rgba(255,201,116,.6), rgba(255,145,25,.22) 55%, transparent 76%);
  mix-blend-mode: soft-light;
}

/* --- spectrum bars over the painted grille (x130-350, y113-202) ---
   Sits above the KSKQ letterforms, so it is kept faint and screen-blended:
   the effect should read as the grille lighting up, not as a chart. */
.screen-bars {
  position: absolute; left: 21.67%; top: 28.68%; width: 36.67%; height: 22.59%;
  display: flex; align-items: flex-end; gap: .9%;
  mix-blend-mode: screen; opacity: 0; pointer-events: none;
  transition: opacity .5s ease;
}
.radio[data-state="playing"] .screen-bars { opacity: .34; }
.screen-bars span {
  flex: 1; height: 12%; border-radius: 1px 1px 0 0;
  background: linear-gradient(to top, rgba(255,120,0,.15), rgba(255,214,140,.95));
  transform-origin: bottom;
  transition: height .09s linear;
}

/* --- antenna broadcast rings (globe centre 178,25 r22) --- */
.antenna {
  position: absolute; left: 26%; top: .76%; width: 7.33%; height: 11.17%;
  pointer-events: none;
}
.antenna i {
  position: absolute; inset: 0; border-radius: 50%;
  border: 2px solid rgba(239,140,28,.7); opacity: 0;
}
.radio[data-state="playing"] .antenna i { animation: ripple 2.6s ease-out infinite; }
.radio[data-state="playing"] .antenna i:nth-child(2) { animation-delay: .85s; }
.radio[data-state="playing"] .antenna i:nth-child(3) { animation-delay: 1.7s; }
@keyframes ripple {
  0%   { transform: scale(.7);  opacity: .85; }
  100% { transform: scale(3.4); opacity: 0; }
}

/* --- sponsor ticker beside the globe (globe centre 178,25 of 600x394) ---
   Floats on its own row, one below now-tag's (top: 6.35%), so both can be
   on screen together — the current show and the sponsor credit never have
   to fight for the same space. Starts just clear of the globe's right edge
   (antenna ends at 26%+7.33%=33.33%) and stops at width 52%, well short of
   the cabinet's right shoulder. */
.hero-ticker {
  position: absolute; left: 34%; width: 52%; top: 15%;
  transform: translateY(-50%); box-sizing: border-box; padding-left: 5px;
  display: flex; align-items: center; gap: .4rem; min-width: 0;
  opacity: 1; transition: opacity .35s ease;
  text-decoration: none;
}
.hero-ticker:hover .hero-ticker-label,
.hero-ticker:hover .hero-ticker-track { color: var(--orange-dk); }
.hero-ticker-label {
  flex: 0 0 auto;
  font: 700 clamp(.5rem, 1.75vw, .74rem)/1 "Courier Prime", monospace;
  letter-spacing: .05em; text-transform: uppercase; color: var(--ink-faint);
}
/* The mask alone clips: overflow lives here, not on a shared ancestor with
   the label, so the track's translateX can never slide left past its own
   box and under the label — it can only slide within the space it owns. */
/* display:flex here too, not just on .hero-ticker: without it the track
   (an inline-flex child of a plain block box) sits by inline baseline
   rules instead of the label's flex-centered ones, landing a few px off. */
.hero-ticker-mask {
  flex: 1 1 auto; min-width: 0; overflow: hidden;
  display: flex; align-items: center;
}
.hero-ticker-track {
  display: inline-flex; gap: .4rem; align-items: center; white-space: nowrap;
  font: 700 clamp(.5rem, 1.75vw, .74rem)/1 "Courier Prime", monospace;
  letter-spacing: .03em; text-transform: uppercase; color: var(--ink-soft);
  animation: ticker-scroll 34s linear infinite;
}
.hero-ticker-dot { color: var(--orange-dk); }
@keyframes ticker-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .hero-ticker-track { animation: none; }
}
@media (max-width: 360px) { .hero-ticker { display: none; } }

/* --- "on air now" beside the globe (globe centre 178,25 of 600x394) ---
   Sits on the globe's centre line and runs out to the edge of the stage,
   across the blank paper above the cabinet's right shoulder. Typed rather than
   set, to match the FM stamps painted into the artwork. Long show names are
   clipped rather than wrapped: a second line would drop onto the cabinet. */
.now-tag {
  position: absolute; left: 35%; right: 2%; top: 6.35%;
  transform: translateY(-50%); margin: 0;
  font: 400 clamp(.5rem, 1.9vw, .78rem)/1.2 "Courier Prime", monospace;
  letter-spacing: .03em; color: var(--ink-soft);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  opacity: 0; transition: opacity .45s ease; pointer-events: none;
}
.now-tag b { font-weight: 700; color: var(--ink); }
/* On air only — and it stays up while muted, since the station has not
   stopped playing the show just because this page stopped listening to it. */
.radio[data-state="playing"] .now-tag { opacity: 1; }
/* Under ~360px the stage is too narrow to hold a show name beside the globe
   without it becoming three characters and an ellipsis. */
@media (max-width: 360px) { .now-tag { display: none; } }

/* --- muted overrides ---
   Same specificity as the data-state rules above, so these must stay after
   them in source order to win. The set is silent but still on air, so the
   glow is dimmed rather than killed. */
.radio.is-muted .screen-glow { opacity: .1; animation: none; }
.radio.is-muted .screen-bars { opacity: 0; }
.radio.is-muted .antenna i   { animation: none; opacity: 0; }

/* --- big right knob = play / pause (centre 482,185 r62) --- */
.knob-power {
  position: absolute; left: 70%; top: 31.22%; width: 20.67%; height: 31.47%;
  border: 0; padding: 0; border-radius: 50%; background: transparent;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.knob-power .knob-ring {
  position: absolute; inset: -6%; border-radius: 50%;
  border: 2.5px solid transparent;
  transition: border-color .2s, box-shadow .25s, transform .25s;
}
.knob-power:hover .knob-ring {
  border-color: rgba(239,140,28,.75);
  box-shadow: 0 0 22px rgba(239,140,28,.45);
}
.knob-power:active { transform: scale(.97); }
/* Curved lettering inside the speaker rim, only while the stream is off. Its
   type is set on the SVG itself; all this does is place it and fade it. */
.knob-legend {
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none; overflow: visible;
  transition: opacity .35s ease;
}
.radio[data-state="playing"] .knob-legend,
.radio[data-state="loading"] .knob-legend { opacity: 0; }
/* Engaged: a solid lit ring that also breathes with --thump, so the play
   state reads at a glance rather than as a faint outline. */
.radio[data-state="playing"] .knob-power .knob-ring {
  border-color: rgba(239,140,28,1); border-width: 3px;
  box-shadow: 0 0 calc(18px + var(--thump-glow, 0) * 26px) rgba(239,140,28,.75),
              inset 0 0 20px rgba(255,190,90,.3);
  transform: scale(var(--thump, 1));
}
.radio.is-muted .knob-power .knob-ring {
  border-color: rgba(150,140,128,.7); box-shadow: none; transform: none;
}
.radio[data-state="loading"] .knob-power .knob-ring {
  border-color: rgba(239,140,28,.55);
  border-top-color: transparent; border-right-color: transparent;
  animation: spin 1s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* --- small centre knob = volume (centre 260,272 r26) --- */
.knob-volume {
  position: absolute; left: 39%; top: 62.44%; width: 8.67%; height: 13.2%;
  border-radius: 50%; cursor: ns-resize; touch-action: none;
}
.knob-volume .vol-ring {
  position: absolute; inset: -34%; border-radius: 50%;
  background: conic-gradient(from -135deg,
              var(--orange) calc(var(--vol, .8) * 270deg),
              rgba(120,100,80,.22) 0 270deg,
              transparent 0);
  -webkit-mask: radial-gradient(circle, transparent 58%, #000 60%);
          mask: radial-gradient(circle, transparent 58%, #000 60%);
  opacity: 0; transition: opacity .2s; pointer-events: none;
}
.knob-volume:hover .vol-ring,
.knob-volume:focus-within .vol-ring,
.knob-volume.is-active .vol-ring { opacity: 1; }
.knob-volume input {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; cursor: ns-resize; margin: 0;
}

/* --- left speaker = mute (oval centre 60,193 · rx35 ry55) --- */
.speaker-mute {
  position: absolute; left: 4.17%; top: 35.03%; width: 11.67%; height: 27.92%;
  border: 0; padding: 0; background: transparent; border-radius: 50%;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.speaker-mute::after {
  content: ""; position: absolute; inset: 12%; border-radius: 50%;
  box-shadow: 0 0 0 0 rgba(239,140,28,0); transition: box-shadow .3s;
}
.speaker-mute:hover::after { box-shadow: 0 0 0 2px rgba(239,140,28,.6); }
.radio[data-state="playing"] .speaker-mute::after { animation: thump 1.9s ease-in-out infinite; }
@keyframes thump {
  0%,100% { box-shadow: 0 0 18px 0 rgba(239,140,28,0); }
  50%     { box-shadow: 0 0 26px 4px rgba(239,140,28,.22); }
}
.radio.is-muted .speaker-mute::after {
  box-shadow: 0 0 0 3px rgba(198,52,34,.95); animation: none;
}
/* a slash across the speaker — the universal "muted" mark */
.speaker-mute::before {
  content: ""; position: absolute; left: 50%; top: 50%; z-index: 2;
  width: 92%; height: 4px; border-radius: 3px;
  background: rgba(198,52,34,.95);
  box-shadow: 0 0 0 1.5px rgba(255,248,238,.65);
  transform: translate(-50%, -50%) rotate(-45deg) scaleX(0);
  transform-origin: center; transition: transform .25s ease;
}
.radio.is-muted .speaker-mute::before {
  transform: translate(-50%, -50%) rotate(-45deg) scaleX(1);
}

/* ---------------- readout ---------------- */
.readout {
  font: 700 .82rem/1 "Courier Prime", monospace; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-soft);
  display: inline-flex; align-items: center; gap: .6rem;
  padding: .55rem 1rem; border: 1px solid var(--rule); border-radius: 999px;
  background: rgba(255,255,255,.55); margin: 0 0 1.4rem;
}
.lamp {
  width: 9px; height: 9px; border-radius: 50%; flex: none;
  background: #bcae99;
}
.radio-live .lamp { background: #e8442e; box-shadow: 0 0 9px rgba(232,68,46,.9); animation: blink 2s ease-in-out infinite; }
.radio-loading .lamp { background: var(--orange); animation: blink .8s ease-in-out infinite; }
.radio-error .lamp { background: #b03a2b; }
.radio-muted .lamp { background: #9a8f80; box-shadow: none; animation: none; }
.radio-muted { border-color: rgba(198,52,34,.45); color: #9c4030; }
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:.35} }

.hero-actions {
  display: flex; gap: .8rem; justify-content: center; flex-wrap: wrap;
  margin-bottom: 1.4rem;
}
.btn-listen {
  background: var(--ink); color: var(--paper); padding: .95rem 1.7rem; font-size: 1rem;
  box-shadow: var(--shadow);
}
.btn-listen:hover { background: #1c140c; color: #fff; }
.btn-listen .ico {
  width: 0; height: 0; border-style: solid;
  border-width: 7px 0 7px 12px; border-color: transparent transparent transparent currentColor;
  margin-left: 2px; transition: none;
}
/* `is-playing` goes on the button itself, so it must be a compound selector —
   a descendant selector here never matched and the pause icon never showed. */
.btn-listen.is-playing .ico {
  width: 12px; height: 14px; border: 0; margin-left: 0;
  background: linear-gradient(to right, currentColor 0 4px, transparent 4px 8px, currentColor 8px 12px);
}

/* ============================ bands ============================ */
.band { padding: clamp(3rem, 7vw, 5.5rem) 0; }
.band-tint { background: var(--cream-2); }
.band-dark { background: var(--ink); color: #efe4d3; }
.band-dark h2, .band-dark h3 { color: var(--paper); }
.band-dark a { color: #f6b45f; text-decoration-color: rgba(246,180,95,.4); }
.band-dark a:hover { color: #ffcd8a; }
/* the link colour above must not swallow the solid buttons */
.band-dark a.btn-donate { color: #fff; text-decoration: none; }
.band-dark a.btn-donate:hover { color: #fff; }
.lede-dark { max-width: 62ch; margin-inline: auto; color: #cdbda6; margin-bottom: 2.5rem; }

/* These bands open with an h2 sitting only 48–82px below their top edge, which
   is inside the sticky bar's 61–67px. A little scroll margin keeps the nav from
   parking the title half under the header. Mission and Staff lead with taller
   furniture — the card head, the clipping masthead — and clear it on their own. */
#about, #calendar, #support, #underwriting, #apps { scroll-margin-top: 2.5rem; }

.two-col {
  display: grid; grid-template-columns: 1.15fr .85fr; gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}
@media (max-width: 820px) { .two-col { grid-template-columns: 1fr; } }

/* About balances its two columns evenly: a run of institutional copy on the
   left against the recent-message card (blurb + square image) on the right,
   rather than Underwriting's lopsided 1.15/.85 text-vs-form split. */
#about .two-col { grid-template-columns: 1fr 1fr; }

.sub { max-width: 58ch; margin: -.3rem auto 2.5rem; }

/* recent message — a swappable promo card: blurb, then a square image that
   always crops to 1:1 via aspect-ratio, whatever the source image's own
   dimensions happen to be. */
.recent-message-eyebrow {
  font: 800 1.05rem/1.2 "Roboto Slab", serif; letter-spacing: .06em;
  text-transform: uppercase; text-align: center; color: var(--orange-dk);
  margin: 0 0 .8rem;
}
.recent-message-blurb { margin: 0 0 1.1rem; }
.recent-message-frame {
  display: block; aspect-ratio: 1 / 1; max-width: 500px;
  overflow: hidden; transform: rotate(-.6deg);
  border: 1px solid var(--rule); border-radius: 4px;
  box-shadow: 0 10px 20px -12px rgba(44,33,23,.4);
  transition: transform .15s ease;
}
.recent-message-frame:hover { transform: rotate(0deg); }
.recent-message-frame img {
  display: block; width: 100%; height: 100%; object-fit: cover; border-radius: 4px;
}

.recent-message-more {
  display: block; text-align: center; margin: 0 0 1.1rem;
  font: 600 .92rem/1 Roboto, sans-serif;
}
.policy-logo { height: 44px; width: auto; margin: 0 auto 1.2rem; display: block; }
.policy {
  background: var(--paper); border-left: 3px solid var(--sky);
  padding: 1.2rem 1.4rem; border-radius: 0 8px 8px 0;
}
.policy h3 { margin-bottom: .4rem; }
.policy p { font-size: .94rem; color: var(--ink-soft); margin-bottom: .7rem; }
.policy p:last-child { margin-bottom: 0; }
/* Unused at the moment — kept for whatever the sidebar next wants to stress.
   Weight and ink only: a size bump on a multi-line run leaves it ragged. */
.policy-emph { font-weight: 700; color: var(--ink); }

/* ---------------- friends of KSKQ ---------------- */
.friends {
  margin-top: 1.8rem; padding-top: 1.1rem;
  border-top: 1px solid var(--rule);
}
.friends h3 {
  font: 700 .72rem/1.3 "Courier Prime", monospace; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink-faint); margin-bottom: .8rem;
}
.friends ul {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, 1fr); gap: .7rem 1.6rem;
}
.friends li { line-height: 1.35; }
.friends a { font-weight: 500; font-size: .95rem; }
.friends span { display: block; font-size: .82rem; color: var(--ink-soft); }
@media (max-width: 560px) { .friends ul { grid-template-columns: 1fr; } }

/* ---------------- staff roster as a newspaper clipping ---------------- */
.clipping {
  display: block;
  margin: 0;
  transform: rotate(-.45deg);
  filter: drop-shadow(0 10px 18px rgba(44,33,23,.22));
}
.clip-inner {
  /* Distinctly cooler and greyer than the page cream, or the torn edge and
     the whole clipping conceit disappear into the background. */
  background: linear-gradient(168deg, #e7e1d1, #ddd6c4 60%, #e3ddcc);
  padding: clamp(1.4rem, 3vw, 2.2rem) clamp(1.2rem, 3vw, 2.4rem);
  /* Scissors-cut edge: irregular, generated once and pasted in. */
  clip-path: polygon(0.0% 0.49%, 4.0% 0.23%, 8.0% 0.98%, 12.0% 0.11%, 16.0% 0.8%, 20.0% 0.55%, 24.0% 0.09%, 28.0% 0.76%, 32.0% 0.06%, 36.0% 0.65%, 40.0% 0.1%, 44.0% 0.14%, 48.0% 0.64%, 52.0% 1.24%, 56.0% 0.19%, 60.0% 0.33%, 64.0% 0.94%, 68.0% 1.42%, 72.0% 0.87%, 76.0% 0.6%, 80.0% 1.46%, 84.0% 0.07%, 88.0% 1.29%, 92.0% 0.43%, 96.0% 0.22%, 100.0% 0.18%, 99.78% 25.0%, 99.43% 50.0%, 99.87% 75.0%, 100.0% 99.13%, 96.0% 99.04%, 92.0% 99.44%, 88.0% 99.18%, 84.0% 99.91%, 80.0% 99.91%, 76.0% 99.69%, 72.0% 98.98%, 68.0% 99.36%, 64.0% 99.53%, 60.0% 99.12%, 56.0% 99.32%, 52.0% 99.55%, 48.0% 98.81%, 44.0% 98.95%, 40.0% 99.63%, 36.0% 99.14%, 32.0% 99.21%, 28.0% 98.69%, 24.0% 98.91%, 20.0% 99.57%, 16.0% 98.53%, 12.0% 99.82%, 8.0% 99.37%, 4.0% 98.86%, 0.0% 99.77%, 0.34% 75.0%, 0.03% 50.0%, 0.47% 25.0%);
  position: relative;
  color: #23201b;
}
/* halftone tint, so it does not read as flat card stock */
.clip-inner::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: radial-gradient(rgba(60,50,38,.22) .5px, transparent .6px);
  background-size: 3px 3px; opacity: .5; mix-blend-mode: multiply;
}

.clip-kicker {
  font: 400 .68rem/1.4 "Courier Prime", monospace; letter-spacing: .18em;
  text-transform: uppercase; color: #6b6154; text-align: center;
  margin: 0 0 .35rem;
}
.clip-head {
  font-family: "Roboto Slab", Georgia, serif; font-weight: 800;
  font-size: clamp(1.5rem, 3.6vw, 2.35rem); line-height: 1.05;
  text-align: center; text-transform: uppercase; letter-spacing: -.005em;
  color: #17140f; margin: 0 0 .5rem;
}
/* the double rule under a masthead */
.clip-standfirst {
  border-top: 3px solid #17140f; border-bottom: 1px solid #17140f;
  padding: .7rem 0; margin: 0 0 1.2rem;
  font-family: "Roboto Slab", Georgia, serif; font-size: .93rem; line-height: 1.5;
  text-align: center; max-width: 62ch; margin-inline: auto; color: #3a342c;
}

.clip-cols {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 0 clamp(1.1rem, 2.6vw, 2rem);
}
/* the thin rules between newspaper columns */
.clip-col + .clip-col {
  border-left: 1px solid rgba(35,32,27,.22);
  padding-left: clamp(1.1rem, 2.6vw, 2rem);
}
.clip-col h4 {
  font: 700 .7rem/1.3 "Courier Prime", monospace; letter-spacing: .14em;
  text-transform: uppercase; color: #17140f;
  margin: 0 0 .55rem; padding-bottom: .3rem;
  border-bottom: 1px solid rgba(35,32,27,.3);
}
.clip-col h4 ~ h4 { margin-top: 1.1rem; }
.clip-col ul { list-style: none; margin: 0; padding: 0; }
.clip-col li { margin-bottom: .5rem; line-height: 1.35; }
.clip-col b {
  display: block; font-family: "Roboto Slab", Georgia, serif;
  font-weight: 600; font-size: .97rem; color: #17140f;
}
.clip-col span { font-size: .8rem; color: #57503f; }

.clip-foot {
  margin: 1.3rem 0 0; padding-top: .6rem;
  border-top: 1px solid rgba(35,32,27,.3);
  font: 400 .7rem/1.4 "Courier Prime", monospace; letter-spacing: .09em;
  text-align: center; color: #6b6154; text-transform: uppercase;
}

@media (max-width: 780px) {
  .clip-cols { grid-template-columns: 1fr; gap: 1.4rem 0; }
  .clip-col + .clip-col {
    border-left: 0; padding-left: 0;
    border-top: 1px solid rgba(35,32,27,.22); padding-top: 1.2rem;
  }
  .clipping { transform: rotate(-.25deg); }
}

/* ---------------- mission as a QSL card ---------------- */
.qsl {
  width: min(680px, 100%); margin-inline: auto; background: var(--paper);
  border: 1px solid var(--ink);
  /* inner keyline, then the card's own shadow — a postcard on the table */
  box-shadow: 0 0 0 1px var(--paper) inset, 0 0 0 4px rgba(44,33,23,.14),
              0 14px 26px -16px rgba(44,33,23,.55);
  padding: clamp(1.5rem, 4vw, 2.2rem);
  transform: rotate(-.5deg);
  display: grid; grid-template-columns: 1fr auto;
  gap: 1.2rem clamp(1.2rem, 4vw, 2.2rem);
}
.qsl-head {
  grid-column: 1 / -1; border-bottom: 2px solid var(--ink); padding-bottom: .7rem;
}
.qsl-call {
  font: 800 clamp(2rem, 7vw, 3.1rem)/1 "Roboto Slab", serif; letter-spacing: .04em;
  margin: 0; color: var(--ink);
}
.qsl-call small {
  display: inline-block; font: 700 .62rem/1 "Courier Prime", monospace;
  letter-spacing: .18em; text-transform: uppercase; color: var(--orange-dk);
  vertical-align: middle; margin-left: .8rem;
}
.qsl-sub {
  font: 400 .68rem/1.4 "Courier Prime", monospace; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-faint); margin: .45rem 0 0;
}
.qsl-body { margin: 0; }
.qsl-body h2 {
  font: 700 .68rem/1 "Courier Prime", monospace; letter-spacing: .18em;
  text-transform: uppercase; color: var(--ink-faint); margin: 0 0 .7rem;
}
.qsl-body p {
  font: 300 clamp(1.05rem, 2.4vw, 1.28rem)/1.55 "Roboto Slab", serif;
  color: var(--ink); margin: 0;
}
.qsl-side { display: grid; gap: .9rem; justify-items: center; align-content: start; }
/* The perforation is a thick dotted border in the card's own paper colour:
   the hatch shows through the gaps, the dots read as punched holes. A masked
   edge would be truer, but it tiles holes across the whole face in Safari. */
.qsl-stamp {
  width: 92px; height: 108px; display: grid; place-items: center; text-align: center;
  background: repeating-linear-gradient(135deg,
      rgba(124,195,229,.38) 0 7px, rgba(124,195,229,.14) 7px 14px), var(--cream);
  border: 6px dotted var(--paper);
  outline: 1px solid rgba(44,33,23,.3); outline-offset: -7px;
  font: 800 1.35rem/1.15 "Roboto Slab", serif; color: var(--teal);
}
/* the second frequency, stacked under the first */
.qsl-stamp i { display: block; font-style: normal; }
.qsl-stamp small { display: block; font-size: .6rem; letter-spacing: .12em; margin-top: .25rem; }
.qsl-mark {
  width: 104px; height: 104px; border-radius: 50%; display: grid; place-items: center;
  border: 2px solid rgba(207,111,8,.55); box-shadow: inset 0 0 0 5px rgba(207,111,8,.10);
  font: 700 .58rem/1.35 "Courier Prime", monospace; letter-spacing: .12em;
  text-transform: uppercase; text-align: center; color: rgba(207,111,8,.75);
  transform: rotate(-9deg);
}
@media (max-width: 620px) {
  .qsl { grid-template-columns: 1fr; transform: rotate(-.25deg); }
  .qsl-side { grid-auto-flow: column; justify-content: center; }
}

/* shows */
/* ---------------- weekly schedule panel ---------------- */
.sched {
  position: relative;           /* the void overlay measures against this */
  max-width: 820px; margin: 0 auto 2rem;
  border: 1px solid var(--rule); border-radius: 12px;
  background: var(--paper); overflow: hidden;
}
.sched-bar {
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
  padding: .7rem .8rem; border-bottom: 1px solid var(--rule);
  background: linear-gradient(var(--paper), var(--cream));
}
.sched-days { display: flex; gap: .25rem; flex-wrap: wrap; }
.sched-days button {
  font: 700 .78rem/1 "Courier Prime", monospace; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-soft);
  padding: .5rem .7rem; border: 1px solid transparent; border-radius: 8px;
  background: transparent; cursor: pointer; transition: background .15s, color .15s;
}
.sched-days button:hover { background: rgba(201,167,124,.2); color: var(--ink); }
.sched-days button[aria-selected="true"] {
  background: var(--ink); color: var(--paper);
}
.sched-days button .dot {
  display: inline-block; width: 5px; height: 5px; border-radius: 50%;
  background: var(--orange); margin-left: .35rem; vertical-align: middle;
}
.sched-now {
  margin: 0 0 0 auto; padding-right: .3rem;
  font: 400 .8rem/1.3 "Courier Prime", monospace; color: var(--ink-faint);
}
.sched-now b { color: var(--ink); font-weight: 700; }

/* No max-height: a capped, scrolling panel put a second scrollbar inside the
   page. The panel grows to its day; radio.js then pins a min-height equal to
   the tallest day so switching tabs does not shift the page. */
.sched-row {
  display: grid; grid-template-columns: 8.5rem 1fr auto; gap: .8rem;
  align-items: baseline; padding: .6rem .9rem;
  border-bottom: 1px solid rgba(92,74,56,.09);
}
.sched-row:last-child { border-bottom: 0; }
.sched-row .tm {
  font: 400 .82rem/1.4 "Courier Prime", monospace; color: var(--ink-faint);
  white-space: nowrap;
}
.sched-row .ti { font-size: .97rem; }
.sched-row .rot {
  font-size: .74rem; color: var(--ink-faint); font-style: italic; margin-left: .35rem;
}
.sched-row .cat {
  font: 600 .66rem/1 Roboto, sans-serif; letter-spacing: .07em; text-transform: uppercase;
  padding: .28rem .5rem; border-radius: 999px; white-space: nowrap;
  border: 1px solid; background: transparent;
}
.cat-syn  { color: #6b4fa8; border-color: rgba(107,79,168,.35); }
.cat-talk { color: #2f7a45; border-color: rgba(47,122,69,.35); }
.cat-dj   { color: var(--orange-dk); border-color: rgba(207,111,8,.4); }
.cat-mus  { color: #b0473a; border-color: rgba(176,71,58,.35); }

/* the show that is on the air right now */
.sched-row.is-live { background: rgba(239,140,28,.1); }
.sched-row.is-live .ti { font-weight: 700; }
.sched-row.is-live .tm { color: var(--orange-dk); }
.sched-row.is-live .tm::before {
  content: ""; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: #e8442e; margin-right: .45rem; vertical-align: middle;
  animation: blink 2s ease-in-out infinite;
}

/* The blank paper under a short day. Sits over the panel rather than in it,
   so nothing here can change the height the rows just measured out. */
.sched-void {
  position: absolute; left: 0; right: 0; pointer-events: none;
  opacity: 0; transition: opacity .5s ease;
}
.sched-void.is-awake { opacity: 1; }
.void-note {
  position: absolute; top: .9rem; left: 0; right: 0; margin: 0; text-align: center;
  font: 400 .68rem/1.4 "Courier Prime", monospace; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-faint);
}
.puppy {
  position: absolute; top: 0; left: 0; color: var(--orange);
  will-change: transform;
}
/* the poses are stacked in the one drawing; bouncing swaps which is showing */
.puppy g { display: none; }
.puppy g.on { display: inline; }

.sched-foot {
  margin: 0; padding: .7rem .9rem; border-top: 1px solid var(--rule);
  background: var(--cream); font-size: .8rem; color: var(--ink-faint);
  display: flex; flex-direction: column; align-items: flex-start; gap: .5rem;
}
.sched-key { display: flex; gap: .7rem; flex-wrap: wrap; }
.sched-note { display: block; }
.sched-key span { display: inline-flex; align-items: center; gap: .3rem; }
.sched-key i {
  width: 9px; height: 9px; border-radius: 3px; display: inline-block;
  border: 1px solid currentColor; background: currentColor; opacity: .75;
}

@media (max-width: 620px) {
  .sched-row { grid-template-columns: 1fr auto; gap: .3rem .7rem; padding: .65rem .8rem; }
  .sched-row .tm { grid-column: 1 / -1; }
  .sched-now { width: 100%; margin-left: 0; }
}

/* support */
/* Four ways to help, four columns. auto-fit would drop to three and leave the
   fourth card orphaned on its own row, so the steps are set by hand: 4, 2, 1. */
.grid-support {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.4rem;
}
@media (max-width: 1040px) { .grid-support { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px)  { .grid-support { grid-template-columns: 1fr; } }
.card {
  background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.14);
  border-radius: 12px; padding: 1.6rem;
}
.card p { font-size: .95rem; color: #cdbda6; }
.card-primary { background: rgba(239,140,28,.1); border-color: rgba(239,140,28,.4); }
.card .btn-donate { margin-top: .4rem; }
.phone a { font: 700 1.3rem/1 "Roboto Slab", serif; text-decoration: none; }

/* underwriting */
.cta-row { display: flex; gap: .7rem; flex-wrap: wrap; }
.callout {
  background: var(--paper); border: 1px solid var(--rule); border-radius: 12px;
  padding: 1.6rem; box-shadow: var(--shadow);
}
.callout-k {
  font: 800 1.9rem/1 "Roboto Slab", serif; color: var(--teal); margin-bottom: .6rem;
}
.callout p:last-child { font-size: .95rem; color: var(--ink-soft); margin-bottom: 0; }

/* apps */
.grid-apps {
  list-style: none; padding: 0; margin: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1.4rem;
  max-width: 800px; margin-inline: auto;
}
.grid-apps li {
  background: var(--paper); border: 1px solid var(--rule); border-radius: 12px;
  padding: 1.5rem; text-align: center; display: grid; gap: .5rem; justify-items: center;
}
.grid-apps img { width: 64px; height: 64px; border-radius: 14px; }
.grid-apps b { font-family: "Roboto Slab", serif; font-size: 1.05rem; }
.grid-apps a { font-size: .9rem; }

/* ============================ footer ============================ */
.site-footer { background: var(--cream-2); border-top: 1px solid var(--rule); padding: 3.5rem 0 1.5rem; }
.foot-grid {
  display: grid; grid-template-columns: 1.3fr .8fr 1fr; gap: 2.5rem;
  padding-bottom: 2.5rem;
}
@media (max-width: 820px) { .foot-grid { grid-template-columns: 1fr; } }
.foot-logo { height: 44px; width: auto; margin-bottom: 1rem; }
.foot-addr { font-size: .93rem; color: var(--ink-soft); line-height: 1.9; }
.foot-social { display: flex; gap: 1rem; font-size: .9rem; }
.site-footer h4 {
  font: 700 .76rem/1 "Courier Prime", monospace; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-faint); margin-bottom: 1rem;
}
.site-footer ul { list-style: none; padding: 0; margin: 0; font-size: .93rem; line-height: 2; color: var(--ink-soft); }
.funders { display: flex; gap: 1.2rem; align-items: center; flex-wrap: wrap; }
.funders img { height: 34px; width: auto; opacity: .8; }
.foot-note { font-size: .9rem; color: var(--ink-soft); margin-top: .9rem; }
.foot-legal {
  border-top: 1px solid var(--rule); padding-top: 1.4rem;
  font-size: .82rem; color: var(--ink-faint);
  text-align: center;
}
/* max-width needs the auto margins too, or the block stays left and only the
   text inside it centres. */
.foot-legal p { margin: 0 auto; max-width: 80ch; }

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