/* ============================================================================
   Direction C · UNIVERS — shared foundation
   Loaded by index.html and every sub-page. Holds only what is direction-wide:
   tokens, reset, header, type scale, the row/figure/reveal primitives, the
   tweaks panel. Page-specific composition stays inline in each page's <style>,
   which loads AFTER this file and therefore wins at equal specificity.
   ============================================================================ */

:root{
  --paper:#fbfbfa; --ink:#1e1e1e; --ink-soft:#767676; --hair:#e4e4e4;   /* white bg + ECM dark grey #1e1e1e (from ecmrecords.com) */
  /* Real ECM face is Univers (licensed). Helvetica Neue → Inter is the free grotesque analog. */
  --sans:"Helvetica Neue",Helvetica,"Inter",Arial,sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,Menlo,monospace;
  --pad:clamp(6.5rem,15vh,13rem);
  --gut:clamp(1.5rem,6vw,6rem);
  --cool:grayscale(.66) contrast(1.05) brightness(.98);
  /* the INDENT STOP — the site's most characteristic measurement. It sets the second line of every
     display headline, the mono season line under it, and the footer title's second line. Named here
     because it was written out three times; the value is unchanged. */
  --ind:clamp(2.2rem,6vw,5.5rem);
  /* band rhythm for text pages. --pad (6.5–13rem) is a homepage cadence and would make a
     3,000-word reading page unreadably tall. */
  --pad-s:clamp(2.4rem,5.5vh,4.5rem);
  /* reading size. body is UI-sized (.95–1.05rem); long-form prose wants a notch more. */
  --read:clamp(1.02rem,1.15vw,1.18rem);
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{background:var(--paper);color:var(--ink);font-family:var(--sans);font-weight:400;
  font-size:clamp(.95rem,.98vw,1.05rem);line-height:1.72;letter-spacing:.005em;
  -webkit-font-smoothing:antialiased;overflow-x:hidden}
img{display:block;max-width:100%}
a{color:inherit;text-decoration:none}

.wrap{max-width:1380px;margin-inline:auto;padding-inline:var(--gut)}
.grid{display:grid;grid-template-columns:repeat(12,1fr);column-gap:clamp(1rem,2vw,2rem);row-gap:0}

/* tiny tracked-caps margin label — ECM signature */
.eyebrow{font-size:.66rem;text-transform:uppercase;letter-spacing:.26em;color:var(--ink-soft);font-weight:600}
.metanum{font-family:var(--mono);font-weight:400;font-variant-numeric:tabular-nums;letter-spacing:.02em}

/* nav — always on paper; logo is absolute so its oversized state never grows the header */
header{position:sticky;top:0;z-index:50;display:flex;align-items:center;gap:clamp(1rem,2.6vw,2.6rem);
  min-height:5.2rem;padding:.9rem var(--gut);background:var(--paper);transition:box-shadow .4s ease}
header.solid{box-shadow:0 1px 0 var(--hair)}
/* ⚠ top BALANCES THE LOGO IN THE HEADER, and it is NOT the header's .9rem padding any more (client,
   2026-08-03). The nav links are flex-centred; the logo was pinned to the padding box, so it sat 14px
   from the top of the page and only 5px from the rule that appears under a scrolled header — visibly
   low. The arithmetic: (5.2rem header − 63px logo) / 2 ≈ 9.95px, so both gaps come out ~10px.
   ⚠ NOT top:50%;translateY(-50%), which is the obvious fix and is wrong here. c-base.js has a
   big→small state that grows the logo to ~20% of the viewport (201px wide, 91px tall — TALLER than
   the 83px header) and lets it overhang downward on purpose. It is not on the shipped site (sizeLogo
   returns early for body.hero-full and body.sub, which between them cover all 15 pages), but it is
   one class away, and true centring would push it off the TOP of the screen. A fixed top can only
   ever overhang downward, which is what that lockup wants.
   ⚠ 63px is the SMALL logo's height — LOGO_SMALL (140px) in c-base.js over the wordmark's 2.22
   aspect. Change LOGO_SMALL and this value stops balancing; the size living in two places is a
   known trap of this header. */
.logo{position:absolute;left:var(--gut);top:.62rem;z-index:60;display:block}
.logo img{display:block;width:140px;height:auto}   /* outlined wordmark (3-line lockup, aspect 2.21); JS sizes width big→small on scroll */
nav{margin-left:auto;display:flex;gap:clamp(1rem,2.6vw,2.6rem)}
nav a{font-size:.82rem;text-transform:uppercase;letter-spacing:.18em;font-weight:500;padding-bottom:.4rem;
  border-bottom:1px solid transparent;transition:border-color .3s,opacity .3s}
nav a:hover{opacity:.55}
nav a.active{border-bottom-color:currentColor}
.actions{display:flex;align-items:center;gap:1.4rem;white-space:nowrap;font-size:.82rem;
  text-transform:uppercase;letter-spacing:.18em;font-weight:500}
.actions a{padding-bottom:.4rem;border-bottom:1px solid transparent}   /* match nav box so all header items align */
.actions a:hover{opacity:.55}
.actions a.active{border-bottom-color:currentColor}
/* Donate = the page's one call-to-action — hairline box sets it apart from wayfinding.
   Class selector, NOT [href] — the deploy postbuild rewrites hrefs (donate.html→#contact) and
   a href-based selector gets rewritten with them, boxing the wrong link on the live site. */
.actions a.donate{border:1px solid currentColor;padding:.5rem .85rem .5rem}
/* accessible page title (the visible name lives in the logo image + hero mask) */
.sr-only{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* header entrance — logo + nav fade/slide in on load */
@keyframes hdrIn{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
.logo{animation:hdrIn .7s ease both}
nav a,.actions a{animation:hdrIn .55s ease both}
nav a:nth-child(2){animation-delay:.06s}
nav a:nth-child(3){animation-delay:.12s}
nav a:nth-child(4){animation-delay:.18s}
.actions a:nth-child(1){animation-delay:.24s}
.actions a:nth-child(2){animation-delay:.30s}

/* contained figure — images are objects on the page, never full-bleed */
figure.fig{margin:0}
.fig .img{background-size:cover;background-position:center}
.fig figcaption{font-family:var(--mono);font-size:.7rem;color:var(--ink-soft);margin-top:.85rem;letter-spacing:.03em}

/* type — display headlines: large bold CAPS (Inter Tight), tight leading, staggered second line */
.lead{font-family:"Inter Tight",var(--sans);font-weight:700;font-size:clamp(2.4rem,5.4vw,4.8rem);line-height:.98;letter-spacing:.005em;text-transform:uppercase}
.lead .l2{display:block;padding-left:var(--ind)}   /* ECM's indented second line */
.lead-sm{font-weight:300;font-size:clamp(1.5rem,3vw,2.6rem);line-height:1.1;letter-spacing:-.014em}
/* editorial body paragraph beneath a headline — liner-notes register */
.measure{max-width:52ch}
.soft{color:var(--ink-soft)}
/* off-grid hangs — type breaks the content column into the gutter */
.hang-l{margin-left:calc(-.5 * var(--gut))}
.hang-r{margin-right:calc(-.5 * var(--gut))}

section{position:relative}
.band{padding-block:var(--pad)}
/* the former colour fields → optional ECM dark-grey full-bleed panels (tweak: body.panels-dark, default on) */
body.panels-dark .field{position:relative;color:#fbfbfa}
body.panels-dark .field::before{content:"";position:absolute;z-index:-1;top:0;bottom:0;left:calc(50% - 50vw);width:100vw;background:#1e1e1e}
body.panels-dark .field .eyebrow{color:rgba(251,251,250,.5)}
body.panels-dark .field .soft,body.panels-dark .field .who-bio,body.panels-dark .field figcaption{color:rgba(251,251,250,.62)}

/* hairline-separated data row — mono key, display value, tracked-caps tail on one baseline.
   .gig is the homepage's concert instance; .row is the same primitive, with knobs in sub.css
   (--c1 column width, .stack / .light / .tight modifiers). One rule set, so they can't drift. */
.gig,.row{display:grid;grid-template-columns:var(--c1,7rem) 1fr auto;gap:clamp(1rem,3vw,2.5rem);align-items:baseline;padding:1.5rem 0}
.gig + .gig,.row + .row{border-top:1px solid var(--hair)}
.gig .date,.row .k{color:var(--ink-soft);font-size:.84rem}
.gig .city,.row .v{font-family:"Inter Tight",var(--sans);font-weight:600;font-size:clamp(1.4rem,2.6vw,2.4rem);line-height:1;letter-spacing:0}   /* speaks the display voice */
.gig .venue,.row .t{color:var(--ink-soft);font-size:.72rem;text-transform:uppercase;letter-spacing:.16em}
/* the mono line under a display title — sits in the headline's indent, never a second headline.
   Carries METADATA (a season, a count), not prose. */
.season{margin-top:.9rem;font-size:.84rem;letter-spacing:.12em;text-transform:uppercase;padding-left:var(--ind)}

/* numbered tracklist row — the programme voice */
.track{display:grid;grid-template-columns:3.2rem 1fr;gap:clamp(1rem,3vw,2.5rem);align-items:baseline;padding:1.5rem 0}
.track + .track{border-top:1px solid var(--hair)}
.track .no{font-family:var(--mono);font-size:.76rem;color:var(--ink-soft);padding-top:.5rem}
.track .composer{font-weight:400;font-size:clamp(1.3rem,2.8vw,2.2rem);line-height:1.06;letter-spacing:-.01em}
.track .piece{color:var(--ink-soft);margin-top:.3rem;font-size:.94rem}

/* sublinks — stacked, underlined by default; hover softens */
.sublinks{display:flex;flex-direction:column;align-items:flex-start;gap:.85rem;margin-top:clamp(1.6rem,3.4vh,2.6rem)}
.sublinks a{white-space:nowrap;font-weight:400;font-size:clamp(1.15rem,1.5vw,1.35rem);letter-spacing:0;   /* no tracking: trailing letter-space would widen the underline past the word */
  border-bottom:1px solid currentColor;transition:opacity .3s}
.sublinks a:hover{opacity:.55}

footer{padding-block:var(--pad) 3.5rem}
/* ⚠️ `.ftitle` AND THE #edgeDissolve FILTER ARE DELETED, not moved (client, 2026-08-05). The footer
   title echoed the hero's dissolving borders by blurring and noise-eroding its letter edges, and
   "Contact us" on index.html was its ONE user — identical to `.lead` in face, weight, case, line
   height and tracking, differing only by that filter. The client read the eroded edges as a
   different typeface and asked for it to match the rest of the homepage, so the heading now takes
   plain `.lead` and the `<svg><defs>` block is gone from index.html with it.
   Removed rather than left dormant BECAUSE it was a trap: the rule carried a `filter:url()` pointing
   at markup that lives on ONE page, so any other page adopting `.ftitle` would have silently
   rendered an unfiltered heading with 0.22em of stray vertical padding.
   The reason that padding existed is worth keeping if the effect is ever wanted again: a CSS
   `filter` rasterizes at the BORDER BOX, so ink outside it is gone before the filter runs and
   widening the SVG's own filter region does nothing (measured). At line-height .98 the box is
   0.98em while the ink needs ~1.21em, so C, O, S and U came out sliced flat. The padding grew the
   box past the ink (~0.12em) plus the blur's reach (stdDeviation 2.4 ≈ 0.09em) and an equal negative
   margin gave the outer footprint back, leaving the .98 stacking and the page rhythm unchanged. */

/* site footer — social links + copyright, the one thing every page ends with, and now the SAME thing
   on all fourteen (client, 2026-08-03). The homepage used to keep its own inline socials row and an
   .eyebrow copyright stacked inside the Contact block; it carries this instead, so `.sitefoot` is
   the single definition of how a page ends. The homepage's Contact block sits above it as a
   <section> — it must NOT be a <footer>, or the page ends twice.
   There is no contact form anywhere on the direction — the Contact block is the client's own named
   people and addresses (index.html .fwrap). */
footer.sitefoot{padding-block:clamp(2.5rem,5vh,4rem) 3rem}
.sitefoot .sf-row{align-items:center}
.sitefoot .socials{grid-column:1/6;display:flex;gap:1.3rem;text-transform:uppercase;letter-spacing:.16em;font-size:.7rem}
.sitefoot .copy{grid-column:8/13;text-align:right;font-family:var(--mono);font-size:.7rem;color:var(--ink-soft);letter-spacing:.03em}
/* IMPRESSUM — the statutory notice, in the footer's right block beside the copyright (client,
   2026-08-03), in the client's own order: copyright first, Impressum last, as their site writes it.
   FULL INK against .copy's grey, because that is this site's one rule about grey — it is the passive
   voice, and everything you can click steps out of it (the socials in this same row are full ink for
   the same reason). The 1.3rem gap is the socials' own gap, so the two halves of the footer are
   spaced by one value. No separator glyph: the socials row sets four items apart with space alone. */
.sitefoot .copy .imp{margin-left:1.3rem;color:var(--ink);text-transform:uppercase;letter-spacing:.14em;white-space:nowrap}
.sitefoot .copy .credit{margin-left:1.3rem;white-space:nowrap}   /* the colophon stays in .copy's grey — a signature, not a control */

/* ECM reveal — fluid slide + fade on a decelerating curve; photos also scale in a touch.
   Reveals RE-TRIGGER on every viewport entry (scroll up + down), so travel is generous.
   NOTE for text pages: because .in is toggled OFF on exit, prose must never carry .reveal —
   it would blink when the reader scrolls back up. See sub.css. */
.reveal{opacity:0;transform:translate3d(0,64px,0);transition:transform 1.2s cubic-bezier(.16,1,.3,1),opacity 1s ease}
.reveal-x{opacity:0;transform:translate3d(76px,0,0);transition:transform 1.2s cubic-bezier(.16,1,.3,1),opacity 1s ease}
.reveal-l{opacity:0;transform:translate3d(-76px,0,0);transition:transform 1.2s cubic-bezier(.16,1,.3,1),opacity 1s ease}
.reveal.in,.reveal-x.in,.reveal-l.in{opacity:1;transform:none}
/* photos: slide + zoom for a more dynamic entrance */
.fig.reveal{transform:translate3d(0,72px,0) scale(.9)}
.fig.reveal-l{transform:translate3d(-80px,0,0) scale(.9)}
.fig.reveal-x{transform:translate3d(80px,0,0) scale(.9)}
.fig.reveal.in,.fig.reveal-l.in,.fig.reveal-x.in{transform:none}
/* small stagger so the links trail their title */
.sublinks.reveal{transition-delay:.12s}
.reveal-focus{opacity:0;transform:perspective(800px) translate3d(0,0,-180px) rotateX(18deg) scale(.95);
  transition:transform .6s ease-in-out,opacity 1s linear}
.reveal-focus.in{opacity:1;transform:none}

/* scroll-linked parallax (Rellax analog) — JS drives translateY drift on tagged block containers */
[data-par]{will-change:transform}

/* draw-in (experimental, off by default) — headings wipe up from a line; clip only, no translate */
body.draw-in .draw{transform:none!important;opacity:1;clip-path:inset(0 0 102% 0);
  transition:clip-path .9s cubic-bezier(.19,1,.22,1)}
body.draw-in .draw.in{clip-path:inset(0 0 -8% 0)}

/* tweaks panel */
.tweaks{position:fixed;right:1.1rem;bottom:1.1rem;z-index:200;font-family:var(--sans);
  display:flex;flex-direction:column;align-items:flex-end;gap:.6rem}
.tweaks .gear{order:0;flex:none;width:44px;height:44px;border-radius:50%;border:1px solid var(--ink);background:var(--paper);
  color:var(--ink);cursor:pointer;font-size:1.05rem;display:grid;place-items:center;box-shadow:0 6px 24px rgba(0,0,0,.12)}
.tweaks .panel{order:1;width:286px;max-height:calc(100svh - 130px);overflow-y:auto;background:var(--paper);color:var(--ink);
  border:1px solid var(--ink);padding:1.2rem 1.3rem;box-shadow:0 12px 48px rgba(0,0,0,.18);display:none}
.tweaks.tw-open .panel{display:block}   /* tw- prefixed: bare .open is the homepage hero's class */
.tweaks h4{font-size:.62rem;text-transform:uppercase;letter-spacing:.24em;color:var(--ink-soft);font-weight:600;margin-bottom:.2rem}
.tweaks .ttl{font-weight:400;font-size:1.1rem;margin-bottom:1rem}
.tw-group{margin-bottom:1.2rem}
.tw-group > label{display:block;font-size:.6rem;text-transform:uppercase;letter-spacing:.18em;color:var(--ink-soft);margin-bottom:.5rem}
.seg{display:flex;border:1px solid var(--hair)}
.seg button{flex:1;background:none;border:none;cursor:pointer;font-family:var(--sans);font-size:.76rem;
  padding:.5rem .4rem;color:var(--ink-soft);transition:background .2s,color .2s}
.seg button[aria-pressed="true"]{background:var(--ink);color:var(--paper)}
.tweaks .hint{font-size:.64rem;color:var(--ink-soft);line-height:1.5;margin-top:.4rem}
.tweaks input[type=range]{width:100%;accent-color:var(--ink);margin:.2rem 0}
body.clean .tweaks{display:none}

/* ── THE PHONE MENU ───────────────────────────────────────────────────────────────────────────
   Both hidden above the breakpoint; the markup is injected by c-base.js on every page (see "THE
   PHONE MENU" there for why it is built rather than authored).
   ⚠️ THE TOGGLE IS THE WORD "MENU", NOT THREE BARS — deliberately. This site carries exactly two
   glyphs and both are functional: `.back`'s ← and the video tile's play triangle, whose own comment
   says a functional triangle is in grammar where a decorative one is not. A hamburger would be the
   third and the first purely decorative one. The word also inherits `nav a`'s exact recipe, so on a
   phone the header reads in the same voice it does on a laptop, and it follows `currentColor` — white
   over the homepage hero, ink once the header goes solid — with no extra rule. */
.navtoggle,.navpanel{display:none}
@media(max-width:880px){
  nav,.actions{display:none}
  .navtoggle{display:block;margin-left:auto;background:none;border:0;padding:.4rem 0;
    font:inherit;color:inherit;cursor:pointer;
    font-size:.82rem;text-transform:uppercase;letter-spacing:.18em;font-weight:500}
  .navtoggle:focus-visible,.navclose:focus-visible{outline:1px solid currentColor;outline-offset:.4rem}
  /* full-bleed paper, not an overlay: a translucent sheet over a page whose own type is this large
     reads as two menus at once. `margin:0` because c-base's `*{margin:0}` is what a <dialog> relies
     on to centre — here we want it filling the screen instead. */
  .navpanel{margin:0;width:100%;max-width:none;height:100%;max-height:none;
    border:0;padding:0;background:var(--paper);color:var(--ink)}
  .navpanel::backdrop{background:var(--paper)}
  .navpanel[open]{display:flex;flex-direction:column}
  /* ⚠️ THE PANEL'S BAR RESTATES THE HEADER'S GEOMETRY EXACTLY — same min-height, same padding, same
     centring, and `position:relative` so the cloned logo's `position:absolute` anchors here instead
     of to the page. Every value is the header's own, and that is the point: the dialog covers the
     masthead, so anything that differs by a pixel reads as the page jumping when the menu opens. */
  .navpanel .navbar{position:relative;display:flex;align-items:center;
    min-height:5.2rem;padding:.9rem var(--gut)}
  .navclose{margin-left:auto;background:none;border:0;padding:.4rem 0;
    font:inherit;color:inherit;cursor:pointer;
    font-size:.82rem;text-transform:uppercase;letter-spacing:.18em;font-weight:500}
  /* `margin-block:auto` centres the six in the leftover height, so the list sits where the thumb is
     rather than pinned under the Close control.
     ⚠️ `margin-inline:0` IS NOT REDUNDANT — this is a real `<nav>`, so it inherits the header's own
     `nav{margin-left:auto}`, the rule that pushes the links to the right of the masthead. Inside a
     flex COLUMN that auto margin shoves the whole list against the right edge, and every count and
     measurement still passes while it does: six links, correct labels, panel fills the screen. Only
     a screenshot showed it. */
  .navpanel nav{display:flex;flex-direction:column;gap:clamp(.9rem,3.2vh,1.7rem);
    margin-block:auto;margin-inline:0;padding:0 var(--gut) 10vh;align-items:flex-start}
  /* the page-title voice at a size six of them fit in: this is the one screen where a nav link is
     the content, so it takes the display face rather than the header's micro-caps. */
  .navpanel nav a{font-family:"Inter Tight",var(--sans);font-weight:700;text-transform:uppercase;
    font-size:clamp(1.6rem,7.6vw,2.4rem);line-height:1;letter-spacing:.005em;
    border:0;padding:0}
  /* the page you are already on steps back rather than lighting up — grey is this site's passive
     voice, and an "active" link in a menu is the one thing you cannot usefully press. */
  .navpanel nav a.active{color:var(--ink-soft)}
  .hang-l,.hang-r{margin-inline:0}
  .gig,.row{grid-template-columns:1fr auto}
  .gig .date,.row .k{grid-column:1/-1;margin-bottom:.3rem}
  .sitefoot .socials,.sitefoot .copy{grid-column:1/-1;text-align:left}
  .sitefoot .copy{margin-top:.8rem}
}
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *{animation:none!important;transition:none!important}
  .reveal,.reveal-x,.reveal-l,.reveal-focus{opacity:1;transform:none}
  body.draw-in .draw{clip-path:none!important}
}
