/* ==========================================================================
   COMPONENTS — the five collage motifs (keyhole, torn panel, wobbly edge,
   halftone, camo blobs), photo duotone, and every reusable UI widget
   (buttons, cards, embeds, lightbox, gig list, member cards, socials).
   The #keyhole clipPath and #wobble filter referenced below live once in
   the hidden <svg class="sprite"> at the top of index.html.
   ========================================================================== */

/* ---- MOTIF 1: keyhole mask --------------------------------------------
   Applied to any square-ish image (gallery thumbs, member portraits, gig
   flyers). Defined once as an objectBoundingBox clipPath in index.html. */
.keyhole {
  clip-path: url(#keyhole);
}

/* small heading-bullet version, drawn with a CSS mask so it can inherit
   whatever colour the heading is set in (currentColor) */
.h-mark {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.h-mark::before {
  content: "";
  display: inline-block;
  width: 0.55em;
  height: 0.8em;
  flex: 0 0 auto;
  background-color: currentColor;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='34' r='22'/%3E%3Cpath d='M36 40 L64 40 L58 95 L42 95 Z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='34' r='22'/%3E%3Cpath d='M36 40 L64 40 L58 95 L42 95 Z'/%3E%3C/svg%3E");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-size: contain;
  mask-size: contain;
}

/* ---- MOTIF 2: torn paper panels ----------------------------------------
   The paper itself is drawn by .blurb-paper::before (see PAGE SKINS below),
   which carries the fill, the hard shadow and the #wobble-card edge. This
   rule now only handles the box model, so the turbulence filter never lands
   on the text and blurs it. */
.panel {
  position: relative;
  color: var(--ink);
  padding: var(--space-4);
  transform: rotate(var(--panel-rotate, -0.4deg));
}
.panel:nth-of-type(odd)  { --panel-rotate: 0.55deg; }
.panel:nth-of-type(even) { --panel-rotate: -0.45deg; }
.panel--flat { transform: none; }
.panel--deep { background: none; }

/* thin wobbly-edged accent strip riding the top of a panel */
.panel > .panel__tab {
  position: absolute;
  top: -8px;
  left: 6%;
  width: 22%;
  height: 14px;
  background: var(--teal-deep);
  filter: url(#wobble);
}

/* standalone wobbly divider, e.g. between the upcoming/archive gig lists */
.wobbly-divider {
  border: 0;
  height: 6px;
  background: var(--paper);
  opacity: 0.55;
  filter: url(#wobble);
  margin: var(--space-5) 0;
}

/* ---- MOTIF 4: halftone dot field ---------------------------------------- */
.halftone {
  position: absolute;
  pointer-events: none;
  background-image: radial-gradient(var(--ink) 1px, transparent 1.6px);
  background-size: 10px 10px;
  opacity: 0.08;
}
.halftone--paper {
  background-image: radial-gradient(var(--paper) 1.5px, transparent 2px);
  opacity: 0.15;
}

/* ---- MOTIF 5: camo blobs (home hero only) --------------------------------- */
.camo-blobs {
  position: absolute;
  inset: -25% -10%;
  z-index: 0;
  pointer-events: none;
  opacity: 0.9;
}
.hero__mark { position: relative; z-index: 1; }
.hero__wordmark { position: relative; z-index: 1; }

/* ---- photo duotone -----------------------------------------------------
   The one reusable class for "teal by default, full colour on hover /
   focus / inside the lightbox". */
.duo {
  position: relative;
  display: block;
  overflow: hidden;
  background: var(--teal-deep);
}
.duo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* These are dark stage photographs. Desaturating and then multiplying a dark
     teal over them crushed everything to black. Lift the exposure first, then
     tint with `color` blend (below), which keeps the image's own luminance and
     only takes teal's hue — a real duotone rather than a dark wash. */
  filter: grayscale(1) brightness(1.55) contrast(1.02);
  transition: filter 250ms ease;
}
.duo::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--teal-bright);
  mix-blend-mode: color;   /* hue + saturation only; luminance survives */
  opacity: 0.92;
  transition: opacity 250ms ease;
  pointer-events: none;
}
.duo:hover img,
.duo:focus-visible img,
.duo.is-color img { filter: none; }
.duo:hover::after,
.duo:focus-visible::after,
.duo.is-color::after { opacity: 0; }

/* ---- buttons (cartoon, hard-shadow, press-down) -------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  font-size: var(--fs-small);
  background: var(--paper);
  color: var(--ink);
  border: var(--border-cartoon);
  box-shadow: var(--shadow-hard-sm);
  text-decoration: none;
  transition: transform 150ms ease, box-shadow 150ms ease, background 150ms ease;
}
.btn:hover { transform: translate(-2px, -2px); box-shadow: 7px 7px 0 var(--teal-deep); }
.btn:active { transform: translate(2px, 2px); box-shadow: 2px 2px 0 var(--teal-deep); }
.btn--primary { background: var(--red); color: var(--white); border-color: var(--ink); }
.btn--outline { background: transparent; color: var(--paper-light); border-color: var(--paper-light); box-shadow: none; }
.btn--outline:hover { background: rgba(242, 233, 216, 0.12); box-shadow: none; }
.btn--giant {
  font-size: clamp(1rem, 1.4vw + 0.6rem, 1.35rem);
  padding: var(--space-4) var(--space-5);
}
.btn svg { width: 1.1em; height: 1.1em; fill: currentColor; }

/* ---- panels grid used on Music page -------------------------------------- */
.embed-card { position: relative; }
.embed-card h3 { margin-bottom: var(--space-3); }

.embed {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--ink);
}
.embed--bandcamp { aspect-ratio: 4 / 3; }
.embed__frame { width: 100%; height: 100%; border: 0; display: block; }
.embed__placeholder {
  position: absolute;
  inset: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  background:
    radial-gradient(circle at 30% 20%, rgba(42,154,160,0.35), transparent 55%),
    linear-gradient(160deg, var(--teal-deep), var(--ink));
  color: var(--paper-light);
  cursor: pointer;
  text-align: center;
  padding: var(--space-3);
}
.embed__play {
  width: 4.25rem;
  height: 4.25rem;
  border-radius: 50%;
  background: var(--red);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-hard-sm);
  transition: transform 150ms ease;
}
.embed__placeholder:hover .embed__play,
.embed__placeholder:focus-visible .embed__play { transform: scale(1.08); }
.embed__play svg { width: 1.5rem; height: 1.5rem; fill: var(--white); margin-left: 3px; }
.embed__title { font-weight: 800; text-transform: uppercase; letter-spacing: 0.02em; }
.embed__hint { font-size: var(--fs-small); color: var(--paper); }

/* ---- live / gig list ------------------------------------------------------ */
.gig-list { display: flex; flex-direction: column; gap: var(--space-3); }
.gig-card {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  background: var(--paper);
  color: var(--ink);
  padding: var(--space-4);
  box-shadow: var(--shadow-hard-sm);
  position: relative;
}
.gig-card--past { background: var(--paper-light); opacity: 0.85; }
.gig-card__flyer {
  flex: 0 0 auto;
  width: 88px;
  height: 88px;
  aspect-ratio: 1 / 1;
}
.gig-card__flyer img { width: 100%; height: 100%; object-fit: cover; }
.gig-card__body { flex: 1 1 auto; min-width: 0; }
.gig-card__top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-1);
}
.gig-card__date {
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.gig-card__venue { font-weight: 800; text-transform: uppercase; font-size: var(--fs-h3); margin: 0.1em 0; }
.gig-card__meta { font-size: var(--fs-small); }
.gig-card__note { font-size: var(--fs-small); font-style: italic; margin-top: var(--space-1); }
.gig-card__actions { flex: 0 0 auto; }

.gig-tag {
  display: inline-block;
  background: var(--red);
  color: var(--white);
  font-weight: 800;
  text-transform: uppercase;
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  padding: 0.25em 0.6em;
  transform: rotate(-2deg);
}
.gig-tag--past { background: var(--blue); }

.gig-empty {
  text-align: center;
  padding: var(--space-6) var(--space-4);
  border: 2px dashed var(--paper);
  color: var(--paper-light);
}
.gig-empty p:first-child { font-weight: 800; text-transform: uppercase; margin-bottom: var(--space-2); }

@media (max-width: 560px) {
  .gig-card { flex-wrap: wrap; }
  .gig-card__flyer { width: 64px; height: 64px; }
}

/* ---- photos / masonry gallery ---------------------------------------------- */
.masonry__item { display: block; }
.thumb {
  display: block;
  width: 100%;
  border: 0;
  padding: 0;
  background: none;
  cursor: zoom-in;
}
.thumb .duo { aspect-ratio: 4 / 5; }
.thumb .duo img { clip-path: url(#keyhole); }
.thumb__cap {
  margin-top: var(--space-1);
  font-size: 0.75rem;
  color: var(--paper);
}

/* ---- lightbox ---------------------------------------------------------------- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 800;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--overlay-scrim);
  padding: var(--space-5) var(--space-4);
}
.lightbox[hidden] { display: none; }
.lightbox__figure { position: relative; max-width: min(92vw, 1100px); max-height: 86vh; }
.lightbox__img {
  display: block;
  max-width: 100%;
  max-height: 86vh;
  object-fit: contain;
  box-shadow: 0 25px 70px rgba(0,0,0,0.55);
}
.lightbox__caption {
  color: var(--paper-light);
  margin-top: var(--space-2);
  font-size: var(--fs-small);
  text-align: center;
}
.lightbox__close,
.lightbox__nav {
  position: absolute;
  color: var(--ink);
  background: var(--paper);
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-hard-sm);
}
.lightbox__close svg, .lightbox__nav svg { width: 1.2rem; height: 1.2rem; fill: currentColor; }
.lightbox__close { top: -1.25rem; right: -1.25rem; }
.lightbox__nav--prev { left: -1.25rem; top: 50%; transform: translateY(-50%); }
.lightbox__nav--next { right: -1.25rem; top: 50%; transform: translateY(-50%); }
@media (max-width: 700px) {
  .lightbox__close { top: -3.25rem; right: 0; }
  .lightbox__nav--prev { left: 0.25rem; }
  .lightbox__nav--next { right: 0.25rem; }
}

/* ---- about / members ----------------------------------------------------------- */
.member-card { text-align: center; }
.member-card__portrait { width: 100%; }
.member-card__portrait .duo { aspect-ratio: 1 / 1; }
.member-card__portrait img { clip-path: url(#keyhole); }
.member-card__name {
  margin-top: var(--space-3);
  font-weight: 800;
  text-transform: uppercase;
  font-size: var(--fs-small);
  letter-spacing: 0.02em;
  color: var(--paper-light);
}
.member-card__role { font-size: 0.8rem; color: var(--paper); margin-top: 0.2em; }

.quote-panel {
  position: relative;
  padding: var(--space-5);
}
.quote-panel .halftone { inset: 0; }
.quote-panel blockquote { position: relative; }
.quote-panel cite {
  display: block;
  margin-top: var(--space-3);
  font-style: normal;
  font-weight: 600;
  font-size: var(--fs-small);
}

/* ---- contact ------------------------------------------------------------------- */
.social-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--paper);
  color: var(--ink);
  padding: var(--space-3) var(--space-4);
  font-weight: 800;
  text-transform: uppercase;
  font-size: var(--fs-small);
  box-shadow: var(--shadow-hard-sm);
  text-decoration: none;
  transition: transform 150ms ease, box-shadow 150ms ease;
}
.social-link:hover { transform: translate(-2px, -2px); box-shadow: 7px 7px 0 var(--teal-deep); }
.social-link svg { width: 1.3rem; height: 1.3rem; fill: currentColor; }

.doc-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--paper-light);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  font-weight: 600;
}
.doc-link svg { width: 1.1rem; height: 1.1rem; fill: currentColor; }

.impressum {
  background: var(--paper);
  color: var(--ink);
  padding: var(--space-5);
  font-size: var(--fs-small);
  line-height: 1.7;
}
.impressum h2 { font-size: var(--fs-h3); margin-bottom: var(--space-3); }
.impressum p + p { margin-top: 0; }

/* ---- hamburger icon morph ------------------------------------------------------- */
.hamburger .line1, .hamburger .line3 { transition: transform 180ms ease; transform-origin: center; }
.hamburger .line2 { transition: opacity 150ms ease; }
.hamburger[aria-expanded="true"] .line1 { transform: translateY(8px) rotate(45deg); }
.hamburger[aria-expanded="true"] .line3 { transform: translateY(-8px) rotate(-45deg); }
.hamburger[aria-expanded="true"] .line2 { opacity: 0; }


/* ---- portrait duotone -------------------------------------------------
   Member portraits are daylight shots and need less lifting than the stage
   photographs, but the keyhole crop puts faces on a small canvas, so they
   have to stay clearly legible. */
.duo--portrait img { filter: grayscale(0.55) brightness(1.12) contrast(0.82); }
.duo--portrait::after { opacity: 0.45; }

/* ---- home: two paper cards ---------------------------------------------
   The landing page is two pieces of kraft laid on the stage photo, angled
   against each other the way the sleeve stacks its title bars over the
   collage. Edges are chewed by #wobble-card so neither is a clean rectangle. */
.hero__cards {
  position: relative;
  width: 100%;
  max-width: min(94vw, 78rem);
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(0.9rem, 2.2vw, 1.9rem);
}

.paper-card {
  position: relative;
  width: 100%;
  margin: 0;
  background-color: var(--paper);
  /* same fibre wash as the header, so the stock matches across the site */
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4'/%3E%3CfeColorMatrix values='0 0 0 0 0.42 0 0 0 0 0.35 0 0 0 0 0.24 0 0 0 0.16 0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23f)'/%3E%3C/svg%3E");
  box-shadow: 10px 12px 0 var(--teal-deep);
  filter: url(#wobble-card);
}

.paper-card--mark {
  padding: clamp(1.1rem, 2.6vw, 2rem) clamp(1.5rem, 6vw, 4.5rem);
  transform: rotate(-1.4deg);
  display: grid;
  place-items: center;
  isolation: isolate;
  overflow: hidden;        /* blobs are confined to the card, like ink on paper */
}
.paper-card--mark .camo-blobs {
  position: absolute;
  inset: -6% -4%;
  z-index: 0;
  /* full strength: on kraft these need to read as printed colour, not a wash.
     Multiply keeps them sitting IN the paper rather than floating over it. */
  opacity: 1;
  mix-blend-mode: multiply;
  pointer-events: none;
}
.paper-card__wordmark {
  position: relative;
  z-index: 1;
  width: min(100%, 52rem);
  height: auto;
}

.paper-card--art {
  transform: rotate(1deg);
  padding: clamp(0.5rem, 1.2vw, 0.9rem);
  overflow: hidden;
}
.paper-card__art {
  display: block;
  width: 100%;
  /* both cards have to share one viewport — cap the photo and crop rather
     than letting it push the mark off the top */
  max-height: 42svh;
  object-fit: cover;
  object-position: center 42%;
}

@media (max-width: 760px) {
  /* less rotation on narrow screens — angled cards eat horizontal room */
  .paper-card--mark { transform: rotate(-0.8deg); }
  .paper-card--art  { transform: rotate(0.5deg); }
  .paper-card { box-shadow: 6px 7px 0 var(--teal-deep); }
}

@media (prefers-reduced-motion: reduce) {
  .paper-card { filter: none; }   /* turbulence filters are costly to composite */
}

/* ==========================================================================
   PAGE SKINS — per-route ground, corner halftone, and torn header edge.
   Driven by data-route on <html>, set by updateNav() in js/main.js.
   ========================================================================== */

.page {
  position: relative;
  isolation: isolate;
  /* teal ground with depth, --bg-angle varies per page */
  background: linear-gradient(var(--bg-angle, 155deg), #093238 0%, #0d4a51 34%, #12585f 62%, #16636a 100%);
}

/* halftone: TWO lattices on the same 15px grid so the dots stay aligned.
   ::before carries big dots concentrated at the hot corner, ::after fine dots
   spread almost the full diagonal. Both use SOFT-EDGED dots — as the mask
   fades them the soft edge drops below visibility, so the dots genuinely
   shrink on the way out rather than just going grey. */
.page::before,
.page::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-repeat: repeat;
}

/* big dots — tight to the corner */
.page::before {
  background-image: radial-gradient(circle,
    var(--ink) 0%, var(--ink) 26%, rgba(16,16,19,0.6) 42%, transparent 66%);
  background-size: 15px 15px;
  opacity: 0.9;
  -webkit-mask-image: radial-gradient(75% 68% at var(--ht-x, 12%) var(--ht-y, 6%),
    #000 0%, rgba(0,0,0,0.8) 34%, rgba(0,0,0,0.25) 62%, transparent 88%);
          mask-image: radial-gradient(75% 68% at var(--ht-x, 12%) var(--ht-y, 6%),
    #000 0%, rgba(0,0,0,0.8) 34%, rgba(0,0,0,0.25) 62%, transparent 88%);
}

/* fine dots — carried almost the whole way across the page */
.page::after {
  background-image: radial-gradient(circle,
    var(--ink) 0%, var(--ink) 12%, rgba(16,16,19,0.5) 26%, transparent 52%);
  background-size: 15px 15px;
  opacity: 0.8;
  -webkit-mask-image: radial-gradient(165% 150% at var(--ht-x, 12%) var(--ht-y, 6%),
    #000 0%, rgba(0,0,0,0.9) 30%, rgba(0,0,0,0.55) 58%, rgba(0,0,0,0.22) 82%, transparent 100%);
          mask-image: radial-gradient(165% 150% at var(--ht-x, 12%) var(--ht-y, 6%),
    #000 0%, rgba(0,0,0,0.9) 30%, rgba(0,0,0,0.55) 58%, rgba(0,0,0,0.22) 82%, transparent 100%);
}

/* per-page: gradient angle + which corner the halftone gathers in */
:root[data-route="home"]    .page { --bg-angle: 155deg; --ht-x: 10%; --ht-y: 8%; }
:root[data-route="music"]   .page { --bg-angle: 200deg; --ht-x: 88%; --ht-y: 6%; }
:root[data-route="live"]    .page { --bg-angle: 135deg; --ht-x: 8%;  --ht-y: 10%; }
:root[data-route="photos"]  .page { --bg-angle: 172deg; --ht-x: 92%; --ht-y: 12%; }
:root[data-route="about"]   .page { --bg-angle: 118deg; --ht-x: 14%; --ht-y: 4%; }
:root[data-route="contact"] .page { --bg-angle: 215deg; --ht-x: 86%; --ht-y: 9%; }

/* the rip under the header, re-seeded per page */
:root[data-route="home"]    .site-header::after, :root[data-route="home"]    .site-header::before { filter: url(#tear-home); }
:root[data-route="music"]   .site-header::after, :root[data-route="music"]   .site-header::before { filter: url(#tear-music); }
:root[data-route="live"]    .site-header::after, :root[data-route="live"]    .site-header::before { filter: url(#tear-live); }
:root[data-route="photos"]  .site-header::after, :root[data-route="photos"]  .site-header::before { filter: url(#tear-photos); }
:root[data-route="about"]   .site-header::after, :root[data-route="about"]   .site-header::before { filter: url(#tear-about); }
:root[data-route="contact"] .site-header::after, :root[data-route="contact"] .site-header::before { filter: url(#tear-contact); }

/* ==========================================================================
   BLURBS — every kraft box gets the hand-torn edge the home cards have.
   The paper lives on a ::before so the wobble filter never touches the text.
   ========================================================================== */

.blurb-paper {
  position: relative;
  z-index: 0;
  background: none;
  box-shadow: none;
  clip-path: none;
}
.blurb-paper > * { position: relative; z-index: 1; }
.blurb-paper::before {
  content: "";
  position: absolute;
  /* MUST stay comfortably larger than #wobble-card's displacement scale (13).
     At -6px the filter could pull the paper inside its own edge and expose the
     teal ground through it — the stray streaks that appeared while scrolling,
     intermittent because filtered layers re-rasterise in tiles. */
  inset: -20px;
  z-index: -1;
  background-color: var(--paper);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4'/%3E%3CfeColorMatrix values='0 0 0 0 0.42 0 0 0 0 0.35 0 0 0 0 0.24 0 0 0 0.16 0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23f)'/%3E%3C/svg%3E");
  box-shadow: 10px 12px 0 var(--teal-deep);
  filter: url(#wobble-card);
  transition: transform 220ms cubic-bezier(.2,.7,.3,1), box-shadow 220ms ease;
}

/* the live nudge: paper shifts under the content on hover */
.blurb-paper:hover::before,
.blurb-paper:focus-within::before {
  transform: rotate(-0.6deg) translate(-3px, -3px) scale(1.005);
  box-shadow: 14px 16px 0 var(--teal-deep);
}

/* ---- page headings as comic-book title bars ----------------------------
   Kicker and title are two separate strips of paper. They need their own
   lines and real gaps — their ::before paper is inset -6px and overlaps
   otherwise, which buries the kicker under the title. */
.page-head {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.85rem;
  margin-bottom: var(--space-5);
}
.page-head h1 {
  display: inline-block;
  align-self: flex-start;
  color: var(--ink);
  padding: 0.12em 0.5em 0.18em;
  margin: 0;
  transform: rotate(-1.2deg);
  transition: transform 220ms cubic-bezier(.2,.7,.3,1);
}
.page-head h1:hover { transform: rotate(0.5deg) scale(1.02); }
.page-kicker.h-mark {
  /* NOT a blurb: .h-mark already owns ::before for the keyhole bullet, and the
     two fought. It stays a plain label on the teal ground. */
  align-self: flex-start;
  margin-left: 0.35rem;
  color: var(--teal-bright);
  letter-spacing: 0.14em;
  transform: rotate(0.9deg);
  transition: transform 220ms cubic-bezier(.2,.7,.3,1), color 220ms ease;
}
.page-kicker.h-mark:hover { color: var(--paper-light); }
.page-kicker.h-mark:hover { transform: rotate(-0.8deg) translateY(-2px); }

@media (prefers-reduced-motion: reduce) {
  .blurb-paper::before,
  .page-head h1,
  .page-kicker.h-mark { transition: none; }
  .blurb-paper:hover::before { transform: none; box-shadow: 10px 12px 0 var(--teal-deep); }
  .page-head h1:hover, .page-kicker.h-mark:hover { transform: none; }
}


/* the gig empty-state and cards sit on kraft now, so their type flips to ink */
.gig-empty.blurb-paper {
  color: var(--ink);
  border-color: rgba(16,16,19,0.35);
}
.gig-card.blurb-paper,
.gig-card.blurb-paper .gig-card__meta { color: var(--ink); }

/* 3. short pages should still fill the window rather than stopping mid-screen */
.page {
  min-height: calc(100svh - var(--nav-height));
}


/* doc-link defaults to paper-light for the teal ground; inside a kraft blurb
   that was near-invisible (this was the low-contrast Bandcamp link). */
.blurb-paper .doc-link,
.panel .doc-link {
  color: var(--teal-deep);
  font-weight: 600;
  text-decoration-thickness: 2px;
}
.blurb-paper .doc-link:hover,
.panel .doc-link:hover { color: var(--red); }


/* the click-to-load notice is doing consent work — give it room to breathe
   and enough contrast to actually be read before the click */
.embed__hint {
  max-width: 34ch;
  margin-inline: auto;
  line-height: 1.4;
  opacity: 0.95;
}


/* ---- transition paint budget ------------------------------------------
   During a page turn TWO .page layers are live at once, each carrying two
   masked halftone lattices (~1.75Mpx apiece) plus turbulence-filtered paper.
   Chromium composites that on the GPU; WebKit largely re-rasterises on the
   CPU every frame. None of it is perceptible during a 650ms turn, so drop it
   for the duration. */
/* Suppress on the OUTGOING layer only. Blanket-suppressing both layers cut
   the paint cost but meant the destination page arrived unstyled and its
   halftone popped in when the transition ended — visible and cheap-looking.
   The page being revealed must look finished from the first frame; the one
   rotating away is leaving and moving fast, so nobody studies its texture. */
.page.tr-curl-out::before,
.page.tr-curl-out::after,
.page.tr-fade-out::before,
.page.tr-fade-out::after { display: none; }

.tr-curl-out .blurb-paper::before,
.tr-fade-out .blurb-paper::before { filter: none; }

/* the wipe hides its outgoing page outright, so its decoration costs nothing
   either way — the incoming page keeps everything. */

/* ---- home cards react to the cursor ------------------------------------ */
.paper-card {
  transition: transform 240ms cubic-bezier(.2,.7,.3,1), box-shadow 240ms ease;
}
.paper-card--mark:hover {
  transform: rotate(-0.6deg) translate(-4px, -5px);
  box-shadow: 16px 18px 0 var(--teal-deep);
}
.paper-card--art:hover {
  transform: rotate(0.4deg) translate(4px, -5px);
  box-shadow: 16px 18px 0 var(--teal-deep);
}

/* ---- track titles: stop them shouting over the page heading ------------ */
.embed-card h2 {
  font-size: clamp(1.05rem, 1vw + 0.8rem, 1.45rem);
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
  line-height: 1.25;
  margin-bottom: var(--space-3);
}

@media (prefers-reduced-motion: reduce) {
  .paper-card { transition: none; }
  .paper-card--mark:hover, .paper-card--art:hover { transform: none; }
}

/* ---- past-gig archive: compact rows you scroll back through ------------- */
.gig-archive {
  list-style: none;
  padding: 0;
  margin: 0;
  max-width: 58rem;
}
.gig-year {
  font-weight: 800;
  font-size: clamp(1.6rem, 3vw + 0.6rem, 2.6rem);
  color: var(--teal-bright);
  letter-spacing: -0.02em;
  margin: var(--space-5) 0 var(--space-2);
  opacity: 0.75;
}
.gig-year:first-child { margin-top: var(--space-2); }

.gig-row {
  display: grid;
  grid-template-columns: 5.5rem minmax(0, 1fr) minmax(0, 0.9fr);
  gap: var(--space-3);
  align-items: baseline;
  padding: 0.6rem 0.2rem;
  border-bottom: 1px solid rgba(231, 218, 193, 0.18);
  transition: background 160ms ease, padding-left 160ms ease;
}
.gig-row:hover {
  background: rgba(231, 218, 193, 0.07);
  padding-left: 0.7rem;
}
.gig-row__date {
  font-weight: 700;
  font-size: var(--fs-small);
  color: var(--teal-bright);
  white-space: nowrap;
}
.gig-row__venue {
  font-weight: 700;
  color: var(--paper-light);
}
.gig-row__city {
  font-size: var(--fs-small);
  color: var(--paper);
  opacity: 0.75;
}
.gig-row__note { font-style: italic; }

@media (max-width: 620px) {
  /* stack on narrow screens — three columns is too tight for venue names */
  .gig-row {
    grid-template-columns: 4.5rem minmax(0, 1fr);
    row-gap: 0.15rem;
  }
  .gig-row__city { grid-column: 2; }
}

/* ---- click-to-load stills ----------------------------------------------
   Downloaded once by tools/fetch-thumbs.sh and served from our own origin —
   hotlinking i.ytimg.com here would put a third-party request back on page
   load and undo the whole reason the site needs no cookie banner. */
.embed__thumb {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
  filter: grayscale(1) brightness(1.15) contrast(0.95);
  transition: filter 250ms ease, transform 400ms ease;
}
.embed__thumb + * { position: relative; z-index: 2; }
.embed__placeholder > :not(.embed__thumb) { position: relative; z-index: 2; }
/* teal wash so the still reads as ours rather than as YouTube furniture */
.embed__placeholder::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--teal);
  mix-blend-mode: color;
  opacity: 0.9;
  transition: opacity 250ms ease;
  pointer-events: none;
}
.embed__placeholder::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(180deg, rgba(10,59,65,0.25), rgba(10,59,65,0.7));
  pointer-events: none;
}
.embed__placeholder:hover .embed__thumb,
.embed__placeholder:focus-visible .embed__thumb { filter: none; transform: scale(1.03); }
.embed__placeholder:hover::before,
.embed__placeholder:focus-visible::before { opacity: 0; }
