/* ============================================================
   JENKINS/EDWARDS — CONCEPT 04 · "SONGBOOK × TWO VOICES"
   Concept 01's concert-hall staging, re-lit in the Two Voices palette.
   Warm paper & stone grounds · one steel accent · deep steel-ink for the
   dramatic bands (intro, hero, photo tiles, enquiry). Fraunces + Inter kept.
   ------------------------------------------------------------
   ROBUSTNESS CONTRACT (proven on prior project):
   - No content is hidden via CSS. Reveal start-states are set in JS
     only when GSAP is present AND motion is allowed. If a CDN fails,
     everything is simply visible and readable.
   - Above-the-fold hero copy never depends on requestAnimationFrame:
     a wall-clock setTimeout force-writes final inline styles.
   - Imagery is bundled locally in assets/images. Every photo is graded to
     the concept and sits under a scrim wherever text overlays it. The two
     <img> slots (Ryan portrait, video poster) fall back to a labelled
     placeholder via inline onerror; decorative backgrounds simply fail to
     the dark base.
   ============================================================ */

:root{
  --stage:      #F2F0EC;   /* warm paper — primary light ground    */
  --stage-2:    #E9E5DF;   /* stone tint — alternate section band  */
  --stage-3:    #E3DED6;   /* deeper stone — quietest light well   */
  --accent-ink: #16333C;   /* deepest steel — the dramatic dark bands */
  --paper-card: #F7F5F2;   /* raised card face                     */
  --ivory:      #16333C;   /* steel-ink — primary type / headings  */
  --ivory-2:    #303338;   /* graphite — body copy                 */
  --ivory-3:    #5F636A;   /* grey — muted labels (AA on paper)    */
  --brass:      #2E5866;   /* the one accent — deep steel          */
  --brass-2:    rgba(46,88,102,0.55);
  --brass-3:    rgba(46,88,102,0.16);
  --on-brass:   #F2F0EC;   /* text that sits on a steel fill       */
  --line:       rgba(20,22,26,0.12);
  --line-2:     rgba(20,22,26,0.07);

  --ff-display: 'Fraunces', Georgia, 'Times New Roman', serif;
  --ff-ui:      'Inter', system-ui, -apple-system, Segoe UI, Roboto, sans-serif;

  --pad:        clamp(1.25rem, 5vw, 6rem);
  --maxw:       1320px;
  --ease:       cubic-bezier(0.22, 1, 0.36, 1);
}

*{ box-sizing:border-box; }
html{ -webkit-text-size-adjust:100%; overflow-x:hidden; }
html, body{ margin:0; }
body{
  background:var(--stage);
  color:var(--ivory);
  font-family:var(--ff-ui);
  font-weight:400;
  line-height:1.6;
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
body.menu-open{ overflow:hidden; }

img, svg{ max-width:100%; display:block; }
a{ color:inherit; text-decoration:none; }
button{ font:inherit; color:inherit; background:none; border:none; cursor:pointer; }
::selection{ background:var(--brass); color:#F2F0EC; }

/* ---- Focus visibility (keyboard) ---- */
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible{
  outline:2px solid var(--brass);
  outline-offset:3px;
  border-radius:2px;
}

.skip-link{
  position:absolute; left:1rem; top:-4rem; z-index:200;
  background:var(--brass); color:var(--on-brass); padding:.6rem 1rem;
  border-radius:4px; font-weight:600; transition:top .2s var(--ease);
}
.skip-link:focus{ top:1rem; }

/* ---- Shared type ---- */
.eyebrow{
  font-family:var(--ff-ui);
  font-size:clamp(.66rem, 1.3vw, .78rem);
  font-weight:500;
  letter-spacing:.34em;
  text-transform:uppercase;
  color:var(--brass);
  display:inline-flex; align-items:center; gap:.85em;
}
.eyebrow::before{
  content:""; width:2.4em; height:1px; background:var(--brass-2);
  display:inline-block;
}
.eyebrow--plain::before{ display:none; }

h1,h2,h3,h4{ font-family:var(--ff-display); font-weight:300; margin:0; }
p{ margin:0 0 1rem; }

/* Masked-line reveal primitive (used for giant type, JS-driven) */
.line{ display:block; overflow:hidden; }
.line__inner{ display:block; will-change:transform; }

/* ============================================================
   LAYOUT SHELL
   ============================================================ */
.wrap{ width:100%; max-width:var(--maxw); margin-inline:auto; padding-inline:var(--pad); }
section{ position:relative; }
.band{ background:var(--stage); }
.band--2{ background:var(--stage-2); }
.band--3{ background:var(--stage-3); }

.rule{ height:1px; background:var(--line); border:0; margin:0; }

/* ---- fixed overlays created/managed by JS but styled here ---- */
.spotlight{
  position:fixed; inset:0; z-index:70; pointer-events:none;
  background:radial-gradient(260px circle at var(--x,50%) var(--y,50%),
             rgba(46,88,102,0.14), rgba(46,88,102,0.05) 40%, transparent 66%);
  mix-blend-mode:multiply;
  opacity:0;                       /* fades in on first pointermove (set in JS) — no glow on load */
  transition:opacity .4s var(--ease);
}
.grain{
  position:fixed; inset:0; z-index:65; pointer-events:none; opacity:.05;
  mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---- progress bar (native scroll driven, no gsap needed) ---- */
.progress{
  position:fixed; left:0; top:0; height:2px; width:100%; z-index:90;
  transform:scaleX(0); transform-origin:0 50%;
  background:linear-gradient(90deg, var(--brass-2), var(--brass));
  pointer-events:none;
}

/* ---- intro curtain (element created in JS, so no-JS never traps) ---- */
/* Pre-paint gate (contract with the <head> gate script + app.js): before ANY page paint,
   html.curtain-wait fills the viewport with the SAME ink as .curtain and hides <body>, so the
   very first paint is the curtain's ink — never the page. app.js removes curtain-wait in the
   same synchronous block that appends the curtain, so gate hands off to curtain in one paint
   with no page ever visible between the two. */
html.curtain-wait{ background:var(--accent-ink); }
html.curtain-wait body{ visibility:hidden; }
.curtain{
  position:fixed; inset:0; z-index:120; background:var(--accent-ink);
  display:grid; place-items:center;
  transition:opacity .9s var(--ease), visibility .9s var(--ease);
}
.curtain__logo{
  width:clamp(240px, 38vw, 500px); height:auto; display:block;
  filter:brightness(0) invert(0.95);          /* dark artwork → light on the steel-ink curtain, matching the nav lockup */
  opacity:0; transform:translateY(8px);
  transition:opacity .8s var(--ease), transform .8s var(--ease);
}
.curtain.reveal .curtain__logo{ opacity:1; transform:none; }
.curtain__logo.is-failed{ display:none; }
.curtain__mark{
  font-family:var(--ff-display); font-weight:300;
  font-size:clamp(1.3rem,4vw,2.2rem); letter-spacing:.02em;
  color:#F2F0EC; display:none; align-items:center; gap:.5rem;   /* text is the onerror fallback only */
  opacity:0; transform:translateY(8px);
  transition:opacity .8s var(--ease), transform .8s var(--ease);
}
.curtain--fallback .curtain__mark{ display:flex; }
.curtain__mark .sl{ color:#7FB2C0; font-weight:300; }
.curtain.reveal .curtain__mark{ opacity:1; transform:none; }
.curtain.gone{ opacity:0; visibility:hidden; }

/* ============================================================
   NAV
   ============================================================ */
.nav{
  position:fixed; inset:0 0 auto 0; z-index:100;
  display:flex; align-items:center; justify-content:space-between;
  padding:clamp(1rem,2.2vw,1.6rem) var(--pad);
  transition:background .4s var(--ease), backdrop-filter .4s var(--ease), border-color .4s var(--ease);
  border-bottom:1px solid transparent;
  --nav-fg:#F2F0EC;                     /* light over the dark hero at the top   */
  --nav-fg-dim:rgba(242,240,236,0.74);
  --nav-slash:#7FB2C0;
}
.nav.scrolled{
  background:rgba(242,240,236,0.82);
  backdrop-filter:blur(14px) saturate(1.1);
  border-bottom:1px solid var(--line-2);
  --nav-fg:#16333C;                     /* steel-ink once scrolled onto light content */
  --nav-fg-dim:#40565C;
  --nav-slash:#2E5866;
}
.brand{
  font-family:var(--ff-display); font-weight:400;
  font-size:clamp(1.05rem,1.7vw,1.35rem); letter-spacing:.01em;
  display:inline-flex; align-items:center; gap:.1em; white-space:nowrap;
  color:var(--nav-fg); transition:color .4s var(--ease);
}
.brand .sl{ color:var(--nav-slash); padding:0 .12em; font-weight:300; }

/* Logo lockup in the nav — dark steel-teal artwork.
   Over the dark hero at the top it must read light (filter); once .scrolled onto
   the paper backdrop it shows in its natural ink. The text brand (.brand__text)
   is revealed only if the image fails to load (onerror → .brand--fallback). */
.brand__logo{
  height:clamp(34px, 4.4vw, 44px); width:auto; display:block;
  filter:brightness(0) invert(0.95);          /* → ~#F2F2F2, matching the light nav type on the dark hero */
  transition:filter .4s var(--ease);
}
.nav.scrolled .brand__logo{ filter:none; }    /* natural dark artwork on the light scrolled bar */
.brand__logo.is-failed{ display:none; }
.brand__text{ display:none; }                  /* text is the onerror fallback only */
.brand--fallback .brand__text{ display:inline-flex; align-items:baseline; gap:.1em; }

.nav__links{ display:flex; align-items:center; gap:clamp(1.2rem,2.4vw,2.6rem); }
.nav__link{
  font-size:.82rem; letter-spacing:.06em; color:var(--nav-fg-dim);
  position:relative; padding:.3rem 0; transition:color .3s var(--ease);
}
.nav__link::after{
  content:""; position:absolute; left:0; bottom:0; height:1px; width:100%;
  background:var(--nav-slash); transform:scaleX(0); transform-origin:0 50%;
  transition:transform .4s var(--ease);
}
.nav__link:hover, .nav__link:focus-visible{ color:var(--nav-fg); }
.nav__link:hover::after, .nav__link:focus-visible::after{ transform:scaleX(1); }

.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:.6em;
  font-family:var(--ff-ui); font-size:.82rem; font-weight:500;
  letter-spacing:.08em; text-transform:uppercase;
  padding:.85em 1.6em; border-radius:100px;
  transition:background .35s var(--ease), color .35s var(--ease), border-color .35s var(--ease), transform .2s var(--ease);
  will-change:transform;
}
.btn--brass{ background:var(--brass); color:var(--on-brass); }
.btn--brass:hover, .btn--brass:focus-visible{ background:var(--ivory); }
.btn--ghost{ border:1px solid var(--line); color:var(--ivory); }
.btn--ghost:hover, .btn--ghost:focus-visible{ border-color:var(--brass); color:var(--brass); }
.nav .btn{ padding:.7em 1.35em; }

.nav__toggle{ display:none; width:44px; height:44px; align-items:center; justify-content:center; }
.nav__toggle span{ position:relative; width:24px; height:1.5px; background:var(--nav-fg); display:block; transition:background .2s; }
.nav__toggle span::before, .nav__toggle span::after{
  content:""; position:absolute; left:0; width:24px; height:1.5px; background:var(--nav-fg);
  transition:transform .3s var(--ease), top .3s var(--ease);
}
.nav__toggle span::before{ top:-7px; }
.nav__toggle span::after{ top:7px; }
.menu-open .nav__toggle span{ background:transparent; }
.menu-open .nav__toggle span::before{ top:0; transform:rotate(45deg); background:var(--ivory); }
.menu-open .nav__toggle span::after{ top:0; transform:rotate(-45deg); background:var(--ivory); }

/* ============================================================
   HERO
   ============================================================ */
.hero{
  position:relative; min-height:100svh; min-height:100vh;
  display:flex; align-items:center;
  padding-top:6rem; overflow:hidden;
  /* the theatrical opening: a deep steel-ink band, lit by luminous strings.
     Every text/accent token is re-scoped light for the whole hero subtree. */
  --ivory:#F2F0EC;
  --ivory-2:rgba(242,240,236,0.74);
  --ivory-3:rgba(242,240,236,0.56);
  --brass:#7FB2C0;
  --brass-2:rgba(127,178,192,0.55);
  --brass-3:rgba(127,178,192,0.16);
  --on-brass:#10262D;
  --line:rgba(242,240,236,0.16);
  --line-2:rgba(242,240,236,0.08);
  color:var(--ivory);
  background:
    radial-gradient(120% 90% at 50% 8%, rgba(127,178,192,0.14), transparent 55%),
    radial-gradient(140% 120% at 50% 120%, rgba(6,16,20,0.92), var(--accent-ink) 60%),
    var(--accent-ink);
}
.hero__canvas{ position:absolute; inset:0; z-index:0; opacity:.9; }
.hero__vignette{
  position:absolute; inset:0; z-index:1; pointer-events:none;
  background:radial-gradient(120% 90% at 50% 45%, transparent 40%, rgba(9,22,27,0.55) 100%);
}
.hero__inner{ position:relative; z-index:2; width:100%; }
/* Dark scrim between the animated strings and the headline text so the bright
   node of the WebGL sweep can never wash out the ivory glyphs. Sits inside
   .hero__inner's stacking context (above canvas + vignette, below the text). */
.hero__inner::before{
  content:""; position:absolute; z-index:-1; pointer-events:none;
  /* Full-bleed pool of shade over the headline. Spans the viewport (edges fall in
     the periphery, off the content) and fades fully to transparent well inside every
     edge, so no straight cut-line can appear. Previously inset -8% of the content box
     with a gradient still ~0.17 opaque at its left edge → a faint vertical seam left
     of the headline. .hero has overflow:hidden, so the 100vw width never scrolls. */
  left:50%; top:50%; transform:translate(-50%, -50%);
  width:min(100vw, 1600px); height:150%;
  background:radial-gradient(46% 60% at 36% 50%, rgba(9,22,27,0.56) 0%, rgba(9,22,27,0.30) 42%, transparent 76%);
}
.hero__eyebrow{ margin-bottom:clamp(1.4rem,3vw,2.4rem); }

.hero__name{
  font-weight:300; line-height:.9;
  font-size:clamp(3.4rem, 14vw, 12.5rem);
  letter-spacing:-.02em; margin:0;
}
/* Hero lockup — as large as the room allows. Solid light-filtered artwork on the
   dark hero, matching the nav + curtain treatment. width/height on the <img> reserve
   the aspect ratio so nothing shifts as it loads. */
.hero__logo{
  width:min(88vw, 1100px); height:auto; display:block;
  filter:brightness(0) invert(0.95);
}
.hero__logo.is-failed{ display:none; }
.hero__name-text{ display:none; }               /* styled text headline — the onerror fallback only */
.hero__name--fallback .hero__name-text{ display:block; }
.hero__name .line__inner{ padding-bottom:.04em; }
.hero__name .amp{ color:var(--brass); font-style:italic; font-weight:300; }

.hero__sub{
  font-family:var(--ff-display); font-weight:300;
  font-size:clamp(1.15rem, 2.4vw, 1.85rem); line-height:1.4;
  color:var(--ivory-2); max-width:34ch;
  margin:clamp(1.6rem,3.5vw,2.6rem) 0 clamp(1.8rem,3.5vw,2.6rem);
}
.hero__sub em{ color:var(--ivory); font-style:italic; }

.hero__cta-row{ display:flex; flex-wrap:wrap; gap:1rem; align-items:center; }

.hero__scroll{
  position:absolute; left:var(--pad); bottom:clamp(1.4rem,3vw,2.4rem); z-index:2;
  display:inline-flex; align-items:center; gap:.8rem;
  font-size:.7rem; letter-spacing:.28em; text-transform:uppercase; color:var(--ivory-3);
}
.hero__scroll .track{ width:44px; height:1px; background:var(--line); position:relative; overflow:hidden; }
.hero__scroll .track::after{
  content:""; position:absolute; inset:0; width:40%; background:var(--brass);
  animation:track 2.4s var(--ease) infinite;
}
@keyframes track{ 0%{transform:translateX(-120%)} 60%,100%{transform:translateX(320%)} }

/* ============================================================
   THE DUO
   ============================================================ */
.section-head{
  display:flex; align-items:flex-end; justify-content:space-between;
  gap:2rem; flex-wrap:wrap; margin-bottom:clamp(2.5rem,6vw,4.5rem);
}
.section-head h2{
  font-size:clamp(2rem, 5.5vw, 4.4rem); line-height:1; letter-spacing:-.015em;
  max-width:16ch;
}
.section-head h2 em{ font-style:italic; color:var(--brass); }
.section-head__meta{ text-align:right; color:var(--ivory-2); max-width:34ch; }

.pad-y{ padding-block:clamp(4.5rem, 11vw, 9rem); }

.duo{ display:grid; grid-template-columns:1fr 1fr; gap:clamp(1.5rem,4vw,3.5rem); }
.performer{ display:flex; flex-direction:column; }
.portrait{
  position:relative; aspect-ratio:4/5; border:1px solid var(--line);
  background:
    linear-gradient(180deg, rgba(46,88,102,0.05), transparent 40%),
    radial-gradient(120% 80% at 50% 12%, rgba(46,88,102,0.07), transparent 55%),
    linear-gradient(180deg, #E9E5DF, #DCD7CF 70%);
  display:grid; place-items:center; overflow:hidden; border-radius:2px;
}
.portrait::after{
  content:""; position:absolute; inset:0;
  background:radial-gradient(80% 60% at 50% 120%, rgba(46,88,102,0.10), transparent 60%);
}
.portrait__tag{
  position:relative; z-index:1; text-align:center; color:var(--ivory-3);
  font-size:.78rem; letter-spacing:.16em; text-transform:uppercase;
  padding:1rem; line-height:1.9;
}
.portrait__tag svg{ margin:0 auto .9rem; opacity:.5; }
.performer__name{
  font-size:clamp(1.7rem,3.2vw,2.6rem); line-height:1.05; margin:1.5rem 0 .3rem;
}
.performer__role{ color:var(--brass); font-size:.8rem; letter-spacing:.22em; text-transform:uppercase; margin-bottom:1rem; }
.performer__bio{ color:var(--ivory-2); max-width:44ch; }
.performer__bio strong{ color:var(--ivory); font-weight:500; }
.tbc{ color:var(--brass); font-style:italic; }

/* ============================================================
   THE SONGBOOK — pinned chapters
   ============================================================ */
.songbook__intro{ text-align:center; padding-block:clamp(4rem,10vw,7rem) clamp(1rem,3vw,2rem); }
.songbook__intro h2{ font-size:clamp(2rem,5.5vw,4rem); line-height:1.05; margin-top:1.2rem; }
.songbook__intro h2 em{ font-style:italic; color:var(--brass); }
.songbook__intro p{ color:var(--ivory-2); max-width:52ch; margin:1.4rem auto 0; }

.chapter{
  min-height:100vh; display:flex; align-items:center;
  padding-block:clamp(4rem,9vw,7rem);
  border-top:1px solid var(--line-2);
}
/* Chapters I & III invert to a deep steel-ink band (all type/accent/line tokens
   re-scoped light, exactly like the hero and #enquire) to break the long light
   stretch. A quiet right-biased teal radial adds depth. The colour change alone
   is the divider, so the top border goes transparent (no stray hairline on the
   light→dark seam). isolation keeps the string-lights screen-blend contained. */
.chapter--dark{
  isolation:isolate;
  background:
    radial-gradient(120% 92% at 78% 32%, rgba(127,178,192,0.10), transparent 55%),
    var(--accent-ink);
  border-top-color:transparent;
  --ivory:#F2F0EC;
  --ivory-2:rgba(242,240,236,0.76);
  --ivory-3:rgba(242,240,236,0.56);
  --brass:#7FB2C0;
  --brass-2:rgba(127,178,192,0.55);
  --brass-3:rgba(127,178,192,0.18);
  --on-brass:#10262D;
  --line:rgba(242,240,236,0.20);
  --line-2:rgba(242,240,236,0.10);
  color:var(--ivory);
}
.chapter__inner{
  width:100%; max-width:var(--maxw); margin-inline:auto; padding-inline:var(--pad);
  display:grid; grid-template-columns:1.15fr .85fr; gap:clamp(2rem,5vw,5rem);
  align-items:center;
}
.chapter__left{ min-width:0; }
.chapter__label{ margin-bottom:1.5rem; }
.chapter__label .cap{ font-size:.7rem; letter-spacing:.3em; text-transform:uppercase; color:var(--ivory-3); }
.chapter__name{
  font-size:clamp(3rem, 12vw, 11rem); line-height:.86; letter-spacing:-.025em;
  font-weight:300; margin:0;
}
.chapter__name .line__inner{ padding-bottom:.12em; }  /* room for descenders (e.g. the 'p' in Knopfler) inside the mask */
.chapter__reverent{
  font-family:var(--ff-display); font-weight:300; font-style:italic;
  font-size:clamp(1.1rem,2vw,1.6rem); line-height:1.5; color:var(--ivory-2);
  max-width:40ch; margin-top:clamp(1.5rem,3vw,2.2rem);
}

/* concert programme */
.programme{ list-style:none; margin:0; padding:0; border-top:1px solid var(--line); }
.programme li{
  display:grid; grid-template-columns:auto 1fr; align-items:baseline; gap:1rem;
  padding:.85rem 0; border-bottom:1px solid var(--line-2);
}
.programme .idx{ font-size:.72rem; color:var(--brass); letter-spacing:.1em; min-width:2ch; }
.programme .title{ font-family:var(--ff-display); font-size:clamp(1.05rem,1.8vw,1.35rem); color:var(--ivory); }
.programme .title em{ font-style:italic; color:var(--ivory-2); }
.programme__note{ margin-top:1.1rem; font-size:.76rem; color:var(--ivory-3); letter-spacing:.04em; }

.songbook__coda{
  text-align:center; padding-block:clamp(5rem,13vw,10rem);
  border-top:1px solid var(--line-2);
}
.songbook__coda p{
  font-family:var(--ff-display); font-style:italic; font-weight:300;
  font-size:clamp(1.6rem,5vw,3.4rem); line-height:1.25; color:var(--ivory);
  max-width:22ch; margin-inline:auto;
}
.songbook__coda .growing{ color:var(--brass); }

/* ============================================================
   OCCASIONS — a horizontally scrolling row of cards (the client asked
   for cards on a scroll row rather than a table). The hairline separators
   and outer frame are preserved with the same gap:1px-over-a-line-coloured
   background trick, which works for a flex row exactly as it did for the grid.
   ============================================================ */
.occasions{
  display:flex; gap:1px;
  background:var(--line-2); border:1px solid var(--line-2);
  overflow-x:auto; overflow-y:hidden;
  overscroll-behavior-x:contain;        /* a horizontal flick shouldn't trigger browser back-nav */
  -webkit-overflow-scrolling:touch;     /* iOS momentum */
  scrollbar-width:thin;                 /* Firefox */
  scrollbar-color:var(--brass-2) transparent;
}
/* A thin brass-on-transparent bar: a deliberate desktop scroll affordance, kept visible (not hidden). */
.occasions::-webkit-scrollbar{ height:8px; }
.occasions::-webkit-scrollbar-track{ background:transparent; }
.occasions::-webkit-scrollbar-thumb{ background:var(--brass-2); border-radius:100px; }
.occasions::-webkit-scrollbar-thumb:hover{ background:var(--brass); }
/* Marquee active (JS has cloned the set + started the auto-drift). A continuously
   sliding scrollbar under a slow drift is just visual noise, so hide it here and let
   the motion + grab cursor be the affordance. Gated on .is-marquee so the no-JS /
   reduced-motion fallback keeps its visible, draggable scrollbar. */
.occasions.is-marquee{ cursor:grab; scrollbar-width:none; }
.occasions.is-marquee::-webkit-scrollbar{ height:0; width:0; display:none; }
.occasions.is-marquee.is-dragging{ cursor:grabbing; user-select:none; }
.occasion{
  position:relative; overflow:hidden;   /* own containing block for .occasion__media + scrim; clips the hover Ken-Burns scale */
  /* Fixed basis so cards never shrink: caps at 340px, where ~3 cards + a peek of the
     4th fill the wrap on desktop; on ≤~420px viewports the card tracks the viewport so
     one card + a ~2.5rem peek of the next always shows as the scroll affordance. */
  flex-grow:0; flex-shrink:0; flex-basis:min(100vw - 5rem, 340px);
  background:var(--stage); padding:clamp(1.8rem,3vw,2.6rem);
  min-height:clamp(15rem,26vw,19rem); display:flex; flex-direction:column;
  transition:background .5s var(--ease);
}
.occasion:hover{ background:var(--stage-2); }
/* margin-top:auto re-anchors heading + body to the card bottom — the job the removed
   .occasion__num (margin-bottom:auto) used to do. The photo-card scrim is darkest across
   the lower half specifically so this bottom-sitting copy clears WCAG AA. */
.occasion h3{ font-size:clamp(1.5rem,2.6vw,2rem); line-height:1.05; margin:auto 0 .8rem; }
.occasion p{ color:var(--ivory-2); font-size:.96rem; margin:0; }

/* ============================================================
   LISTEN / WATCH — a single live-performance video centrepiece.
   Matches the site's card language (hairline border, small radius),
   with a deep steel-ink frame that reads as the video "matte" and
   masks the player's white flash while it loads.
   ============================================================ */
.film{ max-width:min(100%, 920px); margin-inline:auto; }
.film__frame{
  position:relative; aspect-ratio:16/9;   /* reserves height up front — no layout shift on load */
  border:1px solid var(--line); border-radius:4px; overflow:hidden;
  background:var(--accent-ink);
}
.film__frame iframe{ position:absolute; inset:0; width:100%; height:100%; border:0; }
.film__cap{
  margin:clamp(1.1rem,2.2vw,1.6rem) auto 0; max-width:52ch; text-align:center;
  color:var(--ivory-2); font-size:.98rem;
}

/* ============================================================
   ENQUIRE (form — UI only) — inverted to a deep steel-ink band,
   echoing the Two Voices booking panel. Tokens re-scoped light.
   ============================================================ */
#enquire{
  background:var(--accent-ink);
  --ivory:#F2F0EC;
  --ivory-2:rgba(242,240,236,0.76);
  --ivory-3:rgba(242,240,236,0.56);
  --brass:#7FB2C0;
  --brass-2:rgba(127,178,192,0.55);
  --brass-3:rgba(127,178,192,0.18);
  --on-brass:#10262D;
  --line:rgba(242,240,236,0.2);
  --line-2:rgba(242,240,236,0.1);
  color:var(--ivory);
}
.enquire{ display:grid; grid-template-columns:.85fr 1.15fr; gap:clamp(2rem,5vw,4.5rem); }
.enquire__lead h2{ font-size:clamp(2rem,4.5vw,3.4rem); line-height:1.05; }
.enquire__lead h2 em{ font-style:italic; color:var(--brass); }
.enquire__lead p{ color:var(--ivory-2); max-width:40ch; margin-top:1.2rem; }
.enquire__contact{ margin-top:2rem; display:grid; gap:.6rem; font-size:.92rem; color:var(--ivory-2); }
.enquire__contact .k{ color:var(--ivory-3); letter-spacing:.14em; text-transform:uppercase; font-size:.7rem; }

form{ display:grid; gap:1.4rem; }
.field{ display:grid; gap:.5rem; }
.field.row-2{ grid-template-columns:1fr 1fr; gap:1.4rem; }
@media (max-width:560px){ .field.row-2{ grid-template-columns:1fr; } }
label{ font-size:.72rem; letter-spacing:.16em; text-transform:uppercase; color:var(--ivory-3); }
.control{
  width:100%; background:transparent; color:var(--ivory);
  border:1px solid var(--line); border-radius:3px;
  padding:.9em 1em; font-family:var(--ff-ui); font-size:.98rem;
  transition:border-color .3s var(--ease), background .3s var(--ease);
}
.control::placeholder{ color:var(--ivory-3); }
.control:hover{ border-color:var(--brass-2); }
.control:focus{ border-color:var(--brass); background:rgba(127,178,192,0.06); outline:none; }
select.control{ appearance:none; background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%237FB2C0' stroke-width='1.5' fill='none'/%3E%3C/svg%3E"); background-repeat:no-repeat; background-position:right 1em center; padding-right:2.6em; }
textarea.control{ resize:vertical; min-height:7rem; }
.form-foot{ display:flex; align-items:center; justify-content:space-between; gap:1rem; flex-wrap:wrap; }
.form-note{ font-size:.76rem; color:var(--ivory-3); }
.btn--submit{ background:var(--brass); color:var(--on-brass); padding:1em 2.2em; }
.btn--submit:hover, .btn--submit:focus-visible{ background:var(--ivory); }
.btn--submit:disabled{ opacity:.6; cursor:default; }

/* Inline validation + submission feedback. --err is a warm signal tuned to read
   clearly on the deep steel-ink band (scoped inside #enquire, below). */
#enquire{ --err:#EBA091; }
.field__err{ font-size:.74rem; letter-spacing:.02em; text-transform:none; color:var(--err); }
.field__err:empty{ display:none; }               /* no phantom gap until an error lands */
[data-field][data-invalid="true"] .control{ border-color:var(--err); }
[data-field][data-invalid="true"] .control:focus{ border-color:var(--err); background:rgba(235,160,145,0.06); }
[data-field][data-invalid="true"] label{ color:var(--err); }

/* Form-level error: full-width line under the submit row, kept out of flow until shown. */
.form__error{ flex-basis:100%; order:3; margin:0; color:var(--err); font-size:.82rem; line-height:1.5; }
.form__error a{ color:var(--err); text-decoration:underline; text-underline-offset:3px; }

/* Success state — occupies the form's grid cell once the form is hidden. */
.enquire__panel{ min-width:0; }
#bookForm.hide{ display:none; }
.form__success{ display:none; }
.form__success.show{ display:grid; gap:.7rem; justify-items:start; outline:none; animation:successIn .7s var(--ease) both; }
.form__success svg{ width:46px; height:46px; stroke:var(--brass); fill:none; stroke-width:1.4; stroke-linecap:round; stroke-linejoin:round; }
.form__success h3{ font-family:var(--ff-display); font-weight:400; font-size:clamp(1.6rem,3.4vw,2.3rem); line-height:1.1; margin:0; }
.form__success h3 em{ font-style:italic; color:var(--brass); }
.form__success p{ color:var(--ivory-2); max-width:44ch; margin:0; }
@keyframes successIn{ from{ opacity:0; transform:translateY(16px); } to{ opacity:1; transform:none; } }
@media (prefers-reduced-motion: reduce){ .form__success.show{ animation:none; } }

/* ============================================================
   FOOTER
   ============================================================ */
.footer{ background:var(--stage-3); border-top:1px solid var(--line-2); padding-block:clamp(3.5rem,8vw,6rem) 2rem; }
.footer__top{ display:grid; grid-template-columns:1.4fr 1fr 1fr; gap:2.5rem; }
.footer__logo{ height:auto; width:auto; max-height:clamp(70px, 9vw, 110px); max-width:100%; margin-bottom:1.2rem; }  /* the lockup on light stone — natural dark artwork, no filter. max-height caps size; max-width lets the wide 3.69:1 lockup shrink proportionally (no distortion) if the brand column narrows */
.footer__logo.is-failed{ display:none; }
.footer__brand{ font-family:var(--ff-display); font-size:clamp(1.8rem,4vw,3rem); font-weight:300; line-height:1; display:none; }  /* text is the onerror fallback only */
.footer__brand-wrap.is-fallback .footer__brand{ display:block; }
.footer__brand .sl{ color:var(--brass); }
.footer__tag{ color:var(--ivory-2); max-width:34ch; margin-top:1rem; font-size:.95rem; }
.footer__col h3{ font-family:var(--ff-ui); font-size:.7rem; letter-spacing:.2em; text-transform:uppercase; color:var(--ivory-3); font-weight:500; margin-bottom:1.1rem; }
.footer__col a, .footer__col span{ display:block; color:var(--ivory-2); font-size:.94rem; padding:.32rem 0; transition:color .3s var(--ease); }
.footer__col a:hover, .footer__col a:focus-visible{ color:var(--brass); }
.footer__col .ph{ color:var(--ivory-3); font-style:italic; }
.footer__bottom{
  display:flex; align-items:center; justify-content:space-between; gap:1rem; flex-wrap:wrap;
  margin-top:clamp(3rem,6vw,4.5rem); padding-top:1.6rem; border-top:1px solid var(--line-2);
  font-size:.8rem; color:var(--ivory-3);
}

/* ============================================================
   IMAGERY — real + stock photography, graded to the concept.
   The two <img> slots fall back to a labelled placeholder via inline
   onerror; decorative CSS backgrounds fail silently to the dark base.
   Text over imagery always gets a scrim so contrast holds.
   ============================================================ */

/* --- Ryan portrait: fills the 4/5 card; labelled slot is the fallback --- */
.portrait__img{
  position:absolute; inset:0; z-index:0; width:100%; height:100%;
  object-fit:cover; object-position:50% 22%;
  filter:grayscale(1) contrast(1.04) brightness(1);
  /* eager compositing layer: filtered imgs can otherwise stay unpainted until a repaint (Chromium quirk) */
  transform:translateZ(0); will-change:transform;
}
.portrait__img.is-failed{ display:none; }
.portrait__tag{ display:none; }                        /* hidden while the photo shows */
.portrait.is-failed .portrait__tag{ display:block; }   /* labelled fallback returns on error */

/* --- Jo Jenkins: real photo treated like Ryan's slot; the silhouette below is kept as the onerror fallback (never a stock face) --- */
.portrait--jo .silhouette{ position:absolute; inset:0; z-index:0; width:100%; height:100%; }
.portrait--jo .bust{ fill:#DCD7CF; }
.portrait--jo .str{ fill:none; stroke:rgba(20,22,26,.14); stroke-width:1.4; }
.portrait--jo .str--brass{ stroke:rgba(46,88,102,.5); }
/* Jo's real photo: same duotone as Ryan (.portrait__img), a tighter head/torso
   crop, and a Jo-only scrim so the busy home-studio recedes to Ryan's stage-black level */
.portrait--jo .portrait__img{ object-position:50% 50%; transform:translateZ(0) scale(1.09); transform-origin:50% 20%; }
.portrait--jo::before{
  content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:
    linear-gradient(180deg, rgba(22,51,60,0.12) 0%, transparent 26%, transparent 62%, rgba(22,51,60,0.14) 100%),
    radial-gradient(120% 92% at 50% 30%, transparent 45%, rgba(22,51,60,0.10) 100%);
}
.portrait__tag--tbc{ display:block; position:absolute; left:0; right:0; bottom:1.4rem; z-index:2; padding:0 1rem; }

/* --- Occasion cards: photographic mood behind text; heavy scrim keeps copy AA --- */
.occasion--photo{
  isolation:isolate;
  --ivory:#F2F0EC;
  --ivory-2:rgba(242,240,236,0.82);
  --ivory-3:rgba(242,240,236,0.62);
  --brass:#8FBCC8;
  color:var(--ivory);
}
.occasion--photo h3{ color:var(--ivory); }
.occasion--photo .occasion__media{
  position:absolute; inset:0; z-index:0; background-image:var(--img);
  background-size:cover; background-position:center;
  opacity:.7; filter:grayscale(1) contrast(1.05) brightness(.6);
  transition:opacity .6s var(--ease), transform .6s var(--ease);
}
/* Text (heading + body, bottom-anchored) rides the scrim: quiet at top so the
   photo reads, ramping hard-dark across the lower half where all copy sits so
   heading + body clear WCAG AA even over bright frames (e.g. string-lights). */
.occasion--photo::before{
  content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:linear-gradient(180deg, rgba(12,28,33,.72) 0%, rgba(12,28,33,.52) 42%, rgba(8,20,25,.93) 100%);
}
.occasion--photo > *:not(.occasion__media){ position:relative; z-index:2; }
.occasion--photo:hover .occasion__media{ opacity:.82; transform:scale(1.06); }

/* --- Chapter interlude: a graded photo behind the giant name ---
   The mask sits the image centre-left, behind the huge (forgiving) chapter name,
   and fades out before the right-hand programme so the small brass indices /
   ivory list rows keep full contrast. Light chapter (II) gets a clearly-visible
   silver ghost; dark chapters (I & III) get their own darker grade below. */
.chapter{ position:relative; overflow:hidden; }
.chapter__bg{
  position:absolute; inset:0; z-index:0; background-size:cover; background-position:center;
  opacity:.3; filter:grayscale(1) brightness(1.18) contrast(1);
  -webkit-mask-image:radial-gradient(112% 106% at 35% 50%, #000 0%, #000 22%, transparent 66%);
          mask-image:radial-gradient(112% 106% at 35% 50%, #000 0%, #000 22%, transparent 66%);
}
/* On the dark bands the image needs the opposite grade — darker, so the ivory
   name + programme stay AA. string-lights screens out of the navy so the bokeh
   glows rather than muddying it. */
.chapter--dark .chapter__bg{
  opacity:.36; filter:grayscale(.85) brightness(.7) contrast(1.06);
}
.chapter--dark .chapter__bg[style*="string-lights"]{
  opacity:.48; mix-blend-mode:screen;
  filter:grayscale(.25) brightness(.72) contrast(1.12) saturate(1.05);
  /* Own mask: concentrate the bokeh in a soft cloud behind the giant name and fade
     it out before the right-hand programme, so the small ivory list rows + brass
     indices + note sit over clean navy (a bright bokeh behind them would fail AA). */
  -webkit-mask-image:radial-gradient(72% 88% at 27% 42%, #000 0%, #000 12%, transparent 52%);
          mask-image:radial-gradient(72% 88% at 27% 42%, #000 0%, #000 12%, transparent 52%);
}
.chapter__inner{ position:relative; z-index:1; }

/* Mobile (≤900px): chapters unpin and stack 1-col, so the programme drops directly
   below the giant name. The chapter III string-lights screen-blend brightens the navy
   where its bokeh lands, and stacked the bokeh would sit behind the small teal indices
   (only ~5:1 headroom on navy) — so at this breakpoint neutralise the screen and render
   it as a dark ghost like the other dark chapters. Darkening can only raise the contrast
   of the ivory/teal text, so every stacked row stays AA regardless of the crop. */
@media (max-width:900px){
  .chapter--dark .chapter__bg[style*="string-lights"]{
    mix-blend-mode:normal;
    opacity:.32; filter:grayscale(.85) brightness(.62) contrast(1.05);
  }
}

/* --- Listen: faint fretboard backdrop; the cards sit opaque over it --- */
#listen{ position:relative; overflow:hidden; }
#listen::before{
  content:""; position:absolute; inset:0; z-index:0; pointer-events:none;
  /* stock (Unsplash) — illustrative; replace with duo photography */
  background:url("assets/images/stock/guitar-strings.jpg") center/cover;
  opacity:.07; filter:grayscale(.4) brightness(.55) contrast(1.05);
  -webkit-mask-image:linear-gradient(180deg, transparent, #000 32%, #000 70%, transparent);
          mask-image:linear-gradient(180deg, transparent, #000 32%, #000 70%, transparent);
}
#listen > .wrap{ position:relative; z-index:1; }

/* ============================================================
   CLIENT-COPY SECTIONS — craft pillars, all-in-one advantage, pull quotes
   ============================================================ */
.craft{ margin-top:clamp(3rem,6vw,5rem); border-top:1px solid var(--line); padding-top:clamp(2.5rem,5vw,3.5rem); }
.craft__lead{ font-family:var(--ff-display); font-weight:300; font-size:clamp(1.3rem,3vw,2.1rem); line-height:1.35; color:var(--ivory); max-width:32ch; margin:0 0 clamp(2rem,4vw,3rem); }
.craft__lead em{ font-style:italic; color:var(--brass); }
.craft__grid{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:clamp(1.5rem,3vw,3rem); }
.craft__k{ display:block; font-family:var(--ff-ui); font-size:.72rem; letter-spacing:.2em; text-transform:uppercase; color:var(--brass); margin-bottom:.8rem; }
.craft__item p{ color:var(--ivory-2); margin:0; font-size:.98rem; }

.advantage{ margin-top:clamp(1.5rem,3vw,2.5rem); border:1px solid var(--brass-3); border-radius:4px; padding:clamp(1.5rem,3vw,2.2rem); background:linear-gradient(180deg, rgba(46,88,102,0.05), transparent); display:flex; flex-direction:column; gap:.8rem; }
.advantage__tag{ font-size:.7rem; letter-spacing:.24em; text-transform:uppercase; color:var(--brass); }
.advantage__body{ margin:0; color:var(--ivory-2); max-width:72ch; font-size:1.02rem; }
.advantage__body strong{ color:var(--ivory); font-weight:500; }

.quotes__grid{ display:grid; grid-template-columns:1fr 1fr; gap:clamp(2rem,5vw,4.5rem); list-style:none; margin:0; padding:0; }
.quote{ position:relative; padding-left:2.2rem; }
.quote::before{ content:"\201C"; position:absolute; left:-.2rem; top:-.6rem; font-family:var(--ff-display); font-size:3.4rem; line-height:1; color:var(--brass-2); }
.quote__text{ font-family:var(--ff-display); font-weight:300; font-style:italic; font-size:clamp(1.35rem,2.6vw,2rem); line-height:1.4; color:var(--ivory); margin:0 0 1rem; }
.quote__by{ font-size:.72rem; letter-spacing:.16em; text-transform:uppercase; color:var(--ivory-3); }

@media (max-width:640px){
  .craft__grid{ grid-template-columns:1fr; gap:2rem; }
  .quotes__grid{ grid-template-columns:1fr; gap:2.5rem; }
}

/* ============================================================
   FAQ — quiet disclosure list. Native <details>: toggles with
   JS off, content crawlable when collapsed. Hairline rows, a
   Fraunces question, and a brass plus->minus marker.
   ============================================================ */
#faq .section-head .eyebrow{ display:flex; margin-bottom:1rem; }

.faq{ border-top:1px solid var(--line); }
.faq__item{ border-bottom:1px solid var(--line); }

.faq__q{
  list-style:none; cursor:pointer;
  display:flex; align-items:center; justify-content:space-between; gap:1.5rem;
  padding:clamp(1.1rem,2.6vw,1.7rem) 0;
}
.faq__q::-webkit-details-marker{ display:none; }
.faq__q:focus-visible{ outline:2px solid var(--brass); outline-offset:4px; border-radius:2px; }
.faq__q-text{
  font-family:var(--ff-display); font-weight:400;
  font-size:clamp(1.12rem,2.1vw,1.5rem); line-height:1.3;
  color:var(--ivory); transition:color .3s var(--ease);
}
.faq__q:hover .faq__q-text{ color:var(--brass); }
.faq__item[open] .faq__q-text{ color:var(--brass); }

/* plus -> minus toggle */
.faq__icon{ position:relative; flex:none; width:15px; height:15px; }
.faq__icon::before, .faq__icon::after{
  content:""; position:absolute; background:var(--brass);
  transition:transform .3s var(--ease), opacity .3s var(--ease);
}
.faq__icon::before{ top:50%; left:0; right:0; height:1.5px; transform:translateY(-50%); }
.faq__icon::after{ left:50%; top:0; bottom:0; width:1.5px; transform:translateX(-50%); }
.faq__item[open] .faq__icon::after{ transform:translateX(-50%) scaleY(0); opacity:0; }

.faq__a{ padding:0 0 clamp(1.3rem,2.6vw,1.9rem); }
.faq__a p{ color:var(--ivory-2); max-width:72ch; margin:0; }
.faq__a p a{ color:var(--brass); text-decoration:underline; text-underline-offset:3px; }

/* gentle open fade (neutralised under prefers-reduced-motion by the global reset) */
.faq__item[open] .faq__a{ animation:faqOpen .5s var(--ease) both; }
@keyframes faqOpen{ from{ opacity:0; transform:translateY(-4px); } to{ opacity:1; transform:none; } }

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width:900px){
  .duo{ grid-template-columns:1fr; gap:3rem; }
  .chapter__inner{ grid-template-columns:1fr; gap:2.5rem; }
  .enquire{ grid-template-columns:1fr; }
  .footer__top{ grid-template-columns:1fr 1fr; }
}
@media (max-width:820px){
  .nav__toggle{ display:flex; }
  .nav__links{
    position:fixed; inset:0; z-index:-1;
    flex-direction:column; justify-content:center; gap:2rem;
    background:rgba(242,240,236,0.98); backdrop-filter:blur(12px);
    opacity:0; visibility:hidden; transform:translateY(-8px);
    transition:opacity .4s var(--ease), transform .4s var(--ease), visibility .4s var(--ease);
    padding:var(--pad);
  }
  .menu-open .nav__links{ opacity:1; visibility:visible; transform:none; z-index:1; }
  .nav__links .nav__link{ font-size:1.4rem; letter-spacing:.02em; font-family:var(--ff-display); color:var(--ivory-2); }
  .nav__links .nav__link:hover, .nav__links .nav__link:focus-visible{ color:var(--brass); }
  .nav__links .btn{ font-size:.9rem; }
  .chapter{ min-height:auto; }
}
@media (max-width:560px){
  .footer__top{ grid-template-columns:1fr; gap:2rem; }
  .section-head__meta{ text-align:left; }
  .hero__sub{ max-width:30ch; }   /* keep a right gutter on small screens */
}

/* ============================================================
   REDUCED MOTION — everything static, readable, no WebGL/cursor
   (JS also skips heavy subsystems; this is the CSS safety net)
   ============================================================ */
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{ animation-duration:.001ms !important; animation-iteration-count:1 !important; transition-duration:.001ms !important; }
  .hero__scroll .track::after{ animation:none; }
}

/* ---- concept label (parity with the other mocks) ---- */
.badge{
  position:fixed; right:16px; bottom:16px; z-index:60;
  font-family:var(--ff-ui); font-size:.62rem; letter-spacing:.22em; text-transform:uppercase;
  color:var(--ivory-3);
  background:rgba(242,240,236,0.82); -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  border:1px solid var(--line); border-radius:100px; padding:.5em .95em;
  display:inline-flex; gap:.55em; align-items:center; pointer-events:none;
}
.badge b{ color:var(--brass); font-weight:600; }
@media (max-width:520px){ .badge{ display:none; } }
