/* The Good Behaviours: "Sandstone & river" mock-up.
   Light sandstone pages, deep bush-green bands behind the stage photos, ochre
   and river-teal accents, and the logo's banjo pink and brown. Taken from the
   Home cover (sandstone at the water's edge in low gold light), Cloudy in the
   Gully, and their Dyarubbin and Dharawal story. Motion recipes are ported
   from ~/Claude_Code/text-effects.md and scroll-reveal.md (see fx.js), and the
   iOS fixes from the Emily-Rose mock-up (~/Claude_Code/Ero). */

:root {
  --sand: #efe4cf;
  --sand-2: #f6efe2;
  --sand-3: #e4d5b9;
  --bush: #1d2a22;
  --bush-2: #25352b;
  --bush-3: #2f4336;
  --cream: #f3ead8;
  --ink: #1d2a22;
  --ochre: #b8622e;
  --ochre-deep: #8f4520;
  --ochre-light: #e39a62;
  --teal: #2f6f6a;
  --teal-light: #86c3b9;
  --pink: #e3b5a4;
  --brown: #6e3b2e;

  /* Section-scoped tokens: .dark and .pale swap them. */
  --bg: var(--sand);
  --fg: var(--ink);
  --fg-dim: color-mix(in srgb, var(--ink) 70%, transparent);
  --card: var(--sand-2);
  --line: color-mix(in srgb, var(--ink) 15%, transparent);
  --accent: var(--ochre-deep);
  --string: var(--teal);

  --display: 'Young Serif', 'Iowan Old Style', 'Palatino Linotype', Palatino, Georgia, serif;
  --body: 'Instrument Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono: 'DM Mono', ui-monospace, 'SF Mono', Menlo, monospace;
  --gutter: max(20px, 4.5vw);
  --radius: 14px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  color-scheme: light;
}

*, *::before, *::after { box-sizing: border-box; }
/* ⚠ The root's background is what the rubber-band scroll uncovers when you
   pull past the top. It's each page's --edge: the average colour of its
   cover photo's top edge as shown, measured at build time (build.mjs,
   pages.mjs cover()), so the strip matches the photo (Joseph wanted the
   bounce kept, without a strip in a different colour; a solid green fade
   at the top of every cover was tried and rejected). The page paints sand
   on body. The phone home page's photo fades to its own near-black, so the
   root follows it there (below). */
html { -webkit-text-size-adjust: 100%; scroll-padding-top: 90px; background: var(--edge, var(--bush)); }
body {
  margin: 0;
  background: var(--sand);
  color: var(--ink);
  font: 400 1.0625rem/1.65 var(--body);
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}
/* Grain: a faint paper texture over everything. */
body::after {
  content: '';
  /* Starts 8px down: iOS Safari samples fixed full-width layers touching the
     top edge for the status-bar colour, and this near-transparent film must
     not be the one it picks (see the header notes). */
  position: fixed; inset: 8px 0 0; z-index: 39; pointer-events: none;
  /* ...and fades in, so where it starts is never a visible line. */
  -webkit-mask-image: linear-gradient(transparent, #000 60px);
  mask-image: linear-gradient(transparent, #000 60px);
  opacity: 0.07;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-underline-offset: 0.18em; text-decoration-thickness: 1px; }
a:hover { color: var(--accent); }
:focus-visible { outline: 2px solid var(--teal); outline-offset: 3px; border-radius: 4px; }
.dark :focus-visible, .cover :focus-visible { outline-color: var(--ochre-light); }
[hidden] { display: none !important; }
.sr, .hp { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.skip { position: absolute; left: 12px; top: -60px; z-index: 100; background: var(--ochre); color: #fff; padding: 10px 14px; border-radius: 8px; }
.skip:focus { top: 12px; }

.wrap {
  width: 100%; max-width: 1200px; margin-inline: auto;
  /* Landscape phones: keep clear of the notch on either side. */
  padding-left: max(var(--gutter), env(safe-area-inset-left, 0px));
  padding-right: max(var(--gutter), env(safe-area-inset-right, 0px));
}
.narrow { max-width: 760px; }
.center { text-align: center; }
.dim { color: var(--fg-dim); }

/* ── Type ──────────────────────────────────────────────────────────────── */
h1, h2, h3 {
  font-family: var(--display);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -0.012em;
  margin: 0 0 0.45em;
  text-wrap: balance;
}
h2 { font-size: clamp(2rem, 4.4vw, 3.6rem); }
h3 { font-size: clamp(1.2rem, 1.9vw, 1.45rem); line-height: 1.2; }
p { margin: 0 0 1em; }
.lede { font-size: clamp(1.15rem, 1.6vw, 1.32rem); line-height: 1.55; }
.eyebrow {
  font: 600 0.78rem/1.2 var(--body);
  font-stretch: 85%;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 1.1rem;
}
.small-h { font-size: 1.02rem; font-family: var(--body); font-weight: 650; letter-spacing: 0.02em; margin: 2.2rem 0 0.7rem; }
.fine { font-size: 0.85rem; color: var(--fg-dim); }
code { font-size: 0.9em; background: color-mix(in srgb, currentColor 10%, transparent); padding: 0.1em 0.35em; border-radius: 5px; }

/* ── Buttons & links ───────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5em;
  min-height: 48px; padding: 0.7em 1.4em;
  border-radius: 999px; border: 1.5px solid transparent;
  font: 600 0.98rem/1 var(--body); letter-spacing: 0.01em;
  text-decoration: none; cursor: pointer;
  transition: transform 0.25s var(--ease), background-color 0.25s, color 0.25s, border-color 0.25s, box-shadow 0.25s;
}
.btn:hover { transform: translateY(-2px); }
.btn-ochre { background: var(--ochre); color: #fff8ee; }
.btn-ochre:hover { color: #fff8ee; background: var(--ochre-deep); box-shadow: 0 10px 30px -12px color-mix(in srgb, var(--ochre) 80%, transparent); }
.btn-ghost { border-color: color-mix(in srgb, var(--fg) 40%, transparent); color: var(--fg); background: transparent; }
.btn-ghost:hover { border-color: var(--accent); color: var(--accent); }
.btn-small { min-height: 38px; padding: 0.5em 1.05em; font-size: 0.88rem; }
.actions { display: flex; flex-wrap: wrap; gap: 0.8rem; margin-top: 1.6rem; }
.center-actions { justify-content: center; }
.link-arrow { font-weight: 600; text-decoration: none; display: inline-flex; gap: 0.45em; align-items: center; color: var(--accent); }
.link-arrow::after { content: '→'; transition: transform 0.25s var(--ease); }
.link-arrow:hover::after { transform: translateX(4px); }

/* ── Header ────────────────────────────────────────────────────────────── */
.site-header {
  position: fixed; inset: 0 0 auto; z-index: 40;
  padding-top: env(safe-area-inset-top, 0px);
  color: var(--cream);
  /* --solid runs 0 → 1 with the scroll (site.js), so the bar fades in as you
     go rather than snapping on at one point. */
  --solid: 0;
  background: color-mix(in srgb, var(--bush) calc(var(--solid) * 86%), transparent);
  backdrop-filter: blur(calc(var(--solid) * 14px)) saturate(calc(1 + var(--solid) * 0.2));
  -webkit-backdrop-filter: blur(calc(var(--solid) * 14px)) saturate(calc(1 + var(--solid) * 0.2));
  box-shadow: 0 1px 0 color-mix(in srgb, var(--cream) calc(var(--solid) * 12%), transparent);
}
/* ⚠ The notch / Dynamic Island. iOS 26 Safari ignores theme-color and colours
   the status-bar strip from the topmost fixed, full-width layer touching the
   top of the viewport, reading its background-color. The grain film starts 8px
   down so that THIS header is the layer Safari samples: the strip then takes
   the header's own translucent colour. Keep the background on the fixed
   element itself (not a child), keep it translucent (an opaque header was
   rejected on the Emily-Rose mock-up), and keep nothing else fixed and
   full-width at the very top.
   It stays bush green in light mode too: a sand header flipping on as the
   dark cover scrolled away looked wrong (Joseph, 2026-09-24). */
.site-header.scrolled { --solid: 1; }
/* On a computer, every page: the bar's blur and tint start behind the logo
   and spread out along it as it fades in (site.js sets --logo-x
   and --solid). They move to a layer under the header's contents so they can
   be masked without masking the logo and links. Phones keep the plain fade,
   which Joseph was happy with, and which keeps the colour on the header
   itself for iOS's status bar. */
@media (min-width: 900px) {
  .spread-bar .site-header { background: transparent; backdrop-filter: none; -webkit-backdrop-filter: none; }
  .spread-bar .site-header::before {
    content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
    background: color-mix(in srgb, var(--bush) 86%, transparent);
    backdrop-filter: blur(14px) saturate(1.2);
    -webkit-backdrop-filter: blur(14px) saturate(1.2);
    /* Grows slowly at first (a glow round the logo), then sweeps across. */
    --r: calc(var(--solid) * var(--solid) * 112vw);
    --edge: calc(var(--r) + min(1, var(--solid) * 5) * 260px);
    -webkit-mask-image: radial-gradient(circle at var(--logo-x, 280px) 50%, #000 var(--r), transparent var(--edge));
    mask-image: radial-gradient(circle at var(--logo-x, 280px) 50%, #000 var(--r), transparent var(--edge));
  }
}
.header-inner { display: flex; align-items: center; justify-content: space-between; min-height: 76px; gap: 1rem; }
.header-right { display: flex; align-items: center; gap: 0.9rem; }
.mp-slot:empty { display: none; }
.logo { position: relative; display: block; width: clamp(150px, 16vw, 200px); aspect-ratio: 1200 / 351; flex: none; }
.logo img { width: 100%; height: 100%; }
.logo-footer { width: 240px; margin-bottom: 1rem; }
.nav-desktop { display: flex; align-items: center; gap: clamp(0.9rem, 2vw, 1.8rem); font-weight: 600; font-size: 0.97rem; }
.nav-desktop a:not(.btn) { text-decoration: none; position: relative; padding-block: 0.4em; }
.nav-desktop a:not(.btn)::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; border-radius: 2px; background: var(--ochre-light); transform: scaleX(0); transform-origin: left; transition: transform 0.35s var(--ease); }
.nav-desktop a:not(.btn):hover::after, .nav-desktop a[aria-current]::after { transform: scaleX(1); }
.nav-desktop a:not(.btn):hover { color: inherit; }
.nav-mobile { display: none; }
@media (max-width: 899px) {
  .nav-desktop { display: none; }
  .nav-mobile { display: block; }
  .nav-mobile summary { list-style: none; cursor: pointer; width: 48px; height: 48px; display: grid; place-content: center; gap: 6px; border-radius: 50%; background: color-mix(in srgb, var(--bush) 55%, transparent); }
  .nav-mobile summary::-webkit-details-marker { display: none; }
  .nav-mobile summary span { display: block; width: 22px; height: 2px; background: currentColor; border-radius: 2px; transition: transform 0.3s var(--ease), opacity 0.2s; }
  .nav-mobile[open] summary span:nth-child(1) { transform: translateY(8px) rotate(45deg); }
  .nav-mobile[open] summary span:nth-child(2) { opacity: 0; }
  .nav-mobile[open] summary span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }
  .nav-mobile nav {
    position: fixed; inset: calc(76px + env(safe-area-inset-top, 0px)) 0 auto 0;
    background: var(--bush); color: var(--cream); border-top: 1px solid color-mix(in srgb, var(--cream) 12%, transparent);
    display: grid; padding: 1rem var(--gutter) 2rem;
    box-shadow: 0 30px 60px -20px rgba(0,0,0,.45);
  }
  .nav-mobile nav a { font-family: var(--display); font-size: 2rem; padding: 0.3rem 0; text-decoration: none; }
  .nav-mobile nav a[aria-current] { color: var(--ochre-light); }
}

/* ── Cover (scroll-reveal.md §3–4): pinned photo, the page scrolls over it ─ */
.cover {
  position: relative;
  min-height: 68svh;
  display: flex; align-items: flex-end;
  padding-block: calc(110px + env(safe-area-inset-top, 0px)) clamp(3rem, 7vw, 5.5rem);
  color: var(--cream);
}
.cover-home { min-height: 100svh; min-height: 100lvh; align-items: flex-end; }
.cover-bg { position: fixed; inset: 0; z-index: 0; overflow: hidden; background: var(--bush); }
/* ⚠ The photo and its shading live in one layer (.cover-drift) that drifts
   as a whole. When the drift was on the photo alone, the shading and the
   photo sat on separate layers, and Safari's rubber-band scroll pulled them
   apart, uncovering a band of unshaded photo at the top (Joseph). */
.cover-drift { position: absolute; inset: 0; }
.cover-bg img { width: 100%; height: 118%; object-fit: cover; object-position: var(--pos, 50% 50%); }
/* On a computer the photo fills the screen's height, so object-position can't
   move it up or down. --lift (set per page in pages.mjs) raises it instead,
   trimming its top, so the band isn't cut off by the bottom of a short hero
   (Joseph, 2026-09-25: Music, Live, Watch). The photo is 118% tall, so a lift
   up to about 40vh still reaches the bottom of the hero. */
@media (min-width: 900px) { .cover-bg img { translate: 0 calc(-1 * var(--lift, 0px)); } }
.cover-drift::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--bush) 60%, transparent) 0%,
    color-mix(in srgb, var(--bush) 8%, transparent) 26%,
    color-mix(in srgb, var(--bush) 30%, transparent) 55%,
    color-mix(in srgb, var(--bush) 92%, transparent) 100%);
}
.cover-home .cover-drift::after {
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--bush) 55%, transparent) 0%, transparent 20%),
    linear-gradient(0deg, var(--bush) 0%, color-mix(in srgb, var(--bush) 80%, transparent) 26%, transparent 60%);
}
.cover-text { position: relative; z-index: 1; text-shadow: 0 1px 2px rgba(0,0,0,.35), 0 2px 22px rgba(0,0,0,.5); }
.cover-text .btn, .cover-text .pill { text-shadow: none; }
.cover-dim .cover-bg img { filter: brightness(0.62) contrast(1.08); }
.hero-logo { margin: 0 0 0.6rem; width: min(560px, 84vw); }
.hero-logo img { width: 100%; height: auto; filter: drop-shadow(0 6px 30px rgba(0,0,0,.45)); transform-origin: 0 0; }
/* Home: the header logo waits until the cover's big logo has shrunk up into
   its place (site.js), then takes over. html.dock-soon (set in <head>) hides
   it from first paint, before site.js has measured. */
.js-dock .site-header .logo, .dock-soon:has(.hero-logo) .site-header .logo { opacity: 0; }
/* Where scroll-driven animations exist (site.js adds sd-dock), the browser
   runs the whole hand-off against the real scroll position, so it stays
   smooth however fast you scroll: the big logo follows @keyframes tgb-dock
   (written by site.js from measurements) over the first --dock-d of scroll
   and vanishes at the end; the header logo appears at that same instant;
   the bar fades in between --bar-start and --bar-end (site.js barRange). */
@property --solid { syntax: '<number>'; inherits: true; initial-value: 0; }
@supports (animation-timeline: scroll()) {
  .sd-dock .hero-logo img {
    animation: tgb-dock linear both, dock-hide linear both;
    animation-timeline: scroll(root), scroll(root);
    animation-range: 0px var(--dock-d), calc(var(--dock-d) - 6px) var(--dock-d);
  }
  .sd-dock .site-header .logo {
    animation: dock-show linear both;
    animation-timeline: scroll(root);
    animation-range: calc(var(--dock-d) - 6px) var(--dock-d);
  }
  .sd-dock .site-header {
    animation: bar-solid ease-in-out both;
    animation-timeline: scroll(root);
    animation-range: var(--bar-start) var(--bar-end);
  }
}
/* ⚠ The hand-off is an opacity crossfade over the journey's last 6px, not a
   visibility switch: visibility animates on the main thread, so on a fast
   flick the logo rode on up past the header with the page and popped back.
   Opacity, like the transform, stays on the compositor. */
@keyframes dock-hide { from { opacity: 1; } to { opacity: 0; } }
@keyframes dock-show { from { opacity: 0; } to { opacity: 1; } }
@keyframes bar-solid { from { --solid: 0; } to { --solid: 1; } }
/* The big logo rides above the header (z 41 vs 40) while it docks, so the bar
   fading in behind it never dims it. The cover's other words stay below. */
.cover-home .cover-text { z-index: auto; }
.cover-home .cover-text > * { position: relative; z-index: 1; }
.cover-home .cover-text > .hero-logo { z-index: 41; }
.js-dock.logo-docked .site-header .logo { opacity: 1; }
.logo-docked .hero-logo img { opacity: 0; }
.page-title { font-size: clamp(3rem, 8vw, 6.4rem); line-height: 0.95; margin-bottom: 0.2em; }
.cover-line { font-family: var(--display); font-size: clamp(1.2rem, 2.2vw, 1.7rem); line-height: 1.3; margin: 0; color: color-mix(in srgb, var(--cream) 92%, transparent); max-width: 40rem; }
.cover .eyebrow { color: var(--ochre-light); }
.cover .btn-ghost { color: var(--cream); border-color: color-mix(in srgb, var(--cream) 50%, transparent); }
.cover .btn-ghost:hover { color: var(--ochre-light); border-color: var(--ochre-light); }
.hero-award { margin: 1.4rem 0 0; }
@media (max-width: 760px) {
  /* Inner-page covers: shorter on phones, and the photo is sized to the cover
     rather than the whole screen (it is fixed, so it would otherwise always be
     cropped to full phone height). */
  .cover:not(.cover-home) { min-height: 50svh; padding-bottom: 2.2rem; }
  .cover:not(.cover-home) .cover-bg { bottom: auto; height: 50svh; }
  .cover:not(.cover-home) .cover-bg img { height: 110%; }
  /* Home on phones. The band photo is wide and the band fills its width, so
     a full-height crop showed only two of the five, and the whole 3:2 photo
     felt too small: at 4:3 it keeps all five in view. It runs up under the
     logo and menu (Joseph): the photo's own dark ceiling and stage lights sit
     behind them, placed so the band's heads (about 19.5% down the photo, so
     14.6vw at this width) start just below the logo; only the status bar
     area above fades to dark. (A blurred copy filling that space was tried:
     un-blurred enough to look right, it showed a ghost of the band.) Not full
     screen, so the iOS toolbar strip needs no special treatment either. */
  .cover-home { display: block; min-height: 0; padding: 0 0 4.5rem; background: var(--bush); }
  html:has(.cover-home) { background: #120904; } /* the rubber band continues the photo's black */
  .cover-home .cover-bg {
    position: relative; inset: auto;
    height: calc(env(safe-area-inset-top, 0px) + 84px + 60.4vw);
    background: #120904; /* the photo's ceiling, so the top fade is seamless */
  }
  .cover-home .cover-bg img {
    position: absolute; left: 0; bottom: 0; width: 100%; height: 75vw;
    object-position: 48% 50%; animation: none;
    -webkit-mask-image: linear-gradient(transparent, #000 14%);
    mask-image: linear-gradient(transparent, #000 14%);
  }
  .cover-home .cover-drift { animation: none; }
  .cover-home .cover-drift::after { background: linear-gradient(180deg, transparent 80%, var(--bush) 100%); }
  /* The big logo sits at the top, level with the menu button, in the space
     the header logo will take. (It shrinks into it as you scroll: site.js.) */
  .cover-home .cover-text { position: static; margin-top: 1rem; }
  .cover-home .hero-logo {
    position: absolute; z-index: 41; margin: 0; width: min(58vw, 300px);
    top: calc(env(safe-area-inset-top, 0px) + 6px);
    left: max(var(--gutter), env(safe-area-inset-left, 0px));
  }
}
/* Home on a computer: the logo sits up in the dark ceiling, above the band's
   heads (about 27% down the screen at any size), with the tagline and
   buttons still at the foot. Sized so its bottom clears the heads on short
   screens too. */
@media (min-width: 761px) {
  .cover-home .cover-text { position: static; }
  .cover-home .hero-logo {
    position: absolute; z-index: 41; margin: 0;
    top: calc(env(safe-area-inset-top, 0px) + 76px + 1vh);
    left: calc(max(0px, (100% - 1200px) / 2) + max(var(--gutter), env(safe-area-inset-left, 0px)));
    width: clamp(300px, calc((26vh - 90px) * 3.42), 520px);
  }
}
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .cover-drift { animation: cover-drift linear both; animation-timeline: scroll(root); animation-range: 0 100vh; will-change: transform; }
    @keyframes cover-drift { to { transform: translateY(-10vh); } }
  }
}
/* Hero lines: CSS-only fake spring (text-effects.md §2), no script needed. */
@media (prefers-reduced-motion: no-preference) {
  @keyframes hero-rise {
    0% { opacity: 0; transform: translateY(50px) scale(0.5); }
    60% { opacity: 1; transform: translateY(-3px) scale(1.02); }
    100% { opacity: 1; transform: none; }
  }
  .cover-text > * { animation: hero-rise 0.7s var(--ease) both; transform-origin: left center; }
  .cover-text > :nth-child(2) { animation-delay: 0.08s; }
  .cover-text > :nth-child(3) { animation-delay: 0.16s; }
  .cover-text > :nth-child(4) { animation-delay: 0.24s; }
  .cover-text > :nth-child(5) { animation-delay: 0.32s; }
  .cover-text > :nth-child(6) { animation-delay: 0.4s; }
}

/* Everything after the cover rides over it on its own opaque ground. */
.after-cover { position: relative; z-index: 1; background: var(--sand); }

/* ── Bands ─────────────────────────────────────────────────────────────── */
.band { background: var(--bg); color: var(--fg); padding-block: clamp(4.5rem, 10vw, 8rem); position: relative; overflow-x: clip; }
.dark {
  --bg: var(--bush);
  --fg: var(--cream);
  --fg-dim: color-mix(in srgb, var(--cream) 70%, transparent);
  --card: var(--bush-2);
  --line: color-mix(in srgb, var(--cream) 14%, transparent);
  --accent: var(--ochre-light);
  --string: var(--teal-light);
  color-scheme: dark;
  background: var(--bg); color: var(--fg);
}
.pale { --bg: var(--sand-2); --card: #fffaf1; }
.band-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 1rem; flex-wrap: wrap; margin-bottom: 2.4rem; }
.band-head h2 { margin-bottom: 0; }

.split { display: grid; gap: clamp(2.5rem, 6vw, 5.5rem); align-items: center; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); }
.split-even { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
.split-bio { grid-template-columns: minmax(0, 1.35fr) minmax(0, 0.8fr); align-items: start; }
.split-album { grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); align-items: start; }
.split-past { grid-template-columns: minmax(0, 0.7fr) minmax(0, 1.3fr); align-items: start; }
.split-signup, .split-single { grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); }
@media (max-width: 899px) {
  .split, .split-even, .split-bio, .split-album, .split-past, .split-signup, .split-single { grid-template-columns: 1fr; }
}
@media (min-width: 900px) {
  .split-past > div:first-child, .album-side { position: sticky; top: 110px; }
}

/* ── Five strings ──────────────────────────────────────────────────────── */
/* Five fine lines: five players, and a five-string banjo (the top one is the
   short drone string). At rest they lie flat; a pluck is a damped wobble,
   scaling each gently bowed path through zero and back. site.js replays it
   on view, tap and mouse-over. */
.strings { display: grid; gap: 6px; max-width: 360px; margin: 0.2rem 0 1.8rem; }
.strings svg { display: block; width: 100%; height: 12px; overflow: visible; }
.strings path {
  fill: none; stroke: var(--string); stroke-width: 1.4; stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  transform-box: view-box; transform-origin: 50% 50%;
  transform: scaleY(0.001);
}
.strings-hero { max-width: min(560px, 80vw); margin: 0.4rem 0 1.4rem; --string: color-mix(in srgb, var(--cream) 70%, transparent); }
.strings-short { max-width: 220px; }
.strings-center { margin-inline: auto; }
@media (prefers-reduced-motion: no-preference) {
  @keyframes pluck {
    0% { transform: scaleY(0.001); }
    7% { transform: scaleY(1); }
    20% { transform: scaleY(-0.72); }
    34% { transform: scaleY(0.5); }
    50% { transform: scaleY(-0.3); }
    66% { transform: scaleY(0.16); }
    82% { transform: scaleY(-0.06); }
    100% { transform: scaleY(0.001); }
  }
  /* Same steps, second name, so a replay (site.js) restarts the pluck. */
  @keyframes pluck-again {
    0% { transform: scaleY(0.001); }
    7% { transform: scaleY(1); }
    20% { transform: scaleY(-0.72); }
    34% { transform: scaleY(0.5); }
    50% { transform: scaleY(-0.3); }
    66% { transform: scaleY(0.16); }
    82% { transform: scaleY(-0.06); }
    100% { transform: scaleY(0.001); }
  }
  .strings path { animation-duration: 1.7s; animation-timing-function: linear; animation-fill-mode: both; animation-delay: calc(var(--i) * 70ms); }
  .strings.fx-in path, .strings-hero path { animation-name: pluck; }
  .strings-hero path { animation-delay: calc(0.7s + var(--i) * 80ms); }
  .strings.plucked path { animation-name: pluck-again; animation-delay: calc(var(--i) * 50ms); }
  /* While music plays, site.js moves the strings with it; the plucks wait. */
  .strings-live .strings path { animation: none; }
}

/* ── River divider ─────────────────────────────────────────────────────── */
.river { height: clamp(40px, 6vw, 70px); padding-inline: var(--gutter); max-width: 1200px; margin-inline: auto; }
.river svg { width: 100%; height: 100%; overflow: visible; }
.river path { fill: none; stroke: var(--teal); stroke-width: 2; stroke-linecap: round; vector-effect: non-scaling-stroke; }

/* ── Prints: photos with a paper border, like prints pinned up ─────────── */
.print { margin: 0; background: #fffaf1; padding: 10px 10px 0; border-radius: 4px; box-shadow: 0 30px 60px -30px rgba(29,42,34,.55), 0 2px 6px rgba(29,42,34,.12); }
.print img { width: 100%; border-radius: 2px; }
.print figcaption { font: 500 0.82rem/1.3 var(--mono); color: color-mix(in srgb, var(--bush) 65%, transparent); padding: 0.7rem 0.2rem 0.8rem; }
.print:not(:has(figcaption)) { padding-bottom: 10px; }
.print-tilt { transform: rotate(-1.6deg); }
.print-tilt-r { transform: rotate(1.4deg); }
.dark .print { background: var(--cream); }

/* ── Albums ────────────────────────────────────────────────────────────── */
.album-pair { display: grid; gap: clamp(1.6rem, 4vw, 3rem); grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 760px) { .album-pair { grid-template-columns: 1fr; } }
.album-card { display: grid; gap: 1.4rem; align-content: start; }
/* Computers: smaller covers, so the title, blurb and buttons fit on screen
   with them. */
@media (min-width: 900px) { .album-card .album-art { width: min(100%, 360px); } }
.album-card .album-art { display: block; border-radius: 6px; overflow: hidden; aspect-ratio: 1; box-shadow: 0 40px 80px -40px #000; }
.album-card .album-art img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.9s var(--ease); }
.album-card:hover .album-art img { transform: scale(1.04); }
.album-card h3 { font-size: clamp(1.8rem, 3vw, 2.4rem); margin-bottom: 0.4rem; }
.album-year { font: 500 0.85rem/1 var(--mono); color: var(--accent); margin: 0 0 0.5rem; letter-spacing: 0.08em; }
.award-line { margin: 0.2rem 0 1rem; }
.album-art { margin: 0; }
.album-feature .album-art img { border-radius: 6px; width: 100%; box-shadow: 0 40px 80px -40px rgba(0,0,0,.7); }
.album-art figcaption { font: 500 0.8rem/1.3 var(--mono); color: var(--fg-dim); margin-top: 0.6rem; }
.cd-shot { margin: 2rem 0 0; }
.cd-shot img { border-radius: 6px; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.formats { list-style: none; margin: 1.6rem 0 0; padding: 0; border-top: 1px solid var(--line); }
/* Bandcamp's own player, for an album not yet in the site's (music/index.astro). */
.bc-player { display: block; width: 100%; height: 120px; border: 0; border-radius: 10px; margin: 1.2rem 0 0; color-scheme: normal; }
.formats li { display: flex; justify-content: space-between; gap: 1rem; padding: 0.8rem 0; border-bottom: 1px solid var(--line); }
.formats li > span:first-child { display: grid; }
.formats .dim { font-size: 0.9rem; }
.price { font: 500 1rem/1.4 var(--mono); white-space: nowrap; }
.liner { margin: 0.4rem 0 1.4rem; }
.more summary { cursor: pointer; font-weight: 650; color: var(--accent); list-style: none; display: inline-flex; gap: 0.45em; align-items: center; margin-bottom: 1rem; }
.more summary::-webkit-details-marker { display: none; }
.more summary::after { content: '+'; font-family: var(--mono); }
.more[open] summary::after { content: '–'; }
.tracks { margin: 0; padding: 0; list-style: none; counter-reset: t; }
.tracks li { counter-increment: t; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; gap: 1rem; padding: 0.6rem 0; border-bottom: 1px solid var(--line); }
.tracks li > :first-child::before { content: counter(t, decimal-leading-zero); color: var(--accent); font: 500 0.82em var(--mono); margin-right: 1rem; }
.tracks-hint { margin: 0.9rem 0 0; }
.tracks-tuned li { grid-template-columns: minmax(0, 1fr) auto auto; }
.tuning { font: 500 0.78rem/1 var(--mono); color: var(--teal-light); background: color-mix(in srgb, var(--teal) 30%, transparent); padding: 0.3rem 0.5rem; border-radius: 6px; letter-spacing: 0.04em; }
.band:not(.dark) .tuning { color: var(--teal); background: color-mix(in srgb, var(--teal) 12%, transparent); }
.tuning-key { font-weight: 400; font-size: 0.9rem; }
.dur { font: 400 0.9rem/1 var(--mono); color: var(--fg-dim); }
.credits, .ticks { margin: 0; padding: 0; list-style: none; }
.credits li, .ticks li { padding: 0.45rem 0 0.45rem 1.5rem; position: relative; }
.ticks li::before, .credits li::before { content: ''; position: absolute; left: 0; top: 1.05rem; width: 0.7rem; height: 1.5px; background: var(--accent); }
.track-notes { display: grid; gap: 1rem; margin-top: 1.6rem; }
.ack-note { margin-top: 2rem; font-size: 0.95rem; color: var(--fg-dim); font-style: italic; }

/* ── Pill with a glint (text-effects.md §5: overlay adds light, never a mask) */
.pill { display: inline-block; position: relative; overflow: hidden; padding: 0.6rem 1.1rem; border-radius: 999px; background: var(--pink); color: var(--brown); font: 700 0.8rem/1 var(--body); letter-spacing: 0.1em; text-transform: uppercase; }
@media (prefers-reduced-motion: no-preference) {
  .glint::after {
    content: ''; position: absolute; inset: 0; pointer-events: none;
    background: linear-gradient(100deg, transparent 35%, rgba(255, 255, 255, 0.55) 50%, transparent 65%);
    background-size: 300% 100%;
    animation: glint 4.5s 1.2s linear infinite both;
  }
  @keyframes glint { 0% { background-position: 150% 0; } 30%, 100% { background-position: -50% 0; } }
}

/* ── Gigs ──────────────────────────────────────────────────────────────── */
.gig-grid { display: grid; gap: 1.4rem; grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr)); }
.gig-list { display: grid; gap: 1.2rem; }
.gig {
  position: relative; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 0 1.2rem; padding: 1.4rem;
}
.gig-date { display: grid; justify-items: center; min-width: 3.4rem; padding: 0.5rem 0.3rem; border-radius: 10px; background: color-mix(in srgb, var(--ochre) 14%, transparent); color: var(--ochre-deep); line-height: 1; }
.gd { font-family: var(--display); font-size: 2rem; }
.gm { font-size: 0.75rem; letter-spacing: 0.14em; text-transform: uppercase; font-weight: 700; margin-top: 0.25rem; }
.gig-when { font-size: 0.82rem; letter-spacing: 0.06em; text-transform: uppercase; font-weight: 650; color: var(--accent); margin: 0; }
.gig-venue, .gig-place { margin: 0; font-size: 0.93rem; color: var(--fg-dim); }
.empty-card {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1.4rem 2rem;
  padding: clamp(1.6rem, 4vw, 2.6rem); border-radius: var(--radius);
  background: var(--card); border: 1.5px dashed color-mix(in srgb, var(--teal) 45%, transparent);
}
.empty-card h3 { font-size: clamp(1.5rem, 2.6vw, 2rem); }
.empty-card p { margin: 0; max-width: 34rem; color: var(--fg-dim); }
.empty-card .actions { margin-top: 0; }

.past-year { margin-bottom: 2.2rem; }
.past-y { font-size: 2.4rem; color: var(--accent); border-bottom: 1px solid var(--line); padding-bottom: 0.4rem; margin-bottom: 0.4rem; }
.past-list { list-style: none; margin: 0; padding: 0; }
.past-row { display: grid; grid-template-columns: 7.5rem minmax(0, 1fr); gap: 0.1rem 1rem; padding: 0.8rem 0; border-bottom: 1px solid var(--line); }
.past-date { font: 500 0.86rem/1.5 var(--mono); color: var(--fg-dim); grid-row: span 2; padding-top: 0.1rem; }
.past-where { color: var(--fg-dim); font-size: 0.93rem; }
.past-tour { display: block; }
.past-tour summary { display: grid; grid-template-columns: 7.5rem minmax(0, 1fr); gap: 0.1rem 1rem; cursor: pointer; list-style: none; }
.past-tour summary::-webkit-details-marker { display: none; }
.past-tour summary .past-what strong::after { content: ' +'; font-family: var(--mono); color: var(--accent); }
.past-tour details[open] summary .past-what strong::after { content: ' –'; }
.tour-list { margin: 0.6rem 0 0 1.2rem; padding-left: 1rem; border-left: 2px solid color-mix(in srgb, var(--accent) 50%, transparent); }
.tour-list .past-row { grid-template-columns: 6.3rem minmax(0, 1fr); padding: 0.55rem 0; }
.tour-list .past-row:last-child { border-bottom: 0; }
@media (max-width: 520px) {
  .past-row, .past-tour summary { grid-template-columns: 5.6rem minmax(0, 1fr); }
  .tour-list .past-row { grid-template-columns: 4.8rem minmax(0, 1fr); }
}

/* ── Quotes ────────────────────────────────────────────────────────────── */
.quote { margin: 0; position: relative; }
.quote blockquote { margin: 0; }
.quote p { margin: 0; font-family: var(--display); line-height: 1.3; }
.quote figcaption { margin-top: 1rem; font: 500 0.8rem/1.4 var(--mono); letter-spacing: 0.04em; color: var(--fg-dim); }
.quote-small { padding: 1.2rem 1.4rem; border-radius: var(--radius); background: var(--card); border: 1px solid var(--line); }
.quote-small p { font-size: 1.05rem; }
.quote-aside { margin-top: 2rem; }
.quote-aside p { font-size: clamp(1.3rem, 2vw, 1.6rem); }
.quote-aside p::before { content: '“'; color: var(--ochre); }
.quote-aside p::after { content: '”'; color: var(--ochre); }
.quotes-grid { display: grid; gap: clamp(2rem, 5vw, 4rem); grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 760px) { .quotes-grid { grid-template-columns: 1fr; } }
.quote-big p { font-size: clamp(1.35rem, 2.3vw, 1.85rem); }
.quote-big p::before { content: '“'; display: block; font-size: 4.5rem; line-height: 0.7; color: var(--ochre); margin-bottom: 0.05em; }
.quote-wall { display: grid; gap: 1.4rem; grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); }
.quote-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.6rem; }
.quote-card p { font-size: 1.25rem; }

/* ── About ─────────────────────────────────────────────────────────────── */
.bio-side { display: grid; gap: 1rem; }
.players { display: grid; gap: 1.2rem; grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr)); margin-top: 2.4rem; }
.player { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.5rem; }
.player .icon { width: 56px; height: 56px; fill: none; stroke: var(--pink); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; margin-bottom: 1rem; transition: transform 0.5s var(--ease); }
.player:hover .icon { transform: rotate(-8deg) scale(1.06); }
.player h3 { margin-bottom: 0.2rem; }
.player-role { font: 500 0.82rem/1.3 var(--mono); color: var(--accent); margin-bottom: 0.8rem; }
.player p:last-child { margin: 0; font-size: 0.96rem; color: var(--fg-dim); }
.story { display: grid; gap: 1.2rem; grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr)); margin-top: 2.4rem; }
.story-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.5rem; position: relative; overflow: hidden; }
.story-card::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: linear-gradient(90deg, var(--teal), var(--ochre)); }
.story-n { font: 500 0.8rem/1 var(--mono); color: var(--accent); display: block; margin-bottom: 1rem; }
.story-card p { margin: 0; }
.timeline { list-style: none; margin: 2.4rem 0 0; padding: 0; display: grid; gap: 1.2rem; grid-template-columns: repeat(auto-fit, minmax(min(100%, 180px), 1fr)); }
.timeline li { border-top: 2px solid var(--teal); padding-top: 1rem; }
.year { font-family: var(--display); font-size: 2.6rem; line-height: 1; color: var(--ochre-deep); display: block; margin-bottom: 0.6rem; }
.timeline p { margin: 0; }
.award-block { display: flex; gap: 1.4rem; align-items: center; margin-top: 3.4rem; padding: 1.6rem 2rem; border-radius: var(--radius); background: var(--pink); color: var(--brown); max-width: 44rem; }
.award-star { font-size: 3rem; line-height: 1; }
.award-block p { margin: 0; }
.award-big { font-family: var(--display); font-size: clamp(1.6rem, 3vw, 2.2rem); line-height: 1.1; }
.award-label { font-weight: 650; margin-bottom: 0.3rem !important; }
.award-block .dim { color: color-mix(in srgb, var(--brown) 80%, transparent); font-size: 0.93rem; }

/* ── Video ─────────────────────────────────────────────────────────────── */
.yt-card { margin: 0; }
.yt { position: relative; display: block; width: 100%; padding: 0; border: 0; cursor: pointer; aspect-ratio: 16 / 9; border-radius: var(--radius); overflow: hidden; background: #000; }
.yt img { width: 100%; height: 100%; object-fit: cover; opacity: 0.88; transition: transform 0.8s var(--ease), opacity 0.4s; }
.yt:hover img { transform: scale(1.03); opacity: 1; }
/* Play: a pill in the bottom-left corner, not a disc in the middle, because
   the middle of a music-video thumbnail is almost always someone's face. */
.yt::after { content: ''; position: absolute; inset: 55% 40% 0 0; background: radial-gradient(ellipse at 0% 100%, rgba(0,0,0,.55), transparent 70%); pointer-events: none; }
.yt-play {
  position: absolute; left: 0.9rem; bottom: 0.9rem; z-index: 1;
  display: inline-flex; align-items: center; gap: 0.45rem;
  padding: 0.5rem 1rem 0.5rem 0.7rem; border-radius: 999px;
  background: var(--ochre); color: #fff8ee;
  font: 700 0.9rem/1 var(--body); letter-spacing: 0.02em;
  box-shadow: 0 6px 20px -6px rgba(0,0,0,.6);
  transition: transform 0.3s var(--ease);
}
.yt:hover .yt-play { transform: translateY(-2px); }
.yt-play svg { width: 18px; height: 18px; fill: currentColor; }
.yt-big .yt-play { left: 1.2rem; bottom: 1.2rem; padding: 0.7rem 1.3rem 0.7rem 1rem; font-size: 1rem; }
.yt-big .yt-play svg { width: 22px; height: 22px; }
.yt iframe {
  position: absolute; inset: 0; z-index: 2; width: 100%; height: 100%; border: 0;
  /* ⚠ The flash. When an iframe's color-scheme differs from its parent's,
     browsers paint an opaque backdrop behind it until it draws. YouTube's
     player is light; declaring it light stops that on the dark bands, and it
     stays hidden over our thumbnail until it has painted (site.js). */
  color-scheme: light;
  background: transparent;
  opacity: 0;
  transition: opacity 0.5s var(--ease);
}
.yt iframe.ready { opacity: 1; }
.yt-card figcaption { margin-top: 0.8rem; display: grid; gap: 0.2rem; }
.yt-title { font-weight: 600; }
.yt-note { font: 400 0.82rem/1.4 var(--mono); color: var(--fg-dim); }
.yt-big { margin-bottom: 3rem; }
.yt-big .yt-title { font-family: var(--display); font-size: 1.4rem; font-weight: 400; }
.yt-grid { display: grid; gap: 1.8rem 1.6rem; grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr)); margin-bottom: 1.5rem; }

/* ── Booking ───────────────────────────────────────────────────────────── */
.facts { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.6rem 1.8rem; }
.facts .small-h { margin-top: 0; }
.bio-boxes { display: grid; gap: 1.2rem; margin-top: 2rem; }
.bio-box { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.4rem 1.6rem; }
.bio-box-head { display: flex; justify-content: space-between; align-items: center; gap: 1rem; margin-bottom: 0.8rem; }
.bio-box-head h3 { margin: 0; }
.bio-box-text p:last-child { margin-bottom: 0; }
.photo-grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(min(100%, 230px), 1fr)); margin-top: 2rem; }
.photo-grid figure { margin: 0; }
.photo-grid img { aspect-ratio: 4 / 3; object-fit: cover; width: 100%; border-radius: 8px; }
.photo-grid figcaption { font: 400 0.76rem/1.35 var(--mono); color: var(--fg-dim); margin-top: 0.4rem; }

/* ── Signup ────────────────────────────────────────────────────────────── */
.signup { margin-top: 1.6rem; }
.field-row { display: grid; grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); gap: 0.9rem; }
@media (max-width: 560px) { .field-row { grid-template-columns: 1fr; } }
.field { display: grid; gap: 0.35rem; font-size: 0.88rem; font-weight: 600; min-width: 0; }
.field i { font-weight: 400; color: var(--fg-dim); font-style: normal; }
.field input, .field textarea {
  font: inherit; font-size: 1.05rem; font-weight: 400; color: var(--fg);
  width: 100%; min-width: 0; box-sizing: border-box; /* else an input keeps its default ~20ch width and spills into the next field */
  min-height: 52px; padding: 0.7rem 1rem; border-radius: 12px;
  background: var(--card); border: 1.5px solid var(--line);
  transition: border-color 0.25s, box-shadow 0.25s;
}
.field input:focus, .field textarea:focus { outline: none; border-color: var(--teal); box-shadow: 0 0 0 4px color-mix(in srgb, var(--teal) 22%, transparent); }
.signup-foot { display: flex; flex-wrap: wrap; gap: 0.9rem; align-items: center; margin-top: 1rem; }
.signup-foot .cf-turnstile { flex: 1 1 260px; min-height: 65px; }
.form-msg { min-height: 1.5em; margin: 0.8rem 0 0.3rem; font-weight: 600; }
.form-msg.ok { color: #2f7a4a; }
.form-msg.err { color: #b3261e; }
/* After a successful signup the fields fold away and the message stays, as a
   panel (Joseph, 2026-09-25). */
.signup.is-done > :not(.form-msg) { display: none; }
.signup.is-done .form-msg {
  margin: 0; padding: 1.1rem 1.3rem; border-radius: var(--radius);
  background: color-mix(in srgb, var(--teal) 12%, var(--card)); border: 1px solid color-mix(in srgb, var(--teal) 35%, transparent);
  font: 400 clamp(1.15rem, 2vw, 1.4rem)/1.4 var(--display); color: var(--fg);
}
.signup.is-done .form-msg:focus { outline: none; }
.signup-done .hide-when-done { display: none; }
.signup.sending button { opacity: 0.6; pointer-events: none; }
.field textarea { resize: vertical; min-height: 130px; line-height: 1.5; }
.enquiry .field-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
@media (max-width: 560px) { .enquiry .field-row { grid-template-columns: 1fr; } }
.enquiry > .field { margin-top: 0.9rem; }

/* ── Footer ────────────────────────────────────────────────────────────── */
.site-footer { position: relative; z-index: 1; }
.footer-main { background: var(--bg); color: var(--fg); padding-block: 4rem calc(6rem + env(safe-area-inset-bottom, 0px)); }
.footer-main .logo { position: relative; }
.footer-grid { display: grid; gap: 2.5rem; grid-template-columns: minmax(0, 1.4fr) minmax(0, 0.6fr) minmax(0, 1fr); }
@media (max-width: 760px) { .footer-grid { grid-template-columns: 1fr; } }
.footer-grid nav { display: grid; gap: 0.5rem; align-content: start; }
.footer-grid nav a, .footer-links a { text-decoration: none; }
.footer-links { display: flex; flex-wrap: wrap; gap: 0.5rem 1.1rem; margin-bottom: 1.4rem; }
.footer-h { font: 700 0.75rem/1 var(--body); letter-spacing: 0.16em; text-transform: uppercase; color: var(--ochre-light); margin: 0 0 0.8rem; }
.footer-ack { margin-top: 1.2rem; color: var(--fg-dim); max-width: 32rem; font-size: 0.95rem; }
.footer-small { margin-top: 3rem; font-size: 0.82rem; color: var(--fg-dim); }
/* Site credit (Footer.astro): quiet, bottom right, follows the dim footer text. */
.footer-bottom { display: flex; flex-wrap: wrap; margin-top: 3rem; color: var(--fg-dim); }
.site-footer .credit { position: relative; margin-left: auto; color: inherit; display: block; line-height: 0; }
.site-footer .credit:hover, .site-footer .credit:focus-visible { color: var(--fg); }
.site-footer .credit svg { height: 1.9em; width: auto; aspect-ratio: 2144 / 2016; display: block; flex: none; }
.credit-tip { position: absolute; right: 0; bottom: calc(100% + 0.5rem); white-space: nowrap; font: 500 0.78rem/1 var(--body); letter-spacing: 0.02em; padding: 0.45rem 0.6rem; border-radius: 6px; background: var(--fg); color: var(--bg); opacity: 0; pointer-events: none; }
.credit:hover .credit-tip, .credit:focus-visible .credit-tip { opacity: 1; }
@media (prefers-reduced-motion: no-preference) { .credit-tip { transition: opacity 0.2s; } }

/* ── The mock-up pill and source pins ──────────────────────────────────── */
.mock-pill {
  position: fixed; z-index: 70; left: 50%; transform: translateX(-50%);
  bottom: calc(14px + env(safe-area-inset-bottom, 0px));
  display: flex; align-items: center; gap: 0.7rem; max-width: calc(100% - 24px);
  padding: 0.45rem 0.5rem 0.45rem 1rem; border-radius: 999px;
  background: color-mix(in srgb, #141d17 90%, transparent); color: var(--cream);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border: 1px solid color-mix(in srgb, var(--ochre-light) 35%, transparent);
  font-size: 0.82rem; box-shadow: 0 16px 40px -16px #000;
}
.mock-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ochre-light); flex: none; box-shadow: 0 0 0 4px color-mix(in srgb, var(--ochre-light) 25%, transparent); }
.mock-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mock-pill a { color: var(--ochre-light); font-weight: 600; text-decoration: none; padding-right: 0.5rem; }
.notes-toggle { font: 600 0.8rem/1 var(--body); color: var(--bush); background: var(--pink); border: 0; border-radius: 999px; padding: 0.55rem 0.9rem; cursor: pointer; white-space: nowrap; }
.notes-toggle[aria-pressed='true'] { background: var(--ochre); color: #fff; }
@media (max-width: 560px) { .mock-text { display: none; } }

.pins { position: absolute; top: 6px; right: 6px; z-index: 30; display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 4px; max-width: 70%; pointer-events: none; }
.pin {
  pointer-events: auto; position: relative;
  font: 700 10.5px/1 var(--body); letter-spacing: 0.04em; text-decoration: none;
  padding: 4px 7px; border-radius: 999px; white-space: nowrap;
  background: var(--teal-light); color: #13201a !important; border: 1px solid rgba(0,0,0,.25);
  box-shadow: 0 2px 8px rgba(0,0,0,.3);
}
.pin:hover { background: #fff; }
.pin-flag { background: #ffb020; cursor: help; }
.pin-flag::before { content: '⚠ '; }
.pin-img { background: #c9b8ff; }
.pin-tip {
  display: none; position: absolute; right: 0; top: calc(100% + 6px); width: min(300px, 80vw);
  white-space: normal; text-transform: none; letter-spacing: 0; font-weight: 500; font-size: 13px; line-height: 1.4;
  padding: 10px 12px; border-radius: 10px; background: #13201a; color: var(--cream); box-shadow: 0 12px 30px rgba(0,0,0,.5);
}
.pin:hover .pin-tip, .pin:focus .pin-tip, .pin:focus-within .pin-tip { display: block; }
.pin.static { position: static; display: inline-block; }
.notes-on [data-src], .notes-on [data-flag], .notes-on [data-img] { outline: 1px dashed color-mix(in srgb, #ffb020 70%, transparent); outline-offset: 4px; }
.notes-on .has-pins { position: relative; }
.notes-on .cover.has-pins > .pins { top: 90px; }

/* ── Notes page ────────────────────────────────────────────────────────── */
.notes h2 { font-size: clamp(1.8rem, 3.4vw, 2.5rem); margin-top: 2.6rem; }
.notes h2:first-child { margin-top: 0; }
.notes ul li, .flag-list li { margin-bottom: 0.7rem; }
.table-scroll { overflow-x: auto; margin-top: 1.5rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--card); }
.register { border-collapse: collapse; width: 100%; min-width: 820px; font-size: 0.9rem; }
.register th, .register td { text-align: left; padding: 0.8rem; border-bottom: 1px solid var(--line); vertical-align: top; }
.register th { font-size: 0.75rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--accent); }
.register img { width: 96px; height: 72px; object-fit: cover; border-radius: 6px; }
.status { display: inline-block; font-weight: 700; font-size: 0.75rem; padding: 3px 8px; border-radius: 999px; background: var(--sand-3); margin-bottom: 0.3rem; }
.status-credited { background: #f3d2c4; color: #6b2a14; }
.status-band-unknown { background: #f5e3b0; color: #5a4208; }
.status-art { background: #cfe6dc; color: #1e4a3c; }
.source-list { columns: 2 320px; column-gap: 2.5rem; padding-left: 0; list-style: none; }
.source-list li { break-inside: avoid; padding: 0.35rem 0; font-size: 0.93rem; }
.source-list li:target { background: color-mix(in srgb, var(--ochre) 25%, transparent); border-radius: 6px; }
.sid { display: inline-block; min-width: 2.6rem; font: 500 0.85rem var(--mono); color: var(--accent); }

/* ── Scroll reveals (text-effects.md §3). ⚠ THE FAILSAFE: nothing here hides
   anything that lacks data-fx, and only fx.js sets data-fx, in the same breath
   as it starts watching the element. Every hidden state sits inside the
   reduced-motion guard (gotcha 8). The strings are never hidden: they only
   pluck. ──────────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
  [data-fx]:not([data-fx='pluck']) {
    transition: opacity 0.8s var(--ease), transform 0.8s var(--ease), filter 0.8s var(--ease);
    transition-delay: var(--fx-delay, 0s);
  }
  [data-fx='rise']:not(.fx-in) { opacity: 0; transform: translateY(40px); }
  [data-fx='from-left']:not(.fx-in) { opacity: 0; transform: translateX(-80px); }
  [data-fx='from-right']:not(.fx-in) { opacity: 0; transform: translateX(80px); }
  [data-fx='blur']:not(.fx-in) { opacity: 0; filter: blur(6px); }
  [data-fx='tilt']:not(.fx-in) { opacity: 0; transform: perspective(1200px) rotateX(18deg) translateY(30px); }
  /* Each word turns in while a mask sweeps across it, left to right, so its
     letters appear in order. Words stay unbroken runs of text, keeping the
     font's kerning, so nothing shifts when the plain heading comes back
     (fx.js splitLetters). */
  [data-fx='letters'] .fx-word {
    display: inline-block;
    -webkit-mask-image: linear-gradient(90deg, #000 40%, transparent 60%);
    mask-image: linear-gradient(90deg, #000 40%, transparent 60%);
    -webkit-mask-size: 250% 100%;
    mask-size: 250% 100%;
    -webkit-mask-position: 0 0;
    mask-position: 0 0;
    transition: transform 0.6s var(--ease), -webkit-mask-position 0.7s ease-out, mask-position 0.7s ease-out;
    transition-delay: min(calc(var(--i) * 18ms), 600ms);
  }
  [data-fx='letters']:not(.fx-in) .fx-word {
    transform: rotateY(90deg);
    -webkit-mask-position: 100% 0;
    mask-position: 100% 0;
  }
  .fx-word { white-space: nowrap; }
  [data-fx='draw'] path { stroke-dasharray: 1; stroke-dashoffset: 0; transition: stroke-dashoffset 2.2s var(--ease); }
  [data-fx='draw']:not(.fx-in) path { stroke-dashoffset: 1; }
  /* A print that slides in keeps its tilt. */
  .print-tilt-r[data-fx='from-right'].fx-in { transform: rotate(1.4deg); }
  .print-tilt-r[data-fx='from-right']:not(.fx-in) { transform: translateX(80px) rotate(1.4deg); }
}
@media print {
  [data-fx], [data-fx] .fx-word { opacity: 1 !important; transform: none !important; filter: none !important; -webkit-mask-image: none !important; mask-image: none !important; }
  .mock-pill, .site-header, body::after { display: none; }
  .cover-bg { position: absolute; }
}

@media (min-width: 900px) { #newsletter { scroll-margin-top: 56px; } }

/* ── The music player: site-player's player.css, loaded first ─────────
   Its colours and fonts, from ours. */
:root {
  --sp-bg: #141d17;
  --sp-fg: var(--cream);
  --sp-accent: var(--ochre);
  --sp-accent-deep: var(--ochre-deep);
  --sp-accent-light: var(--ochre-light);
  --sp-on-accent: #fff8ee;
  --sp-display: var(--display);
  --sp-mono: var(--mono);
  --sp-ease: var(--ease);
}
.album-more { margin: 1rem 0 0; }

/* ── News: past newsletters (/news/) ──────────────────────────────────── */
.news-cards { list-style: none; margin: 0; padding: 0; display: grid; gap: 1rem; }
.news-card a {
  display: block; padding: 1.4rem 1.6rem; border-radius: var(--radius); text-decoration: none; color: inherit;
  background: var(--card); border: 1px solid var(--line); transition: transform 0.25s var(--ease), border-color 0.25s;
}
.news-card a:hover { transform: translateY(-2px); border-color: var(--accent); }
.news-card .eyebrow { margin-bottom: 0.5rem; }
.news-card h3 { margin: 0 0 0.4rem; font: 400 clamp(1.25rem, 2.2vw, 1.5rem)/1.25 var(--display); }
.news-card p:last-child { margin: 0; color: var(--fg-dim); }
.news-body p, .news-body li { font-size: 1.08rem; line-height: 1.65; }
.news-body p { margin: 0 0 1.1rem; }
.news-body h2 { font-size: clamp(1.5rem, 3vw, 2.1rem); margin: 2.8rem 0 1rem; }
.news-body a:not(.btn) { color: var(--accent); }
.news-body .actions { margin: 1.4rem 0 1.8rem; }
.news-img { margin: 1.8rem 0; }
.news-img img { display: block; width: auto; max-width: 100%; max-height: 80vh; height: auto; margin-inline: auto; border-radius: var(--radius); }
.news-list { margin: 0 0 1.4rem; padding-left: 1.2rem; }
.news-list li { margin: 0.25rem 0; }
.news-body hr { border: 0; border-top: 1px solid var(--line); margin: 2.6rem 0; }
.news-body .yt-card { margin: 1.4rem 0 1.6rem; }
.news-sent { margin-top: 3rem !important; }
.news-nav { justify-content: space-between; }
/* Newsletters from cf-email's archive (worker/news.js) */
.news-gig { display: grid; gap: 1rem 1.4rem; margin: 1.8rem 0; padding: 1.2rem; border: 1px solid var(--line); border-radius: var(--radius); }
.news-gig figure { margin: 0; }
.news-gig img, .news-pictures img, .news-media img { display: block; width: 100%; height: auto; border-radius: var(--radius); }
.news-gig h3 { margin: 0 0 0.5rem; font: 400 clamp(1.25rem, 2.2vw, 1.5rem)/1.25 var(--display); }
.news-gig .eyebrow { margin-bottom: 0.4rem; }
.news-gig p:last-child { margin-bottom: 0; }
@media (min-width: 640px) { .news-gig:has(figure) { grid-template-columns: 40% 1fr; align-items: start; } }
.news-pictures { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 0.8rem; margin: 1.8rem 0; }
.news-pictures figure { margin: 0; }
.news-panel { margin: 1.8rem 0; padding: 1.2rem 1.4rem; border-left: 3px solid var(--accent); background: color-mix(in srgb, var(--accent) 7%, transparent); border-radius: 0 var(--radius) var(--radius) 0; }
.news-panel h3 { margin: 0 0 0.5rem; }
.news-panel p:last-child { margin-bottom: 0; }
.news-media { display: grid; gap: 1rem 1.4rem; margin: 1.8rem 0; }
.news-media figure { margin: 0; }
@media (min-width: 640px) { .news-media:has(figure) { grid-template-columns: 40% 1fr; align-items: start; } .news-media.right:has(figure) { grid-template-columns: 1fr 40%; } .news-media.right figure { order: 2; } }
.news-gig-when { margin-bottom: 0.4rem !important; font-size: 0.85rem !important; letter-spacing: 0.08em; text-transform: uppercase; color: var(--fg-dim); }
@media (min-width: 640px) { .news-media.news-media-right:has(figure) { grid-template-columns: 1fr 40%; } .news-media-right figure { order: 2; } }
.news-space[data-size="s"] { height: 0.8rem; } .news-space[data-size="m"] { height: 1.6rem; } .news-space[data-size="l"] { height: 3rem; }

/* ── Video lightbox (mouse devices; see site.js) ──────────────────────── */
.lightbox {
  /* The dialog fills the screen; the dimmed area around the video is the
     dialog itself, so a click on it closes the lightbox. */
  width: 100%; height: 100%; max-width: none; max-height: none; margin: 0;
  padding: 1.5rem max(var(--gutter), env(safe-area-inset-right));
  border: 0; background: transparent; color: var(--cream);
  display: grid; place-items: center;
}
.lightbox:not([open]) { display: none; }
.lightbox::backdrop {
  background: rgba(20, 29, 23, 0.92);
  backdrop-filter: blur(14px) saturate(1.1);
  -webkit-backdrop-filter: blur(14px) saturate(1.1);
}
html:has(.lightbox[open]) { overflow: hidden; }
.lb-inner { width: min(100%, 1280px, calc((100svh - 3rem - 4.5rem) * 16 / 9)); }
.lb-bar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1rem; }
.lb-title { margin: 0; font: 400 clamp(1.1rem, 2vw, 1.5rem)/1.25 var(--display); }
.lb-close {
  flex: none; display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.5rem 1rem 0.5rem 0.75rem; border-radius: 999px; cursor: pointer;
  border: 1px solid color-mix(in srgb, var(--cream) 20%, transparent); background: color-mix(in srgb, var(--cream) 6%, transparent);
  color: var(--cream); font: 600 0.9rem/1 var(--body);
  transition: background 0.2s, border-color 0.2s;
}
.lb-close:hover { background: color-mix(in srgb, var(--cream) 12%, transparent); border-color: var(--ochre-light); }
.lb-close svg { width: 16px; height: 16px; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; fill: none; }
.lb-frame {
  position: relative; aspect-ratio: 16 / 9; border-radius: var(--radius); overflow: hidden;
  background: #000; box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.8);
}
.lb-frame img { width: 100%; height: 100%; object-fit: cover; opacity: 0.6; }
.lb-frame iframe {
  position: absolute; inset: 0; width: 100%; height: 100%; border: 0;
  color-scheme: light; background: transparent; /* the flash: see .yt iframe */
  opacity: 0; transition: opacity 0.5s var(--ease);
}
.lb-frame iframe.ready { opacity: 1; }
@media (prefers-reduced-motion: no-preference) {
  .lightbox[open] .lb-inner { animation: lb-in 0.5s var(--ease); }
  .lightbox[open]::backdrop { animation: lb-fade 0.3s ease-out; }
}
@keyframes lb-in { from { opacity: 0; transform: translateY(14px) scale(0.97); } }
@keyframes lb-fade { from { opacity: 0; } }

/* ── Dark mode: follows the device's own setting ────────────────────────
   The sand pages become night bush and the text turns cream; the dark bands
   go a shade deeper so the rhythm between them survives; prints keep their
   paper borders. Last in the file so it wins. */
@media (prefers-color-scheme: dark) {
  :root {
    --sand: #18221c;
    --sand-2: #1e2a23;
    --sand-3: #2c3a31;
    --ink: #f0e6d2;
    --fg-dim: color-mix(in srgb, var(--ink) 72%, transparent);
    --line: color-mix(in srgb, var(--ink) 14%, transparent);
    --accent: var(--ochre-light);
    --string: var(--teal-light);
    color-scheme: dark;
  }
  .dark { --bg: #0f1612; --card: #18221c; }
  .pale { --bg: #1d2922; --card: #243129; }
  body::after { mix-blend-mode: normal; opacity: 0.05; }
  .year, .gig-date { color: var(--ochre-light); }
  .band:not(.dark) .tuning { color: var(--teal-light); background: color-mix(in srgb, var(--teal) 30%, transparent); }
  .river path, .timeline li { stroke: var(--teal-light); border-top-color: var(--teal-light); }
  :focus-visible { outline-color: var(--ochre-light); }
  .form-msg.ok { color: #8fd6a4; }
  .form-msg.err { color: #ff9c8a; }
}
