/* Fort Collins Public Media: the site's one stylesheet, plain CSS with no build step.
   Colours, type and spacing are tokens in :root. see docs/site.md */

/* --- Tokens --------------------------------------------------------------- */

:root {
  /* Yellow is a surface, never text on paper (1.4:1); site/bin/test_tokens.py checks. */
  /* brand:light: from FC-Public-Media/brand (brand.yml), written by its render.py. Change it there. */
  --ink:           #121417;  /* body text, and the dark surfaces */
  --slate:         #232830;  /* the second dark surface, one step up from ink; unlit marks */
  --ink-soft:      #545c66;  /* secondary text */
  --paper:         #f4f1ea;  /* page background: warm, not white */
  --paper-alt:     #e8e3d8;  /* banded sections */
  --rule:          #d5cfc2;  /* hairlines */
  --signal:        #ffc61a;  /* the plate: fills, borders, outlines, marks. A surface, never text on paper (1.4:1) */
  --signal-ink:    #121417;  /* what sits on top of yellow: 11.7:1 */
  --record:        #d93a26;  /* on-air red for fills: 4.1:1 on paper */
  --record-ink:    #a52c1d;  /* on-air red for text: 6.3:1 */
  --masthead:      #121417;  /* the masthead band: dark in both schemes, the one surface that does not flip */
  --masthead-ink:  #f4f1ea;  /* text on the band */
  --masthead-soft: #9ba3ad;  /* secondary text on the band, and on any dark ground: 7.2:1 */
  --accent:        #e5af00;  /* links: ink, underlined, red on hover */
  --font-display:  "Source Serif 4", Georgia, "Times New Roman", serif;
  --font-body:     Archivo, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono:     ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* end brand:light */

  --stable-glass: #e8e3d8;
  --stable-glass-inv: #1c2126;
  --brand-tilt: -4deg;

  /* What the glass panels become where backdrop-filter is unavailable or unwanted: one solid, dark
     and slightly warm, so --stable-glass text stays at about 11:1 instead of sitting on 15% yellow
     over a photograph. */
  --glass-solid: color-mix(in srgb, var(--masthead) 88%, var(--signal));

  /* The masthead's height, so the hero can fill exactly what is left of the viewport. */
  --head-h: 4.25rem;

  /* Fluid type scale */
  --step--1: clamp(0.86rem, 0.83rem + 0.15vw, 0.94rem);
  --step-0:  clamp(1.02rem, 0.98rem + 0.20vw, 1.13rem);
  --step-1:  clamp(1.28rem, 1.18rem + 0.45vw, 1.55rem);
  --step-2:  clamp(1.60rem, 1.40rem + 0.95vw, 2.15rem);
  --step-3:  clamp(2.00rem, 1.60rem + 1.90vw, 3.10rem);
  --step-4:  clamp(2.50rem, 1.75rem + 3.40vw, 4.60rem);

  /* Space and measure */
  --wrap: 68rem;
  --measure: 38rem;
  --gap: clamp(1rem, 0.7rem + 1.4vw, 2rem);
}

/* --- The dark scheme: opt-in, set as data-theme by assets/js/theme.js; light without JS --- */

:root { color-scheme: light; }

:root[data-theme="dark"] {
  color-scheme: dark;
  /* brand:dark: from FC-Public-Media/brand (brand.yml), written by its render.py. Change it there. */
  --ink:       #ece8e1;  /* body text on the dark paper */
  --slate:     #2b313a;  /* the second dark surface */
  --ink-soft:  #a1a8b2;  /* secondary text */
  --paper:     #121417;  /* the dark page */
  --paper-alt: #1c2126;  /* banded sections */
  --rule:      #2f363d;  /* hairlines on dark */
  --signal:    #ffc61a;  /* unchanged in both schemes; on this dark paper it is safe as text */
  --signal-ink: #121417;  /* what sits on top of yellow */
  --record:    #d93a26;  /* on-air red for fills */
  --record-ink: #e16151;  /* text red walked light: the brand red is 4.0:1 on this paper */
  --accent:    #ffc61a;  /* links */
  /* end brand:dark */
}

/* --- Fonts: self-hosted variable faces, one file covers every weight -------- */

@font-face {
  font-family: "Archivo";
  src: url("/assets/fonts/archivo.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Source Serif 4";
  src: url("/assets/fonts/source-serif-4.woff2") format("woff2");
  font-weight: 200 900;
  font-style: normal;
  font-display: swap;
}

/* --- Base ----------------------------------------------------------------- */

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

/* Any rule that sets display would otherwise un-hide [hidden]. */
[hidden] { display: none !important; }

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.6;
  text-underline-offset: 0.18em;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 750;
  line-height: 1.08;
  letter-spacing: -0.022em;
  margin: 0 0 0.5em;
  text-wrap: balance;
}

h1 { font-size: var(--step-3); }
h2 { font-size: var(--step-2); }
h3 { font-size: var(--step-1); }

p, ul, ol, dl, table { margin: 0 0 1.1em; }

a { color: var(--accent); text-decoration-thickness: 1px; }
a:hover { color: var(--record-ink); }

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

/* Long URLs and paths in code spans break rather than widen the page on a phone. */
code { font-family: var(--font-mono); font-size: 0.9em; overflow-wrap: anywhere; }

/* Text meant to be copied (a device record, a key); scrolls inside itself. */
.code-block {
  margin: 0 0 1.5em;
  padding: 1rem;
  background: var(--paper-sunk, rgba(0, 0, 0, 0.04));
  border: 1px solid var(--rule);
  border-radius: 4px;
  overflow-x: auto;
  max-width: 100%;
}
.code-block code {
  white-space: pre;
  overflow-wrap: normal;
  font-size: var(--step--1);
}

hr { border: 0; border-top: 1px solid var(--rule); margin: 2.5rem 0; }

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

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* --- The brand plane ------------------------------------------------------ */

/* The mark sits at an angle, and so can anything else. `.plane` is the whole vocabulary:
 *
 *   .plane            put this box on the angle
 *   .plane > *        its children stand back up, automatically
 *   .plane > .tilted  except this one, which rides the angle with the box
 *
 * So there is no adding a rotation and then subtracting it by hand, and no wrapper element per
 * child whose only job is to be straightened. One element with `.plane` and no children is simply
 * a thing on the angle — which is how the reel's pause button is attached.
 *
 * `rotate` and not `transform`, so a translate or a scale on the same element composes instead of
 * overwriting. Change the angle in one place: --brand-tilt. */
.plane { rotate: var(--brand-tilt); }
.plane > * { rotate: calc(-1 * var(--brand-tilt)); }
.plane > .tilted { rotate: 0deg; }

/* A rotated box still reserves its unrotated space, so its corners can cross a neighbour. Give the
 * parent room rather than pushing the angle down to the children. */
.plane-room { padding: 1.5rem; }

/* --- Layout --------------------------------------------------------------- */

.wrap {
  width: min(100% - 2.5rem, var(--wrap));
  margin-inline: auto;
}

/* The measure is on text elements, so grids and tables in prose get the full column. */
.prose { max-width: 100%; }
.prose > p,
.prose > h2,
.prose > h3,
.prose > blockquote,
.prose > .transaction,
.prose > ul:not(.grid):not(.rows),
.prose > ol { max-width: var(--measure); }

.prose > :last-child { margin-bottom: 0; }
.prose h2 { margin-top: 0; }
.prose h3 { margin-top: 1.6em; }
.prose li { margin-bottom: 0.35em; }

.muted { color: var(--ink-soft); }
.lede  { font-size: var(--step-1); color: var(--ink-soft); max-width: var(--measure); line-height: 1.4; }

.eyebrow {
  font-size: var(--step--1);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 650;
  color: var(--ink-soft);
  margin-bottom: 0.6rem;
}

.band { background: var(--paper-alt); padding: clamp(2.5rem, 6vw, 5rem) 0; margin-top: 4rem; }
/* Secondary tokens flip on a dark band, so components inside need no special cases. */
.band-ink {
  background: var(--ink);
  color: var(--paper);
  --ink-soft: color-mix(in srgb, var(--paper) 66%, transparent);
  --rule: color-mix(in srgb, var(--paper) 24%, transparent);
}
/* Without color-mix() (Safari before 16.2) the two above are unusable: full-strength stand-ins. */
@supports not (color: color-mix(in srgb, red, red)) {
  .band-ink { --ink-soft: var(--paper); --rule: currentColor; }
}
.band-ink h2 { color: var(--paper); }
.band-ink a { color: var(--paper); }

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

/* A dark band in both schemes: the plate is 1.4:1 on paper and 11.7:1 on ink. */
.site-head {
  border-bottom: 1px solid var(--slate);
  position: sticky; top: 0; z-index: 20;
  background: var(--masthead);
  color: var(--masthead-ink);
}
/* Behind @supports, not a second declaration: with var() inside, Safari before 16.2 (the iPad Air 2's
   iOS 15) would accept the line and then paint nothing, leaving light text on the light page. */
@supports (color: color-mix(in srgb, red, red)) {
  .site-head {
    background: color-mix(in srgb, var(--masthead) 94%, transparent);
    backdrop-filter: blur(8px);
  }
}
/* :not(.btn): `.site-head a` outranks `.btn-cta` and would put light text on yellow. */
.site-head a:not(.btn) { color: inherit; }

.site-head-inner {
  display: flex; align-items: center; gap: var(--gap);
  min-height: 4.25rem;
}

/* The name and what is on now, read as one group. `margin-right: auto` lives here rather than on
   .wordmark so the on-air title stays beside the name instead of being pushed against the menu.
   min-width: 0 is what lets the title inside shrink far enough to ellipsise. */
.site-head-brand {
  display: flex; align-items: center; gap: 1rem;
  margin-right: auto; min-width: 0;
}

.wordmark {
  display: flex; align-items: center; gap: 0.6rem;
  text-decoration: none; color: inherit;
  /* The name never gives up space; the programme title absorbs the squeeze. */
  flex: none;
}

/* The mark: the plate, set at -8deg. */
.wordmark-mark {
  width: 1.15rem; height: 1.15rem;
  background: var(--signal);
  flex: none;
  rotate: -8deg;
}

.wordmark-text { display: flex; flex-direction: column; line-height: 1.05; }
.wordmark-text b {
  font-family: var(--font-display);
  font-size: 1.02rem; font-weight: 780; letter-spacing: -0.02em;
}
.wordmark-text span {
  font-size: 0.7rem; text-transform: uppercase;
  letter-spacing: 0.14em;
  /* --ink-soft is tuned for paper and lands at 2.7:1 here. */
  color: var(--masthead-soft);
}

/* The current page's menu word, shown in the masthead on narrow screens only. */
.site-head-here {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

@media (max-width: 60rem) {
  .site-head-here {
    position: static; width: auto; height: auto;
    margin: 0; clip: auto;
    /* Same face as the wordmark, so the bar reads as one thing. */
    font-family: var(--font-display);
    font-size: 1.02rem; font-weight: 780; letter-spacing: -0.02em;
    color: var(--masthead-ink);
    margin-left: auto;
  }
}

.site-nav { display: flex; align-items: center; gap: 1.4rem; }
.site-nav ul {
  display: flex; gap: 1.35rem;
  list-style: none; margin: 0; padding: 0;
}
.site-nav a:not(.btn) {
  /* inherit, not var(--ink): the masthead is dark. site/tests/contrast.spec.js checks. */
  color: inherit; text-decoration: none;
  font-size: var(--step--1); font-weight: 550;
  padding: 0.35rem 0;
  border-bottom: 2px solid transparent;
}
.site-nav a:not(.btn):hover { border-bottom-color: var(--rule); }
.site-nav a:not(.btn)[aria-current="page"] { border-bottom-color: var(--signal); }

/* The line icons beside each word (_includes/nav-icon.html): the text's colour, no fill. */
.site-nav a:not(.btn) { display: inline-flex; align-items: center; gap: 0.4em; }
.nav-icon {
  width: 1.25em; height: 1.25em; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}
.nav-gear { transform-box: fill-box; transform-origin: center; }
/* Join's box is empty until you reach for it. */
.nav-tick { stroke-dasharray: 12; stroke-dashoffset: 12; transition: stroke-dashoffset 0.25s ease-out; }
.site-nav a:hover .nav-tick,
.site-nav a:focus-visible .nav-tick,
.site-nav a[aria-current="page"] .nav-tick { stroke-dashoffset: 0; }
@media (prefers-reduced-motion: no-preference) {
  /* The gears mesh: speeds in the ratio of their teeth, 6 to 5. */
  .site-nav a:hover .nav-gear-big { animation: nav-turn 4.8s linear infinite; }
  .site-nav a:hover .nav-gear-small { animation: nav-turn 4s linear infinite reverse; }
}
@keyframes nav-turn { to { transform: rotate(360deg); } }

/* Links under one grey verb that is not a link: "Reserve  Equipment  Studios". */
.nav-group {
  display: flex; align-items: baseline; gap: 0.7rem;
}
.nav-group-label {
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.12em;
  font-weight: 650;
  color: var(--masthead-soft);
  align-self: center;
}
.nav-group ul { gap: 1.1rem; }

.nav-toggle { display: none; }

@media (max-width: 60rem) {
  .nav-toggle {
    display: grid; place-items: center;
    width: 2.75rem; height: 2.75rem;
    background: none; border: 1px solid var(--masthead-soft); cursor: pointer;
  }
  .nav-toggle-bars,
  .nav-toggle-bars::before,
  .nav-toggle-bars::after {
    /* --masthead-ink, not --ink: the band is dark in both schemes. */
    display: block; width: 1.15rem; height: 2px; background: var(--masthead-ink);
  }
  .nav-toggle-bars { position: relative; }
  .nav-toggle-bars::before,
  .nav-toggle-bars::after { content: ""; position: absolute; left: 0; }
  .nav-toggle-bars::before { top: -6px; }
  .nav-toggle-bars::after  { top:  6px; }

  /* The drawer is the dark masthead continued, since its links inherit light text. */
  .site-nav {
    display: none;
    position: absolute; left: 0; right: 0; top: 100%;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--masthead);
    border-bottom: 1px solid var(--slate);
    padding: 0.5rem 1.25rem 1.25rem;
  }
  .site-nav[data-open="true"] { display: flex; }
  .site-nav ul { flex-direction: column; gap: 0; }
  .site-nav ul a,
  .site-nav a:not(.btn) {
    display: flex; padding: 0.8rem 0;
    border-bottom: 1px solid var(--slate);
    font-size: var(--step-0);
  }

  /* Stacked in the drawer, so the group label reads as a heading. */
  .nav-group { display: block; }
  .nav-group-label { display: block; padding: 0.9rem 0 0.35rem; }
  .site-nav .btn-cta { margin-top: 1rem; text-align: center; }
}

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

.btn {
  display: inline-block;
  padding: 0.65rem 1.15rem;
  font-size: var(--step--1);
  font-weight: 650;
  text-decoration: none;
  border: 2px solid var(--ink);
  color: var(--ink);
  background: transparent;
}
.btn:hover { background: var(--ink); color: var(--paper); }

.btn-primary,
.btn-cta {
  background: var(--signal);
  border-color: var(--signal);
  color: var(--signal-ink);
}
.btn-primary:hover,
.btn-cta:hover {
  background: transparent;
  color: var(--record-ink);
  border-color: var(--record-ink);
}

/* --- Hero ----------------------------------------------------------------- */

/* Tight, so identity, channels, the check-in code and a live class fit above the fold. */
.hero { padding: clamp(1.75rem, 3vw, 2.5rem) 0 clamp(1.5rem, 2.5vw, 2rem); }

/* `oneview` (set by `oneview: true` in a page's front matter): one screen, footer included.
 *
 * The shell is the viewport and the hero takes whatever the masthead and the footer leave. The hero
 * is deliberately NOT given a height of its own: `100svh - header` is how the footer ends up just
 * below the fold, because it does not account for the footer. Letting the hero be the flexible row
 * means the three parts always add up to exactly one screen.
 *
 * `svh` and not `vh`: on a phone `vh` is the height with the browser chrome retracted, so a 100vh
 * shell is taller than the screen until you scroll. `min-height`, not `height`, so content that
 * genuinely does not fit scrolls rather than being clipped. */
.oneview {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
}
.oneview > main {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}
.oneview .hero {
  flex: 1 1 auto;
  display: grid;
  /*align-items: center;*/
  &> .wrap { padding: 3rem 0; }
}

/* The footer's usual 5rem of air is there to separate it from a page that has ended. On a fitted
   page it is the bottom of the screen, so it only needs its rule. */
.oneview .site-foot { margin-top: 0; }

/* The hero is the row that gives. `min-height: 0` is the part that is easy to miss: a flex item
   will not shrink below its content without it, so the page would grow past the screen instead.
   And its own padding-block goes, because on a fitted page the shell is already supplying the
   height — keeping both counts the same space twice, which is what pushed the footer under. */
.oneview .hero { min-height: 0; }
.oneview .hero-photo { padding-block: 0; }

/* An empty section still occupies its margins. Nothing to show, nothing to space. */
.oneview > main > section:empty,
.oneview > main > div:empty { display: none; margin: 0; }

/* Named areas reorder on a phone; the auto column collapses when the class card is hidden. */
.hero .wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "panel class";
  column-gap: clamp(1.5rem, 4vw, 3rem);
  row-gap: 1rem;
  align-items: start;
}
.hero-panel { grid-area: panel; }
.hero-class { grid-area: class; }

/* With a photo, the type sits on opaque panels rather than on the image. */
.hero-photo {
  background-image: var(--hero-image);
  background-size: cover;
  background-position: center;
  padding-block: clamp(3rem, 6vw, 5rem);
}
/* The tilt and the straightening are `.plane` now; see the brand plane, above. This only adds the
   breathing room the angle needs. */
.hero-photo .hero-panel > * { padding: 1em; }

.hero-photo .hero-panel,
.hero-photo .hero-class {
  color: var(--stable-glass);
    background-color: color-mix(in srgb, var(--signal) 15%, transparent);
    backdrop-filter: blur(120px) saturate(180%);
    -webkit-backdrop-filter: blur(120px) saturate(180%);
    border: 1px solid color-mix(in srgb, var(--signal) 20%, transparent);
  padding: clamp(1.5rem, 3vw, 2.25rem);

  span {
     text-shadow: 0 2px 1px var(--stable-glass-inv);
  }
}

/* The fallback the glass needs. Without backdrop-filter the panel is 15% yellow over a photograph,
   which is not a tint — it is unreadable text on whatever happens to be behind it. So: one solid.
   Two reasons to take it, and the same answer for both.

   `prefers-reduced-transparency` comes first because it is a preference, not a capability: a
   browser that supports the blur must still drop it when the reader has asked for less. */
@media (prefers-reduced-transparency: reduce) {
  .hero-photo .hero-panel,
  .hero-photo .hero-class {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background-color: var(--glass-solid);
  }
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .hero-photo .hero-panel,
  .hero-photo .hero-class {
    background-color: var(--glass-solid);
  }
}
/* The QR's own panel only needs to be as wide as the code. */
.hero-photo .hero-qr { padding: 1rem; width: fit-content; }
.hero h1 {
  font-size: var(--step-4);
  max-width: 16ch;
  margin-bottom: 0.25em;
}
.hero .lede { font-size: var(--step-1); max-width: 46ch; }

/* The line under the slogan (front matter `tagline`), set tight and dark, not as a .lede. */
.hero-tagline {
  margin-bottom: 0;
  color: var(--stable-glass);
}

.hero-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 2rem; }

/* Slogan, check-in code, channels. The code stands beside the slogan only; on a wide panel it may
   run down beside the buttons too, but on a narrow one the buttons take the full width back
   rather than wrapping one to a line in the code's shadow. */
.hero-lockup {
  display: grid;
  /* min-content: the label wraps to the code's width instead of widening the column. */
  grid-template-columns: minmax(0, 1fr) min-content;
  grid-template-areas:
    "title    qr"
    "channels qr";
  column-gap: clamp(1rem, 3vw, 2rem);
  align-items: start;
}
.hero-lockup h1 { grid-area: title; }
.hero-lockup .hero-qr { grid-area: qr; }
.hero-lockup .hero-channels { grid-area: channels; }
@media (max-width: 56rem) {
  .hero-lockup {
    grid-template-areas:
      "title    qr"
      "channels channels";
  }
  .hero .hero-channels { gap: 0.5rem; }
  .hero .hero-channels .btn { padding: 0.5rem 0.8rem; }
}

/* Where to find us: text buttons, never icons. */
.hero-channels { margin-top: 1.1rem; }

/* Both classes, to outrank .checkin-card-qr (declared later), which centres its contents. */
.checkin-card-qr.hero-qr {
  align-items: flex-start;
  align-self: start;
  justify-self: start;
  gap: 0.35rem;
}
/* max-width off: in the lockup's min-content column a percentage cap lets the code shrink to the
   width of the word CHECK. The code sets the column; the label wraps to it. */
.checkin-card-qr.hero-qr img { max-width: none; }
/* The code is the densest thing in the hero and not its main action, so its white tile is glass, not
   paper: translucent white behind the SVG's own black modules (the SVG has no background). The modules
   stay solid black for scanning; --qr-light is how much white. Read by OpenCV down to 15% on screenshots;
   35% leaves a real phone camera room. No blend mode needed, so the tilted panel's isolation is moot. */
.hero-qr { --qr-light: 35%; }
.checkin-card-qr.hero-qr img { background: color-mix(in srgb, #fff var(--qr-light), transparent); }
.hero-qr span { font-size: 0.66rem; color: var(--stable-glass); }

.hero .btn {
  border: 2px solid var(--stable-glass);
  color: var(--stable-glass);
}

/* --- A class, in the hero ------------------------------------------------- */

.hero-class {
  flex: 0 0 auto;
  width: min(26rem, 100%);
  border-left: 5px solid var(--signal);
  padding-left: clamp(1rem, 2vw, 1.5rem);
}
.hero-class[hidden] { display: none; }
.hero-class h2 { font-size: var(--step-2); margin-bottom: 0.25em; margin-top: 0; }
.hero-class .eyebrow { color: var(--record-ink); }
.hero-class-when { font-weight: 650; margin-bottom: 0.4em; }
.hero-class-summary { color: var(--ink-soft); max-width: 34ch; }
.hero-class .hero-actions { margin-top: 1.25rem; }

/* One column on a phone. */
@media (max-width: 56rem) {
  .hero .wrap {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "panel";
    row-gap: 1.5rem;
  }
  .hero-class { width: 100%; }

  /* A class that is on moves above the headline; data-class-mode is set by classmode.js. */
  .hero[data-class-mode="soon"] .wrap,
  .hero[data-class-mode="now"] .wrap,
  .hero[data-class-mode="late"] .wrap {
    grid-template-areas:
      "class"
      "panel";
  }
}

/* Used by _layouts/podcast.html, where the heading is the episode's name. */
.page-head {
  padding: clamp(1.5rem, 3vw, 2.25rem) 0 clamp(1rem, 2vw, 1.5rem);
  border-bottom: 1px solid var(--rule);
  margin-bottom: clamp(1.5rem, 3vw, 2rem);
}

/* _layouts/page.html has no header; this is the only space below the masthead. */
.page-body { padding-top: 2.5em; }

/* --- The floor plan ------------------------------------------------------- */

/* A photo introducing a page; height capped since phone photos arrive in any aspect. */
.page-photo {
  margin: 0 0 clamp(1.5rem, 4vw, 2.5rem);
}
.page-photo img {
  display: block;
  width: 100%;
  max-height: 26rem;
  object-fit: cover;
  background: var(--paper-alt);
}
.page-photo figcaption {
  margin-top: 0.5rem;
  font-size: var(--step--1);
  color: var(--ink-soft);
}

/* The floor plan: an appendix at the foot of the page, set apart by a rule. */
.floor-plan img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--rule);
}
.floor-plan figcaption {
  font-size: var(--step--1);
  color: var(--ink-soft);
}

/* --- Cards and grids ------------------------------------------------------ */

.grid {
  display: grid;
  gap: var(--gap);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  list-style: none; padding: 0; margin: 0;
}

/* Narrower minimum, so four short cards sit on one row instead of 3 + 1. */
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); }

.card {
  border: 1px solid var(--rule);
  padding: 1.4rem;
  background: var(--paper);
  display: flex; flex-direction: column;
}
.card h3 { margin: 0; font-size: var(--step-1); }
.card p { margin: 0; color: var(--ink-soft); font-size: var(--step--1); }
.card a { text-decoration: none; }
.card a:hover { text-decoration: underline; }
.card-foot { margin-top: auto; padding-top: 0.9rem; }

/* Membership tiers: an invisible radio covers each card; the chosen one tilts -8deg. */
.tiers { border: 0; margin: 0; padding: 0; min-width: 0; }
.tier {
  position: relative;
  transition: rotate 220ms cubic-bezier(.34, 1.56, .64, 1),
              border-color 150ms ease, box-shadow 150ms ease;
}
.tier input[type="radio"] {
  position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%; margin: 0;
  opacity: 0; cursor: pointer;
}
.tier:hover { border-color: var(--ink-soft); }
.tier:has(input:focus-visible) { outline: 3px solid var(--signal); outline-offset: 2px; }
.tier:has(input:checked) {
  rotate: -8deg;
  z-index: 2;
  border-color: var(--signal);
  box-shadow: 0 0 0 3px var(--signal), 0 10px 24px rgb(0 0 0 / 0.18);
}
@media (prefers-reduced-motion: reduce) {
  .tier { transition: none; }
}

/* A roster headshot: square, with the aspect enforced rather than taken from the file. */
.card-portrait {
  width: clamp(4.5rem, 30%, 7rem);
  aspect-ratio: 1;
  overflow: hidden;
  background: var(--paper-alt);
  border-radius: 50%;
}
.card-portrait img { width: 100%; height: 100%; object-fit: cover; }

/* Office hours override the muted grey of .card p. */
.office-hours { color: var(--ink) !important; }
.office-hours b { display: block; font-weight: 650; font-size: var(--step--1); }

.card .price,
.price {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 780;
  letter-spacing: -0.03em;
  color: var(--ink);
}

/* Definition-style rows — used for facilities, carriage, equipment. */
.rows { list-style: none; margin: 0 0 1.5em; padding: 0; }
.rows li {
  display: flex; flex-wrap: wrap; gap: 0.25rem 1rem;
  justify-content: space-between; align-items: baseline;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--rule);
}
.rows li b { font-weight: 650; }

/* Spaces: a grid, not flex, so every width gets two rows: name and size, then the text. */
.rows-spaces li {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  column-gap: 1rem;
}
.rows-spaces li p {
  grid-column: 1 / -1;
  margin: 0.3rem 0 0;
  color: var(--ink-soft);
  /*max-width: var(--measure);*/
}
.rows li span { color: var(--ink-soft); font-size: var(--step--1); }

/* --- Tags ----------------------------------------------------------------- */

.tag {
  display: inline-block;
  font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em;
  font-weight: 700; padding: 0.2rem 0.5rem;
  border: 1px solid var(--rule); color: var(--ink-soft);
}
.tag-warn { border-color: var(--record-ink); color: var(--record-ink); }

/* --- Transactions --------------------------------------------------------- */

.transaction { margin: 1.75rem 0; }

/* Something not set up yet, made loud so it is noticed before production. */
.transaction-todo {
  border-left: 4px solid var(--signal);
  background: var(--paper-alt);
  padding: 1rem 1.15rem;
  font-size: var(--step--1);
}
.transaction-todo b { display: block; margin-bottom: 0.25rem; font-size: var(--step-0); }
.transaction-todo .muted { display: block; margin-top: 0.4rem; }

/* --- The reel: the hero photograph, moving --------------------------------- */

/* Behind the hero's panels, covering the section, with the still image underneath it. `object-fit`
   so a 16:9 clip fills a hero of any shape without stretching. */
.hero-video {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  /* Behind the panels, above .hero-photo's background-image. */
  z-index: 0;
  /* Until frames are moving, the photograph behind it shows: never a frozen or black frame. */
  background: transparent;
  opacity: 0;
  transition: opacity 0.6s ease;
}
.hero-video.is-playing { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .hero-video { transition: none; } }

/* The hero becomes the positioning context, and its content has to sit above the video. */
.hero { position: relative; isolation: isolate; }
.hero .wrap { position: relative; z-index: 1; }

/* The control, mounted on the panel rather than on the video: the panel is already on the brand
   plane, and `.tilted` is what keeps this riding the angle instead of being stood back up with the
   panel's other children. Pulled out of the panel's flow so it sits in the corner. */
.reel-toggle {
  position: absolute;
  top: 0; right: 0;
  translate: -35% 35%;
  display: grid; place-items: center;
  width: 2.5rem; height: 2.5rem;
  padding: 0;
  background: none;
  color: var(--stable-glass);
  border: 0;
  cursor: pointer;
  z-index: 2;
}
.reel-toggle[hidden] { display: none; }
.hero-panel { position: relative; }

.reel-icon { width: 0.9rem; height: 0.9rem; fill: currentColor; }

/* One button, two glyphs: show the one that says what the click will do. */
.reel-icon-pause { display: none; }
/* The button's own state, so a tap answers at once while the video is still loading. */
.reel-toggle[aria-pressed="true"] .reel-icon-play { display: none; }
.reel-toggle[aria-pressed="true"] .reel-icon-pause { display: block; }

/* --- Embeds --------------------------------------------------------------- */

.embed { margin: 0 0 1.5rem; width: 100%; }
.embed iframe { width: 100%; border: 0; aspect-ratio: 16 / 9; }
.embed-audio iframe { aspect-ratio: auto; height: 180px; }

.embed-live {
  background: #000;
}
.embed-live iframe { display: block; }

/* --- Sections ------------------------------------------------------------- */

.section { margin-top: clamp(3rem, 6vw, 5rem); }

.section-head {
  display: flex; flex-wrap: wrap; gap: 1rem 2rem;
  align-items: end; justify-content: space-between;
  margin-bottom: 1.75rem;
}
.section-head h2 { margin: 0; }
.section-head .eyebrow { margin-bottom: 0.35rem; }

/* --- Mission statement ---------------------------------------------------- */

/* One large sentence, no heading; wider than --measure because it is display type. */
.mission-statement {
  font-size: var(--step-2);
  line-height: 1.25;
  max-width: 48rem;
  margin: 0;
  text-wrap: balance;
}

/* --- On-air bar ----------------------------------------------------------- */

/* Directly under the hero; a ticker that does not move. */
.onair-bar {
  font-size: var(--step--1);
}
.onair-bar[hidden] { display: none; }
.onair-bar > * { display: inline; }

/* In the masthead the programme title is whatever Cablecast says it is, so it takes the room that
   is left and ellipsises rather than shoving the menu. Not a flex container: text-overflow needs a
   block with the text directly in it. */
.site-head-brand .onair-bar {
  display: block; min-width: 0;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}

.onair-label {
  font-weight: 700;
}
.onair-next { color: var(--ink-soft); }

.onair-inline {
  border: 1px solid var(--rule);
  background: var(--paper-alt);
  color: var(--ink);
}

/* --- Featured ------------------------------------------------------------- */

.featured { margin-top: clamp(2.5rem, 5vw, 4rem); }

.grid-feature { grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr)); }

.card-feature { border-top: 4px solid var(--signal); }
.card-feature .tag { align-self: start; }
.feature-when { font-weight: 650; color: var(--ink) !important; }

/* --- Show cards ----------------------------------------------------------- */

.grid-show { grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr)); }

.card-show { padding: 0; border: 1px solid var(--rule); gap: 0; }
.card-show h3 {
  font-size: var(--step-0); font-weight: 650; line-height: 1.25;
  padding: 0.9rem 1rem 0.35rem;
}
.card-show h3 a { color: var(--ink); }
.card-show .show-meta {
  padding: 0 1rem 0.25rem;
  font-size: 0.8rem;
}
.card-show .show-meta:last-child { padding-bottom: 1rem; }

.show-thumb { display: block; background: var(--paper-alt); }
.show-thumb img {
  width: 100%; aspect-ratio: 16 / 9; object-fit: cover;
}

/* --- Archive -------------------------------------------------------------- */

.rows-inline { display: flex; flex-wrap: wrap; gap: 0 2rem; }
.rows-inline li { border: 0; padding: 0.4rem 0; }

.rows-tight li { padding: 0.5rem 0; }

.rows-connect li { border-bottom-color: color-mix(in srgb, currentColor 25%, transparent); }

.rows-archive li[hidden] { display: none; }

/* Airing counts as tabular data; "not aired" carries the emphasis. */
.airings { font-variant-numeric: tabular-nums; font-weight: 600; }
.airings-none { color: var(--record-ink); }

/* A date that has not happened yet. */
.coming { color: var(--record-ink); font-variant-numeric: tabular-nums; }

/* Short fields that belong together (date, time, runtime) on one line. */
.field-row { display: flex; flex-wrap: wrap; gap: 0 1rem; }
.field-row .field { flex: 1 1 8rem; display: flex; flex-direction: column; }
/* A select draws shorter than an input; side by side, the row evens them. */
.field-row .field > :is(input, select) { flex: 1; }

.field textarea {
  width: 100%; font: inherit; padding: 0.6rem 0.7rem;
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--rule); resize: vertical;
}

/* The settings YAML editor: monospace and unwrapped, since indentation carries meaning. */
#settings-text {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  line-height: 1.5;
  tab-size: 2;
  white-space: pre;
  overflow-x: auto;
}

/* A button that reads as a link, for a secondary action inside a sentence. */
.btn-link {
  background: none; border: 0; padding: 0;
  font: inherit; color: var(--accent); cursor: pointer;
  text-decoration: underline; text-underline-offset: 0.18em;
}
.btn-link:hover { color: var(--record-ink); }

/* Cablecast titles are often one unbreakable token (Midnight_Limited_1940_2026-07-14_11_59_43). */
.rows-archive li b,
.rows-archive li span,
.card-show h3 { overflow-wrap: anywhere; }

.filter {
  position: sticky; top: 4.25rem; z-index: 5;
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
  padding: 1rem 0;
  margin-bottom: 1rem;
  display: grid; gap: 0.4rem 1rem;
  grid-template-columns: minmax(12rem, 1fr) auto;
  align-items: end;
}
.filter label { grid-row: 1; }
.filter input, .filter select { grid-row: 2; }
.filter-count { grid-column: 1 / -1; grid-row: 3; }
.filter select {
  font: inherit; font-size: var(--step--1);
  padding: 0.6rem 0.7rem;
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--rule);
}
@media (max-width: 32rem) {
  .filter { grid-template-columns: 1fr; }
  .filter label, .filter input, .filter select, .filter-count { grid-row: auto; }
}
.filter[hidden] { display: none; }
.filter label {
  display: block; font-size: 0.72rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--ink-soft); margin-bottom: 0.4rem;
}
.filter input {
  width: min(100%, 26rem);
  font: inherit; font-size: var(--step-0);
  padding: 0.6rem 0.8rem;
  border: 1px solid var(--rule);
  background: var(--paper); color: var(--ink);
}
.filter-count { margin: 0.5rem 0 0; font-size: var(--step--1); color: var(--ink-soft); }

/* The footer colour-scheme toggle; `hidden` in the markup until theme.js reveals it. */
.theme-toggle {
  margin: 0 0 1rem;
  font-size: var(--step--1);
}
.theme-toggle[hidden] { display: none; }
.theme-toggle label {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--ink-soft);
  cursor: pointer;
}
.theme-toggle label:hover { color: var(--ink); }
.theme-toggle input { accent-color: var(--signal); }
.theme-toggle input:checked + span { color: var(--ink); font-weight: 650; }

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

.site-foot {
  margin-top: 5rem;
  border-top: 3px solid var(--ink);
  padding-top: 3rem;
  font-size: var(--step--1);

  &.flush { border-top: none; }
}

.site-foot-inner {
  display: grid; gap: var(--gap);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
}

.foot-title {
  font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--ink-soft); margin-bottom: 0.9rem; font-weight: 700;
}
.site-foot address { font-style: normal; margin-bottom: 1em; }
.foot-links { list-style: none; margin: 0; padding: 0; }
.foot-links li { margin-bottom: 0.45rem; }

.foot-legal {
  color: var(--ink-soft);
}
.foot-legal p { margin: 0; }

/* --- Check-in ------------------------------------------------------------- */

.rows-checkin li b { font-variant-numeric: tabular-nums; }

/* Member programs from feeds: a fixed-ratio thumbnail beside the title. */
.feed { list-style: none; margin: 0 0 1.5em; padding: 0; }
.feed li {
  display: flex; gap: 1rem; align-items: flex-start;
  padding: 1rem 0;
  border-bottom: 1px solid var(--rule);
}
.feed-thumb {
  flex: none;
  width: clamp(6.5rem, 22vw, 10rem);
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--paper-alt);
}
.feed-thumb img { width: 100%; height: 100%; object-fit: cover; }
.feed-body { min-width: 0; }
.feed-body b { font-weight: 650; display: block; margin-bottom: 0.2rem; }
.feed-meta { margin: 0; font-size: var(--step--1); }
.feed-summary {
  margin: 0.35rem 0 0;
  font-size: var(--step--1);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Merged community calendar: dates in a column, the time beneath each date. */
.rows-events li b,
.rows-feed li b {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  display: flex; flex-direction: column; gap: 0.1rem;
}
.rows-events li b .muted,
.rows-feed li b .muted { font-weight: 400; }

/* Class context on the check-in page, from the same data as the homepage's. */
.class-banner {
  border-left: 5px solid var(--signal);
  background: var(--paper-alt);
  padding: 1.25rem 1.5rem;
  margin-bottom: 2.5rem;
}
.class-banner[hidden] { display: none; }
.class-banner h2 { margin: 0 0 0.3em; }
.class-banner .lede { font-size: var(--step-0); margin-bottom: 0.5em; }
.class-banner [data-class-room]::before { content: " · "; }
.class-banner p:last-child { margin-bottom: 0; }

.rsvp-noted { font-weight: 600; }
.rsvp-noted[hidden],
[data-rsvp-offer][hidden] { display: none; }

/* Only one state panel is ever visible; the rest carry `hidden`. */
.state[hidden] { display: none; }
.state { margin-bottom: 2.5rem; }
.state h2 { margin-top: 0; }

/* The primary action, sized for a thumb. */
.btn-big {
  font-size: var(--step-1);
  padding: 0.9rem 1.8rem;
}

.field { margin-bottom: 1.25rem; max-width: var(--measure); }
.field label {
  display: block;
  font-size: 0.75rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--ink-soft); margin-bottom: 0.4rem;
}
.field input,
.field select {
  font: inherit; font-size: var(--step-0);
  width: 100%;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--rule);
  background: var(--paper); color: var(--ink);
}

/* Class mode: a yellow leading edge on the band while a class is on. */
.band[data-class-mode="now"],
.band[data-class-mode="late"],
.band[data-class-mode="soon"] { border-left: 5px solid var(--signal); }

.hero-class [data-class-room]::before { content: " · "; }

.class-late {
  border-left: 3px solid var(--signal);
  padding-left: 0.9rem;
  font-weight: 600;
}
.class-late[hidden] { display: none; }

.checkin-card-qr {
  flex: 0 0 auto;
  display: flex; flex-direction: column; align-items: center; gap: 0.5rem;
  text-decoration: none;
}
.checkin-card-qr img {
  width: clamp(8rem, 22vw, 11rem); height: auto;
  background: #fff;
  border: 1px solid var(--rule);
}
.checkin-card-qr span {
  font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.12em;
  font-weight: 700;
}

.rows input[type="text"] {
  font: inherit;
  padding: 0.35rem 0.6rem;
  border: 1px solid var(--rule);
  background: var(--paper);
  color: var(--ink);
  max-width: 14rem;
}

/* A label styled as a button, driving a hidden file input ("Restore from a file"). */
label.btn { cursor: pointer; }

/* --- Poster --------------------------------------------------------------- */

.poster {
  border: 3px solid var(--ink);
  padding: clamp(1.5rem, 5vw, 3rem);
  text-align: center;
  max-width: 34rem;
  margin: 2rem 0;
}
.poster-eyebrow {
  font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.14em;
  font-weight: 700; color: var(--ink-soft); margin-bottom: 0.5rem;
}
.poster-title { font-size: var(--step-3); margin-bottom: 1.5rem; }
.poster-qr {
  width: min(100%, 20rem); height: auto; margin: 0 auto 1.25rem;
  /* White ground in both schemes, so the black SVG code stays scannable. */
  background: #fff; padding: 0.75rem;
}
.poster-url { font-weight: 650; font-size: var(--step-1); margin-bottom: 0.75rem; overflow-wrap: anywhere; }
.poster-note { color: var(--ink-soft); font-size: var(--step--1); margin: 0; }

@media print {
  .site-head, .site-foot, .no-print, .page-head .lede { display: none !important; }
  .poster { border-width: 2px; page-break-inside: avoid; }
  body { background: #fff; color: #000; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* --- The countdown: the plate depleting while media loads, with no numbers ----- */

/* Registered so the sweep can animate; without @property support the plate sits still. */
@property --sweep {
  syntax: "<angle>";
  inherits: false;
  initial-value: 360deg;
}

.countdown {
  --size: 2.75rem;
  --sweep: 360deg;

  width: var(--size);
  height: var(--size);
  flex: none;
  background: var(--signal);

  /* Masked, not drawn, so the square keeps its shape and only its coverage changes. */
  -webkit-mask-image: conic-gradient(#000 var(--sweep), transparent 0);
  mask-image: conic-gradient(#000 var(--sweep), transparent 0);

  animation:
    countdown-sweep 1.5s linear infinite,
    countdown-swing 1.5s cubic-bezier(0.16, 0.84, 0.28, 1) infinite;
}

@keyframes countdown-sweep {
  from { --sweep: 360deg; }
  to   { --sweep: 0deg; }
}

/* Counter-clockwise and eased, settling slightly small before each new cycle. */
@keyframes countdown-swing {
  0%   { rotate: 0turn;      scale: 1; }
  70%  { rotate: -0.92turn;  scale: 0.94; }
  100% { rotate: -1turn;     scale: 1; }
}

.countdown-wrap {
  display: flex; align-items: center; gap: 0.9rem;
  color: var(--ink-soft); font-size: var(--step--1);
}

/* Rotation is a vestibular trigger; with reduced motion the plate holds still and breathes. */
@media (prefers-reduced-motion: reduce) {
  .countdown {
    animation: countdown-breathe 2.4s ease-in-out infinite;
    -webkit-mask-image: none;
    mask-image: none;
    rotate: -8deg;
  }
  @keyframes countdown-breathe {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.45; }
  }
}

/* --- The Booqable store on /reserve/ -------------------------------------- */
/* Tiles are Booqable's own and untouched. List is ours, only under .is-list, so a markup change
   on their side breaks the list and never the checkout. #main outranks their later-injected
   sheet. Never target hashed class names. See docs/payments.md#booqable. */

#main .booqable-store { padding-bottom: 1rem; }

/* Tiles | List, set by assets/js/booqable-view.js; hidden until that script runs. */
.booqable-view {
  display: flex;
  justify-content: flex-end;
  gap: 0.4rem;
  margin: 1.5rem 0 0.75rem;
}
.booqable-view button {
  font: inherit;
  font-size: var(--step--1);
  font-weight: 650;
  padding: 0.4rem 0.9rem;
  border: 2px solid var(--ink);
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  cursor: pointer;
}
.booqable-view button:hover { background: var(--ink); color: var(--paper); }
.booqable-view button[aria-pressed="true"] {
  background: var(--signal);
  border-color: var(--signal);
  color: var(--signal-ink);
}

/* List: their grid of cards becomes one column of rows. */
#main .booqable-store.is-list .booqable-product-list-grid { display: block !important; padding: 0; }

#main .booqable-store.is-list .booqable-product,
#main .booqable-store.is-list .booqable-product-wrapper {
  min-width: 0 !important; max-width: none !important; width: auto !important; margin: 0;
}

#main .booqable-store.is-list .booqable-product-inner {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 0.9rem;
  border-radius: 0;
  box-shadow: none;
  border: 0;
  border-bottom: 1px solid var(--rule);
  padding: 0.6rem 0.2rem;
  height: auto;
}
#main .booqable-store.is-list .booqable-product:first-child .booqable-product-inner {
  border-top: 1px solid var(--rule);
}

/* The thumbnail: matched by structure, since the only classes here are hashed. */
#main .booqable-store.is-list .booqable-product-inner > div:first-child {
  flex: 0 0 auto;
  width: 3.2rem;
  height: 3.2rem;
  border: 1px solid var(--rule);
  border-radius: 3px;
  overflow: hidden;
  background: #fff;
  position: relative;
}
#main .booqable-store.is-list .booqable-product-inner > div:first-child > span > * {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  min-height: 0;
  padding: 0;
  margin: 0;
  border: 0;
}
#main .booqable-store.is-list .booqable-product-inner > div:first-child img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The rest of the row: name, availability, price, then their cart button last. */
#main .booqable-store.is-list .bq-details {
  flex: 1 1 auto;
  min-width: 0;
  height: auto;
  padding: 0;
  display: flex;
  align-items: center;
  gap: 0.9rem;
}
#main .booqable-store.is-list .bq-details > div:first-child { order: 2; flex: 0 0 auto; position: static; }
#main .booqable-store.is-list .bq-details .bq-status { position: static; margin: 0; }
#main .booqable-store.is-list .bq-product-title-wrapper,
#main .booqable-store.is-list .bq-product-title-wrapper.bq-has-prices {
  order: 1;
  flex: 1 1 auto;
  min-width: 0;
  height: auto;
  padding-right: 0;
}
#main .booqable-store.is-list .bq-price-details { order: 3; }
#main .booqable-store.is-list .bq-details > .bq-button { order: 4; position: static; flex: 0 0 auto; margin: 0; }

/* Names wrap to two lines: the end tells them apart ("...for Sony E", "...for Canon"). */
#main .booqable-store.is-list .bq-product-name {
  white-space: normal;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.3;
  font-family: var(--font-body);
  font-size: var(--step-0);
  font-weight: 550;
  color: var(--ink);
}

/* Prices right-aligned and unwrapped, so they line up down the page. */
#main .booqable-store.is-list .bq-price-details {
  flex: 0 0 auto;
  min-width: 8.5rem;
  margin-top: 0;
  text-align: right;
  white-space: nowrap;
  font-size: var(--step--1);
  color: var(--ink-soft);
}
#main .booqable-store.is-list .bq-price-details .bq-price {
  margin-left: 0.4em;
  color: var(--ink);
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

/* Narrow rows: name on its own line, the rest beneath it. */
@media (max-width: 30rem) {
  #main .booqable-store.is-list .bq-details { flex-wrap: wrap; gap: 0.3rem 0.9rem; }
  #main .booqable-store.is-list .bq-product-title-wrapper,
  #main .booqable-store.is-list .bq-product-title-wrapper.bq-has-prices { flex: 1 1 100%; }
  #main .booqable-store.is-list .bq-price-details { min-width: 0; margin-left: auto; }
}

/* --- The pass (/check-in/, _layouts/pass.html): fills the screen, never scrolls --- */

html.is-pass { background: var(--masthead); }
html.is-pass,
.pass-body { height: 100%; overflow: hidden; }

/* Dark in both schemes: the page tokens point at the masthead pair, which never flips. */
.pass-body {
  --ink: var(--masthead-ink);
  --ink-soft: var(--masthead-soft);
  --paper: var(--masthead);
  --paper-alt: #232830;
  --rule: #2f363d;
  --accent: var(--masthead-ink);
  margin: 0; background: var(--paper); color: var(--ink);
}

/* Phone-width; the slope is tan(8deg) of that width, so each edge sits at the mark's angle. */
.pass-view {
  --slope: 14.05cqw;
  max-width: 28rem; margin-inline: auto; container-type: inline-size;
  height: 100vh; height: 100dvh;
  display: grid; grid-template-rows: auto 1fr auto;
  padding-bottom: env(safe-area-inset-bottom);
  box-sizing: border-box;
}
.pass-view[hidden] { display: none; }
.pass-view.pass { grid-template-rows: auto auto 1fr auto; }
.pass-card { grid-row: 1; } .pass-go { grid-row: 2; } .pass-now { grid-row: 3; } .pass-nav { grid-row: 4; }

.pass-card {
  background: var(--signal); color: var(--signal-ink);
  padding: calc(1.5rem + env(safe-area-inset-top)) 1.5rem calc(1rem + var(--slope));
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--slope)), 0 100%);
  display: flex; flex-direction: column; gap: 0.3rem;
}
.pass-head { display: flex; align-items: center; gap: 0.9rem; margin-bottom: 0.4rem; }
.pass-mark {
  flex: none; display: block; width: 2.6rem; height: 2.6rem;
  background: var(--signal-ink); rotate: -8deg;
}
.pass-card input {
  font: inherit; color: inherit; background: transparent;
  border: 0; border-bottom: 2px solid transparent; border-radius: 0;
  padding: 0.1rem 0; width: 100%; min-width: 0;
}
.pass-card input::placeholder { color: color-mix(in srgb, var(--signal-ink) 45%, transparent); }
.pass-card input:focus { outline: none; border-bottom-color: var(--signal-ink); }
.pass-card input:placeholder-shown { border-bottom-color: color-mix(in srgb, var(--signal-ink) 25%, transparent); }
.pass-card .pass-name {
  font-family: var(--font-display); font-size: clamp(2rem, 10cqw, 3rem);
  font-weight: 700; line-height: 1.05; letter-spacing: -0.01em;
}
.pass-email, .pass-email input { font-size: var(--step-0); margin: 0; }
.pass-email[hidden] { display: none; }
.pass-chip {
  display: inline-block; margin-left: 0.4rem; padding: 0.1rem 0.5rem;
  font-size: 0.7rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  background: var(--masthead); color: var(--masthead-ink);
}
.pass-card .pass-device {
  font-size: 0.75rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  margin-top: 0.4rem;
}
.pass-contact {
  align-self: flex-start; margin: -0.2rem 0 0.2rem; padding: 0;
  font: inherit; font-size: var(--step--1); font-weight: 650;
  background: none; border: 0; color: var(--signal-ink); text-decoration: underline;
}
.pass-contact[hidden] { display: none; }
.pass-staff { margin: 0.7rem 0 0; font-size: 0.85rem; }
.pass-staff a { color: var(--ink-soft); }

/* Check in: a band at the card's angle; the clipped parallelogram is all that can be pressed. */
.pass-go { --thick: 4.5rem; --gap: 0.55rem; margin-top: calc(var(--gap) - var(--slope)); }
.pass-go[hidden] { display: none; }
.pass-band {
  position: relative; display: block; width: 100%;
  height: calc(var(--slope) + var(--thick));
  margin: 0; padding: 0; border: 0; cursor: pointer;
  background: var(--signal); color: var(--signal-ink); font: inherit;
  clip-path: polygon(0 var(--slope), 100% 0, 100% var(--thick), 0 calc(var(--slope) + var(--thick)));
}
.pass-band:focus-visible { outline: none; background: var(--masthead-ink); }
.pass-band-in {
  position: absolute; left: 50%; top: calc((var(--slope) + var(--thick)) / 2);
  translate: -50% -50%; rotate: -8deg;
  display: flex; flex-direction: column; align-items: center; white-space: nowrap;
}
.pass-band-label { font-size: var(--step-2); font-weight: 750; line-height: 1.1; }
.pass-reason {
  font-size: 0.7rem; font-weight: 750; letter-spacing: 0.12em; text-transform: uppercase;
}
.pass-reason[hidden] { display: none; }

/* What is happening now: the states and a class, on the black. */
.pass-now {
  min-height: 0; overflow: hidden;
  display: flex; flex-direction: column; gap: 1rem;
  padding: 1.25rem 1.5rem 0;
}
.pass-now h2 { font-size: var(--step-1); margin: 0 0 0.25rem; }
.pass-now p { margin: 0 0 0.5rem; }
.pass-now .state { margin: 0; }
.pass-now [data-state]:not([hidden]) p { color: var(--ink-soft); }
.pass-status { font-weight: 600; }
.pass-status[hidden] { display: none; }
.pass .class-banner { margin: 0; padding: 0 0 0 0.9rem; border-left: 4px solid var(--signal); background: none; }
.pass-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0 0 1rem; }

/* Bottom right: the angle again, in slate, holding the links to Visits and This phone. */
.pass-nav {
  display: flex; justify-content: flex-end; align-items: flex-end; gap: 1.25rem;
  height: var(--slope); padding: 0 1.5rem 0.6rem; box-sizing: border-box;
  background: var(--paper-alt);
  clip-path: polygon(0 100%, 100% 0, 100% 100%);
}
.pass-nav a { color: var(--ink); font-size: 0.95rem; font-weight: 650; text-decoration: none; }
#checkin-count:not(:empty) {
  display: inline-block; min-width: 1.4em; margin-left: 0.3rem; padding: 0 0.35em;
  font-size: 0.8em; text-align: center; background: var(--signal); color: var(--signal-ink);
}

/* A view of its own: a way back, a name, and a list that scrolls inside itself. */
.pass-top {
  display: flex; align-items: baseline; gap: 1rem;
  padding: calc(1rem + env(safe-area-inset-top)) 1.5rem 0.75rem;
  border-bottom: 1px solid var(--rule);
}
.pass-top h2 { font-size: var(--step-1); margin: 0; }
.pass-back { font-weight: 650; text-decoration: none; color: var(--ink-soft); }
.pass-back::before { content: "\2190\00a0"; }
.pass-scroll { min-height: 0; overflow: auto; padding: 1rem 1.5rem; }


.supports {
  color: var(--ink-soft);
  font-size: var(--step--1);
  b { font-size: 0.9em; }
}

blockquote {
  border-left: 3px solid var(--signal);
  margin-left: 1rem;
  padding-left: 1rem;
  color: var(--record-ink)
}

/* --- Split: the page's reading on the left, its form on the right (stacked on a phone) --- */

.split { display: grid; gap: clamp(2rem, 5vw, 4rem); }
.split > * > :first-child { margin-top: 0; }
.split-main > :is(p, h2, h3, blockquote, ul, ol) { max-width: var(--measure); }
@media (min-width: 56rem) {
  .split { grid-template-columns: minmax(0, 1fr) minmax(20rem, 28rem); align-items: start; }
}

/* The way to Dropbox: a link to its upload page in a new tab, since Dropbox will not be framed. */
.dropbox {
  display: block; padding: 0 1.25rem 1rem;
  text-align: center;
}
.dropbox b { display: block; font-size: var(--step-1); }
.dropbox span { color: var(--ink-soft); font-size: var(--step--1); }

.check { display: flex; gap: 0.6rem; align-items: flex-start; margin-bottom: 0.9rem; cursor: pointer; }
.check input { margin-top: 0.3rem; flex: none; }

/* Filled in by robots only. Off-screen rather than display:none, which some skip. */
.trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* /join/'s survey: the experience questions fold away; their options run in columns. */
.join-more { margin: 0.5rem 0 1.5rem; }
.join-more summary { cursor: pointer; font-weight: 600; margin-bottom: 1rem; }
.checks { border: 0; padding: 0; margin: 0 0 1.25rem; }
.checks legend { font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; color: var(--ink-soft); margin-bottom: 0.6rem; }
.checks { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); column-gap: 1rem; }
.checks .check { margin-bottom: 0.5rem; }

/* The organization field's suggestions from the IRS list. */
[data-org-results]:empty { display: none; }
[data-org-results] { margin: 0.4rem 0 0; }

/* --- Halves: two parts of a page side by side; tabs on a phone (assets/js/halves.js) --- */

/* minmax(0, …) so a wide child (the studio's week) scrolls inside its half instead of widening the page. */
.halves { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(2rem, 5vw, 4rem); }
.half > :first-child { margin-top: 0; }
.halves-tabs { display: none; }
@media (min-width: 56rem) {
  /* Wider than the page's column where the screen has room, and the studio's week gets the larger half.
     Written out rather than through a var(): old Safari drops var() inside min(). */
  .halves {
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); align-items: start;
    width: max(100%, min(100vw - 3.5rem, 94rem));
    margin-inline: calc((100% - max(100%, min(100vw - 3.5rem, 94rem))) / 2);
  }
}
@media (max-width: 55.99rem) {
  .halves { gap: 1.5rem; }
  .halves-tabs:not([hidden]) {
    display: flex; gap: 0; border-bottom: 1px solid var(--rule);
    position: sticky; top: 0; z-index: 2; background: var(--paper);
  }
  .halves-tabs button {
    flex: 1; font: inherit; font-weight: 700; padding: 0.8rem 1rem; cursor: pointer;
    background: none; border: 0; border-bottom: 3px solid transparent; color: var(--ink-soft);
  }
  .halves-tabs button[aria-selected="true"] { color: var(--ink); border-bottom-color: var(--signal); }
  .half.is-away { display: none; }
}

/* --- /reserve/'s studio request: a space, a day, a start, a host (assets/js/book.js) --- */

/* The week shown and the space: two rows of picks that look alike, so they read as the form's choices
   rather than as tabs. Each row ends in a box held to the right: the start time, then the host. */
.book-spaces { border: 0; padding: 0; margin: 0; min-width: 0; }
.book-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.75rem 1rem; margin-bottom: 1rem; }
.book-row .field { margin: 0 0 0 auto; flex: 0 1 13rem; }
.book-picks { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.book-picks label { position: relative; cursor: pointer; }
.book-picks input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.book-picks span, .book-picks button {
  display: block; font: inherit; font-weight: 650; padding: 0.55rem 0.95rem; cursor: pointer;
  background: none; color: var(--ink); border: 1px solid var(--rule);
}
.book-picks label:hover span, .book-picks button:hover { border-color: var(--ink-soft); }
.book-picks input:checked + span,
.book-picks button[aria-pressed="true"] { background: var(--signal); color: var(--signal-ink); border-color: var(--signal); }
.book-picks input:focus-visible + span,
.book-picks button:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; }
.book-picks[hidden] { display: none; }
/* Three to a row on a phone. */
@media (max-width: 30rem) {
  .book-picks { gap: 0.35rem; }
  .book-picks span, .book-picks button { padding: 0.5rem 0.6rem; font-size: var(--step--1); }
}
.book-space p { margin: 0 0 0.75rem; color: var(--ink-soft); max-width: var(--measure); }
.book-space p b { color: var(--ink); }

.planner { margin: 0 0 1.5rem; }
/* Padding, because scrolling sideways clips, and a picked card tilts past its box. */
.planner-scroll { overflow-x: auto; padding: 1rem 0.5rem 0.5rem; margin-inline: -0.5rem; }
.planner-grid { display: grid; column-gap: 0.4rem; }

.planner-head { display: flex; flex-direction: column; gap: 0.5rem; padding-bottom: 0.4rem; }
.planner-month { margin: 0 0 0.35rem; font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; }
.planner-date { margin: 0; font-size: var(--step--1); color: var(--ink-soft); }
.planner-date b { color: var(--ink); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.1em; }

.planner-seat { position: relative; isolation: isolate; }
/* The day's own host while a time on their day is picked: a yellow mark behind the card. */
.planner-seat.is-suggested::before {
  content: ""; position: absolute; inset: -0.25rem; z-index: -1;
  background: var(--signal); rotate: -8deg;
}
.planner-host {
  display: block; width: 100%; font: inherit; font-size: var(--step--1); font-weight: 650; text-align: left;
  padding: 0.55rem 0.6rem; background: var(--paper); color: var(--ink); border: 1px solid var(--rule); cursor: pointer;
  transition: rotate 220ms cubic-bezier(.34, 1.56, .64, 1), border-color 150ms ease, box-shadow 150ms ease;
}
.planner-host img { width: 2.5rem; height: 2.5rem; object-fit: cover; border-radius: 50%; margin-bottom: 0.35rem; }
.planner-host span { display: block; overflow-wrap: anywhere; }
.planner-host small { display: block; margin-top: 0.2rem; font-size: 0.72rem; font-weight: 500; line-height: 1.3; color: var(--ink-soft); }
.planner-host:hover { border-color: var(--ink-soft); }
.planner-host:focus-visible { outline: 3px solid var(--signal); outline-offset: 2px; }
/* The host picked: tilted, as /join/'s tier is. */
.planner-host.is-picked {
  rotate: -8deg; position: relative; z-index: 2; border-color: var(--signal);
  box-shadow: 0 0 0 3px var(--signal), 0 10px 24px rgb(0 0 0 / 0.18);
}

.planner-hours { position: relative; }
.planner-hours span {
  position: absolute; right: 0.35rem; translate: 0 -50%;
  font-size: 0.72rem; font-weight: 650; color: var(--ink-soft);
}
.planner-track { position: relative; border-left: 1px solid var(--rule); cursor: pointer; }
.planner-line { position: absolute; left: 0; right: 0; border-top: 1px solid var(--rule); pointer-events: none; }

.planner-slot, .planner-you {
  position: absolute; left: 0.2rem; right: 0.2rem;
  display: flex; flex-direction: column; gap: 0.1rem; overflow: hidden;
  padding: 0.35rem 0.45rem; text-align: left; font: inherit;
}
.planner-slot {
  background: var(--paper-alt); color: var(--ink); cursor: pointer;
  border: 1px solid var(--rule); border-left: 4px solid var(--ink);
}
.planner-slot b { font-size: var(--step--1); }
.planner-slot span { font-size: 0.82rem; font-weight: 650; }
.planner-slot small { font-size: 0.72rem; line-height: 1.3; color: var(--ink-soft); }
.planner-slot:hover { border-color: var(--ink-soft); border-left-color: var(--ink); }
.planner-slot:focus-visible { outline: 3px solid var(--signal); outline-offset: 1px; }
.planner-slot.is-picked { background: var(--signal); color: var(--signal-ink); border-color: var(--signal); border-left-color: var(--signal-ink); }
.planner-slot.is-picked small { color: var(--signal-ink); }
.planner-slot:disabled { cursor: default; opacity: 0.4; }
.planner-now {
  position: absolute; left: -0.3rem; right: 0; z-index: 3; height: 0;
  border-top: 2px solid var(--record); pointer-events: none;
}
.planner-now::before {
  content: ""; position: absolute; left: 0; top: -0.3rem;
  width: 0.5rem; height: 0.5rem; margin-top: -1px; border-radius: 50%; background: var(--record);
}
.planner-you { background: var(--signal); color: var(--signal-ink); font-size: 0.82rem; font-weight: 700; pointer-events: none; }

.planner-bumper {
  font: inherit; font-size: 0.75rem; margin: 0.3rem 0; padding: 0.4rem 0.3rem; cursor: pointer;
  background: none; color: var(--ink-soft); border: 1px dashed var(--rule);
}
.planner-bumper:hover { color: var(--ink); border-color: var(--ink-soft); }
.planner-bumper.is-picked { background: var(--signal); color: var(--signal-ink); border: 1px solid var(--signal); font-weight: 700; }
.planner-bumper:disabled { visibility: hidden; }
.planner-head.is-past, .planner-track.is-past { opacity: 0.45; }
.planner-track.is-past { cursor: default; }
.planner-hint { font-size: var(--step--1); margin: 0.6rem 0 0; }

.book-mine .rows li code { font-size: var(--step--1); }

@media (prefers-reduced-motion: reduce) {
  .planner-host { transition: none; }
}

/* Short checkbox options on one wrapping line (times of day, days of the week). */
.checks-inline { display: flex; flex-wrap: wrap; gap: 0.25rem 0.9rem; }
.field-row > .checks { flex: 1 1 8rem; }
.checks-inline legend { width: 100%; }
.checks-inline .check { margin-bottom: 0.25rem; }

a[href^="mailto:"] span {
  padding-left: 0.25em;
  font-size: var(--step--1);
  letter-spacing: -0.05em;
  color: var(--signal-ink);
}
.nonprofit {
  color: var(--record) !important;
  font-weight: bold;
}
.student {
  color: var(--record-ink) !important;
  font-weight: bold;
}
