    @view-transition {
      navigation: auto;
    }

    /* ── Fonts ── */
    @font-face {
      font-family: "Firme";
      src: url("/assets/fonts/firme-book.woff2") format("woff2"),
           url("/Fonts/firme-book.ttf") format("truetype");
      font-weight: 400;
      font-style: normal;
      font-display: swap;
    }
    @font-face {
      font-family: "Neue Haas Display";
      src: url("/assets/fonts/NeueHaasDisplayBold.woff2") format("woff2"),
           url("/Fonts/NeueHaasDisplayBold.ttf") format("truetype");
      font-weight: 700;
      font-style: normal;
      font-display: swap;
    }

    /* ── Page preloader ── */
    #page-loader {
      position: fixed;
      inset: 0;
      z-index: 9999;
      background: #F5F1E8;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      gap: 28px;
      transition: opacity 700ms cubic-bezier(0.4,0,0.2,1), visibility 700ms linear;
    }
    #page-loader.loader-hidden {
      opacity: 0;
      visibility: hidden;
      pointer-events: none;
    }
    .loader-logo {
      width: clamp(120px, 28vw, 200px);
      height: auto;
      display: block;
    }
    .loader-track {
      width: 100px;
      height: 1px;
      background: #D3C7A8;
      overflow: hidden;
    }
    .loader-fill {
      height: 100%;
      width: 0%;
      background: #B83333;
      animation: loader-sweep 2s cubic-bezier(0.4,0,0.2,1) forwards;
    }
    @keyframes loader-sweep {
      0%   { width: 0%; }
      50%  { width: 60%; }
      85%  { width: 88%; }
      100% { width: 100%; }
    }

    :root {
      --bg: #F1F0E2;
      --surface: #F8F7EC;
      --surface-2: #E8E7D6;
      --border: #DAD8C4;
      --text: #131516;
      --text-muted: #66675B;
      --text-dim: #6D6E62;
      --accent: #1F7349;
      --accent-soft: #B9D2C4;
      --accent-hover: #145636;
      --accent-ink: #FFFFFF;
      --accent-live: #9A3412;
      --accent-live-ink: #FFFFFF;
      --ff-head: "Neue Haas Display", system-ui, sans-serif;
      --ff-body: "Firme", system-ui, sans-serif;
      --ff-mono: "Firme", system-ui, sans-serif;
      --ticker-h: 0px;
      --fs-hero: clamp(3.25rem, 13vw, 11rem);
      --fs-h1: clamp(2.25rem, 6.5vw, 5rem);
      --fs-h2: clamp(1.75rem, 4vw, 3rem);
      --fs-h3: clamp(1.25rem, 2.2vw, 1.75rem);
      --fs-lead: clamp(1.1rem, 1.7vw, 1.4rem);
      --fs-body: clamp(1rem, 1.3vw, 1.0625rem);
      --fs-label: 0.75rem;
      --fs-sm: 0.8125rem;
      --fs-stat: clamp(2.5rem, 7vw, 6rem);
      --sp-1: 4px;
      --sp-2: 8px;
      --sp-3: 12px;
      --sp-4: 16px;
      --sp-5: 24px;
      --sp-6: 32px;
      --sp-7: 48px;
      --sp-8: 64px;
      --sp-9: 96px;
      --sp-10: 128px;
      --sp-11: 192px;
      --radius-sm: 2px;
      --radius-md: 4px;
      --radius-pill: 999px;
      --shadow-card: 0 1px 2px rgba(10,10,11,.06), 0 12px 32px -16px rgba(10,10,11,.18);
      --shadow-card-hover: 0 2px 4px rgba(10,10,11,.08), 0 20px 48px -20px rgba(10,10,11,.24);
      --ease: cubic-bezier(0.22, 1, 0.36, 1);
      --t-fast: 180ms var(--ease);
      --t-med: 320ms var(--ease);
      --t-slow: 600ms var(--ease);
      --maxw: 1320px;
      /* One measure for running text. Every paragraph on a page stops at the
         same place, so the right-hand edge of the text stays put as you
         scroll instead of moving section to section. 640px is roughly 58
         characters at lead size and 75 at body size — both inside the
         comfortable range. */
      --maxw-text: 640px;
      --zoom: 0.9;
      --nav-h: 72px;
      --nav-h-mobile: 60px;
      --tap: 44px;
    }

    * {
      box-sizing: border-box;
      margin: 0;
      /* Mobile WebKit/Blink paint their own grey-orange box over anything
         tappable on touch. The site already has its own press, hover and
         focus states, so the UA layer is only ever a second, uglier one. */
      -webkit-tap-highlight-color: transparent;
    }

    /* Global 0.9 zoom tightens the whole site's density. The catch: zoom scales
       the rendered box but NOT the viewport units inside it, so every 100svh
       element renders at 90% of the screen and leaves a band underneath. Each
       one has to divide by the same factor — hence the token, so they can't
       drift apart the way #hero had already drifted from body. */
    html {
      scroll-behavior: smooth;
      overflow-x: hidden;
      zoom: var(--zoom);
    }

    body {
      background: var(--bg);
      color: var(--text);
      font-family: var(--ff-body);
      font-size: var(--fs-body);
      line-height: 1.65;
      -webkit-font-smoothing: antialiased;
      min-height: calc(100svh / var(--zoom));
      display: flex;
      flex-direction: column;
    }

    main {
      display: flex;
      flex-direction: column;
      flex: 1;
    }

    /* ── Grain texture (site-wide) ── */
    .grain-overlay {
      position: fixed;
      inset: 0;
      z-index: 3;
      pointer-events: none;
      opacity: 0.1;
      mix-blend-mode: multiply;
      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch' result='noise'/%3E%3CfeColorMatrix in='noise' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0.59 0.11 0 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
      background-size: 180px 180px;
    }

    h1,
    h2,
    h3 {
      font-family: var(--ff-head);
      text-transform: uppercase;
      line-height: .92;
    }

    @media(prefers-reduced-motion:reduce) {
      html {
        scroll-behavior: auto;
      }

      *,
      *::before,
      *::after {
        animation: none !important;
        transition: none !important;
      }

      .reveal {
        opacity: 1 !important;
        transform: none !important;
        filter: none !important;
      }
    }

    /* ── Global Buttons ──
       One button look site-wide, set by the Collaborate "Send It Over"
       button: 2px accent outline on a transparent box at rest, solid accent
       fill with a white label on hover/focus, 180ms, no wipe. .btn-ghost is
       no longer a separate look — the class stays in the markup (and in the
       print rule below) but renders as a plain .btn. */
    .btn {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: var(--sp-2);
      font-family: var(--ff-mono);
      font-weight: 700;
      font-size: var(--fs-label);
      text-transform: uppercase;
      letter-spacing: 0.1em;
      padding: var(--sp-4) var(--sp-6);
      min-height: 48px;
      border-radius: 14px;
      background-color: transparent;
      color: var(--text);
      border: 2px solid var(--accent);
      text-decoration: none;
      cursor: pointer;
      transition: background-color var(--t-fast), border-color var(--t-fast), color var(--t-fast);
    }

    .btn:focus-visible {
      background-color: var(--accent-hover);
      border-color: var(--accent-hover);
      color: var(--accent-ink);
    }

    @media (hover: hover) {
      .btn:hover {
        background-color: var(--accent-hover);
        border-color: var(--accent-hover);
        color: var(--accent-ink);
      }
    }

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

    .skip-link {
      position: absolute;
      top: -100%;
      left: var(--sp-4);
      z-index: 10000;
      padding: var(--sp-3) var(--sp-5);
      background: var(--accent-live);
      color: var(--accent-live-ink);
      font-family: var(--ff-head);
      font-size: var(--fs-sm);
      text-decoration: none;
      transition: top var(--t-fast);
    }

    .skip-link:focus {
      top: var(--sp-4);
    }

    /* ── Navbar ── */
    .site-header {
      position: fixed;
      top: var(--ticker-h);
      left: 0;
      width: 100%;
      height: var(--nav-h);
      z-index: 100;
      background: transparent;
      border-bottom: 1px solid transparent;
      transition: background 300ms ease, backdrop-filter 300ms ease, box-shadow 300ms ease, border-color 300ms ease;
    }

    .site-header.scrolled {
      background: rgba(245, 241, 232, 0.72);
      backdrop-filter: blur(18px) saturate(170%);
      -webkit-backdrop-filter: blur(18px) saturate(170%);
      border-bottom-color: rgba(0, 0, 0, 0.06);
      box-shadow: 0 10px 28px rgba(0, 0, 0, 0.06);
    }

    /* ── Site logo — pinned to the browser corner, independent of the
       centered nav max-width so it always sits flush at the edge. ── */
    /* Both offsets below cancel the transparent padding baked into
       YOSCHI BLACK.png, the same correction the mobile rule already makes
       (see the .site-logo transform near the end of this file). The file is
       1890x1417 with ink only inside (311,532)-(1600,794), so the img box is
       far larger than the wordmark: 16.46% of the width is empty on the left
       and the ink's vertical centre sits 3.21% of the height above the box's.
       Left-pinning the BOX therefore left the glyphs 43px further in than
       --sp-6, unbalanced against the next-stop's --sp-6 on the right, and the
       old flat --logo-offset (16px, i.e. 7.3% of the 220px box) pushed them
       ~8px below the nav's centre line. Written against --logo-h, not as flat
       px, so both corrections track the scroll shrink the way the mobile rule
       does rather than drifting as the logo resizes. */
    .site-logo {
      position: absolute;
      left: calc(var(--sp-6) - 0.2196 * var(--logo-h, 220px));
      top: 50%;
      transform: translateY(calc(-50% + 0.0321 * var(--logo-h, 220px)));
      z-index: 2;
      display: flex;
      align-items: center;
    }

    .site-logo img {
      height: var(--logo-h, 220px);
      width: auto;
      display: block;
    }

    /* ── Next-stop pill ── */
    .nav-right {
      position: absolute;
      right: var(--sp-6);
      top: 50%;
      transform: translateY(-50%);
      display: flex;
      align-items: center;
      gap: var(--sp-4);
    }

    /* Not a chip. Every boxed variant of this — glass capsule, bordered stamp —
       read as a component dropped onto the page from somewhere else, because
       nothing else in this nav sits in a container. So: no border, no fill, no
       shadow. A pin and two lines of type, the way a tour poster prints a date. */
    .next-stop {
      display: inline-flex;
      flex-direction: column;
      align-items: flex-start;
      gap: 4px;
      text-decoration: none;
      white-space: nowrap;
    }

    /* 9px at --text-dim was legible in theory and squinted at in practice.
       11px, a notch darker and heavier, with tracking pulled back so it stops
       out-running the city underneath it. */
    .next-stop-label {
      font-family: var(--ff-mono);
      font-size: 0.6875rem;
      font-weight: 700;
      line-height: 1;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      color: var(--text-muted);
    }

    /* Pin lives on the city's own line and centres against it. Sitting it
       outside the stack meant it aligned to the two-line block instead, which
       is why it never lined up with the word it belongs to. */
    .next-stop-place {
      display: flex;
      align-items: center;
      gap: 6px;
    }

    /* Sized so the drawn pin matches the city's cap height — box-centring alone
       measured correct but read low, because lucide's pin fills its whole box
       while caps only fill part of the line box, leaving the glyph overhanging
       above and below the word. The extra 1px of bottom margin past the 4px
       that cancels the underline gutter sits its head on the cap band. */
    .next-stop-pin {
      width: 15px;
      height: 15px;
      flex: none;
      margin-bottom: 5px;
      color: var(--accent);
      transition: color 200ms ease, transform 200ms ease;
    }

    /* The city is the message: display face, heavy, so the glance lands on the
       place and not on the words introducing it. */
    .next-stop-city {
      font-family: var(--ff-head);
      font-size: 1.125rem;
      font-weight: 800;
      line-height: 1;
      letter-spacing: -0.015em;
      text-transform: uppercase;
      color: var(--text);
      padding-bottom: 4px;
      background-image: linear-gradient(var(--accent), var(--accent));
      background-repeat: no-repeat;
      background-position: 0 100%;
      background-size: 0 2px;
      transition: background-size 280ms ease;
    }

    .next-stop:focus-visible .next-stop-city { background-size: 100% 2px; }

    @media (hover: hover) {
      .next-stop:hover .next-stop-city { background-size: 100% 2px; }
    }

    .next-stop:focus-visible .next-stop-pin {
      color: var(--accent-hover);
      transform: translateY(-1px);
    }

    @media (hover: hover) {
      .next-stop:hover .next-stop-pin {
        color: var(--accent-hover);
        transform: translateY(-1px);
      }
    }

    .next-stop:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: 5px;
      border-radius: 2px;
    }

    @media (prefers-reduced-motion: reduce) {
      .next-stop-pin, .next-stop-city { transition: none; }
    }

    .nav-inner {
      max-width: var(--maxw);
      margin: 0 auto;
      height: 100%;
      padding: 0 var(--sp-6);
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .nav-links {
      position: relative;
      display: flex;
      align-items: center;
      list-style: none;
      gap: 0;
      padding: 4px;
      height: 48px;
      background: transparent;
      border: 1px solid transparent;
      border-radius: 999px;
    }

    .nav-links li { list-style: none; }

    .nav-links a {
      font-family: var(--ff-mono);
      font-size: var(--fs-label);
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.10em;
      color: rgba(10, 10, 11, 0.65);
      text-decoration: none;
      /* padding-top > 0, bottom 0 — flex align-items:center centers the
         LINE BOX (font ascent+descent), not the glyph ink. This is
         uppercase-only text in a font with real descender metrics, so the
         reserved descender space below the cap-height goes unused and the
         word visually sits high. Measured ~1.5px high via canvas ink-pixel
         scan; a few px of top padding eats into the centered space from
         the top edge, nudging the visible glyphs down to true center. */
      padding: 3px 18px 0;
      height: 36px;
      display: flex;
      align-items: center;
      border-radius: 999px;
      white-space: nowrap;
      position: relative;
      z-index: 1;
      transition: color 200ms, background 200ms;
    }

    /* Underline Grow hover — thin ink line sweeps in from center.
       Skips the active link: brackets already mark it, a second
       treatment on top would compete. */
    .nav-links > li > a:not(.nav-view-active)::after {
      content: '';
      position: absolute;
      left: 50%;
      right: 50%;
      bottom: 3px;
      height: 1.4px;
      background: var(--accent);
      transition: left 200ms cubic-bezier(0.4, 0, 0.2, 1),
                  right 200ms cubic-bezier(0.4, 0, 0.2, 1);
    }

    .nav-links > li > a:not(.nav-view-active):focus-visible {
      color: var(--text);
    }

    @media (hover: hover) {
      .nav-links > li > a:not(.nav-view-active):hover {
        color: var(--text);
      }
    }
    .nav-links > li > a:not(.nav-view-active):focus-visible::after {
      left: 16px;
      right: 16px;
    }

    @media (hover: hover) {
      .nav-links > li > a:not(.nav-view-active):hover::after {
        left: 16px;
        right: 16px;
      }
    }

    /* Brackets — plain corner ticks framing the active label, no fill.
       Solid ink border only, no backdrop-filter: any glass/blur pulls
       tint from whatever photo or blur sits behind it, which read as
       stray color and threw off the left/right balance while scrolling. */
    .nav-indicator {
      position: absolute;
      z-index: 0;
      pointer-events: none;
      visibility: hidden; /* stays hidden until JS sets a real position — unstyled it sits at
        left:0/top:0 (default DOM position, right by the logo) and flashes there on reload
        before layout/fonts settle */
      transition: left 300ms cubic-bezier(0.4, 0, 0.2, 1),
                  top 300ms cubic-bezier(0.4, 0, 0.2, 1),
                  width 300ms cubic-bezier(0.4, 0, 0.2, 1),
                  height 300ms cubic-bezier(0.4, 0, 0.2, 1);
    }
    .nav-indicator::before,
    .nav-indicator::after {
      content: '';
      position: absolute;
      top: 2px;
      bottom: 2px;
      width: 6px;
      border: 1.5px solid var(--accent);
    }
    .nav-indicator::before { left: 0; border-right: none; border-radius: 5px 0 0 5px; }
    .nav-indicator::after  { right: 0; border-left: none; border-radius: 0 5px 5px 0; }

    .nav-hamburger { display: none; }

    .nav-break { display: none; }

    /* Dropdown (Gigs / Services) — shared markup used in both the desktop
       pill nav and the mobile full-screen overlay; positioning differs. */
    .nav-drop { position: relative; }

    .nav-drop-trigger {
      font-family: var(--ff-mono);
      font-size: var(--fs-label);
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.10em;
      color: rgba(10, 10, 11, 0.65);
      background: none;
      border: none;
      cursor: pointer;
      padding: 3px 18px 0; /* same optical-centering nudge as .nav-links a */
      height: 36px;
      display: flex;
      align-items: center;
      gap: 4px;
      border-radius: 999px;
      white-space: nowrap;
      position: relative;
      transition: color 200ms, background 200ms;
    }

    /* Active trigger — same treatment as an active nav link. The
       .nav-indicator span (brackets) already picks this up generically. */
    .nav-drop-trigger.nav-view-active {
      color: var(--accent);
      font-weight: 700;
      background: transparent;
    }

    /* Underline Grow hover — matches .nav-links a, skips the active trigger
       since brackets already mark it. */
    .nav-drop-trigger:not(.nav-view-active)::after {
      content: '';
      position: absolute;
      left: 50%;
      right: 50%;
      bottom: 3px;
      height: 1.4px;
      background: var(--accent);
      transition: left 200ms cubic-bezier(0.4, 0, 0.2, 1),
                  right 200ms cubic-bezier(0.4, 0, 0.2, 1);
    }

    .nav-drop-trigger:not(.nav-view-active):focus-visible,
    .nav-drop-trigger:not(.nav-view-active)[aria-expanded="true"] {
      color: var(--text);
    }

    @media (hover: hover) {
      .nav-drop-trigger:not(.nav-view-active):hover {
        color: var(--text);
      }
    }
    .nav-drop-trigger:not(.nav-view-active):focus-visible::after,
    .nav-drop-trigger:not(.nav-view-active)[aria-expanded="true"]::after {
      left: 16px;
      right: 16px;
    }

    @media (hover: hover) {
      .nav-drop-trigger:not(.nav-view-active):hover::after {
        left: 16px;
        right: 16px;
      }
    }

    .nav-drop-arrow {
      width: 14px;
      height: 14px;
      flex: none;
      transition: transform 200ms;
    }

    .nav-drop-trigger[aria-expanded="true"] .nav-drop-arrow { transform: rotate(180deg); }

    @media (hover: hover) {
      .nav-drop:hover .nav-drop-arrow { transform: rotate(180deg); }
    }

    .nav-drop-menu {
      list-style: none;
      display: none;
      flex-direction: column;
      margin: 0;
      padding: 6px;
      gap: 2px;
    }

    /* Click/Enter on the trigger owns .open. :focus-within used to open it
       too, which left the menu stuck visible after a sub-link was clicked —
       the click navigates, JS drops .open, but the link keeps focus. */
    .nav-drop.open .nav-drop-menu { display: flex; }

    @media (hover: hover) {
      .nav-drop:hover .nav-drop-menu { display: flex; }
    }

    .nav-drop-menu a {
      font-family: var(--ff-mono);
      font-size: var(--fs-label);
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.08em;
      color: rgba(10, 10, 11, 0.65);
      text-decoration: none;
      white-space: nowrap;
      transition: color 200ms, background 200ms;
      display: block;
      padding: 8px 4px;
    }

    /* Row highlight — flat ink tint, no glass/blur, matches the brackets/
       underline's solid-ink language instead of a bright pill fill. */
    .nav-drop-menu a:focus-visible {
      color: var(--accent);
      background: rgba(10, 10, 11, 0.06);
    }

    @media (hover: hover) {
      .nav-drop-menu a:hover {
        color: var(--accent);
        background: rgba(10, 10, 11, 0.06);
      }
    }
    .nav-drop-menu a.nav-view-active {
      color: var(--accent);
      font-weight: 700;
      background: rgba(10, 10, 11, 0.045);
    }

    @media (min-width: 768px) {
      /* top:100% (flush, zero gap) + padding-top standing in for the old
         8px offset — :hover matches on any descendant regardless of paint
         position, but the 8px gap used to be empty space belonging to
         neither the trigger nor the menu, so crossing it on the way down
         dropped out of both hover boxes and the menu closed mid-move. */
      .nav-drop-menu {
        position: absolute;
        top: 100%;
        left: 50%;
        transform: translateX(-50%);
        min-width: 168px;
        padding-top: 14px;
        background: rgba(245, 241, 232, 0.92);
        backdrop-filter: blur(24px) saturate(1.5);
        -webkit-backdrop-filter: blur(24px) saturate(1.5);
        border: 1px solid rgba(10, 10, 11, 0.11);
        border-radius: 16px;
        z-index: 10;
      }

      @media (hover: hover) {
         {
          position: absolute;
          top: 100%;
          left: 50%;
          transform: translateX(-50%);
          min-width: 168px;
          padding-top: 14px;
          background: rgba(245, 241, 232, 0.92);
          backdrop-filter: blur(24px) saturate(1.5);
          -webkit-backdrop-filter: blur(24px) saturate(1.5);
          border: 1px solid rgba(10, 10, 11, 0.11);
          border-radius: 16px;
          z-index: 10;
        }
      }

      .nav-drop-menu a { padding: 9px 14px; border-radius: 10px; }
    }

    /* Overlay context: dropdown trigger matches the big overlay-links style;
       submenu items sit smaller/quieter beneath it, inline (no floating). */
    #nav-overlay .nav-drop { display: flex; flex-direction: column; align-items: flex-start; }

    #nav-overlay .nav-drop-trigger {
      font-family: var(--ff-head);
      font-size: var(--fs-h3);
      text-transform: uppercase;
      color: var(--text);
      padding: 0;
      height: auto;
    }

    #nav-overlay .nav-drop-trigger[aria-expanded="true"] { color: var(--text); }
    #nav-overlay .nav-drop-trigger::after { display: none; }

    @media (hover: hover) {
      #nav-overlay .nav-drop-trigger:hover { color: var(--accent); }
    }

    #nav-overlay .nav-drop-arrow {
      width: calc(20px / var(--zoom));
      height: calc(20px / var(--zoom));
      stroke-width: 2;
      color: var(--text-muted);
    }

    #nav-overlay .nav-drop-trigger[aria-expanded="true"] .nav-drop-arrow { color: var(--accent); }

    /* The sub-list opens downward out of the row that was tapped: the wrapper
       animates 0fr -> 1fr, so everything under it reflows down and nothing
       above it moves. display:none couldn't be animated, hence the wrapper. */
    #nav-overlay .nav-drop-wrap {
      display: grid;
      grid-template-rows: 0fr;
      transition: grid-template-rows 340ms cubic-bezier(0.22, 1, 0.36, 1);
      width: 100%;
    }

    #nav-overlay .nav-drop.open .nav-drop-wrap { grid-template-rows: 1fr; }

    #nav-overlay .nav-drop-menu {
      display: flex;
      align-items: flex-start;
      gap: 0;
      margin: 0;
      padding: 0;
      overflow: hidden;
      min-height: 0;
      /* held visible through the close so the rows clip away rather than
         blink out, then hidden so the links leave the tab order */
      visibility: hidden;
      transition: visibility 0s 340ms;
    }

    #nav-overlay .nav-drop.open .nav-drop-menu { visibility: visible; transition: visibility 0s; }

    #nav-overlay .nav-drop-menu li:first-child { padding-top: calc(10px / var(--zoom)); }

    #nav-overlay .nav-drop-menu a {
      font-family: var(--ff-body);
      font-size: calc(13px / var(--zoom));
      font-weight: 500;
      letter-spacing: 0.12em;
      color: var(--text-muted);
      padding: 0;
      /* row pitch stays a 40px touch target even though the type is 13px */
      display: flex;
      align-items: center;
      min-height: calc(40px / var(--zoom));
    }

    #nav-overlay .nav-drop-menu a.nav-view-active { color: var(--accent); }

    @media (hover: hover) {
      #nav-overlay .nav-drop-menu a:hover { color: var(--accent); }
    }

    @media (max-width: 1160px) {
      /* Top header stays, but as a bare hamburger trigger — the full pill
         nav + dropdowns don't fit/work on touch, so mobile gets the same
         full-screen overlay as desktop's "more" affordance. Measured (real
         browser, getBoundingClientRect): nav-links vs. the next-stop
         collide 768-899px; separately, nav-links (centered in .nav-inner)
         vs. the corner-pinned .site-logo collide 900-1130px since nav-inner
         centers in the full max-width box with no awareness of the logo's
         reserved width. Combined clear point is ~1140px — breakpoint set to
         1160px for margin. Old value was 767px (phone only), then 899px
         (fixed pill collision but missed the logo collision above it). */
      :root { --nav-h: var(--nav-h-mobile); }

      .nav-links { display: none; }
      .next-stop { display: none; }

      .nav-hamburger {
        display: flex;
        align-items: center;
        justify-content: center;
        width: var(--tap);
        height: var(--tap);
        min-width: var(--tap);
        min-height: var(--tap);
        margin-left: auto;
        background: transparent;
        border: none;
        border-radius: 999px;
        color: var(--text);
        cursor: pointer;
        transition: background 200ms;
      }

      @media (hover: hover) {
        .nav-hamburger:hover { background: rgba(10, 10, 11, 0.08); }
      }

      .site-logo img { max-height: 96px; }

      .view.active { padding-bottom: var(--sp-6); }

      /* Home view: skip observer — show reveals immediately on mobile */
      #view-home .reveal,
      #view-home .reveal-right,
      #view-home .reveal-clip {
        opacity: 1 !important;
        clip-path: none !important;
        transition: none !important;
      }
    }

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

    /* ── Mobile Overlay: "Bloom" ──────────────────────────────────────────
       The panel opens as a circle growing out of the hamburger itself, so
       the menu reads as coming from the control that summoned it rather
       than sliding in from nowhere. Origin is the burger's ink centre —
       --burger-x is overridden per breakpoint (the phone rule pulls the
       button 12px left); --burger-y is half the mobile header height.
       150% radius guarantees the circle covers the far corner on any
       viewport, so no size query is needed. */
    #nav-overlay {
      /* Bloom origin = the burger's ink centre: left:var(--sp-4) minus the
         -12px optical pull, plus half the 44px target. */
      --burger-x: 26px;
      --burger-y: calc(var(--nav-h-mobile) / 2);
      --bloom: 640ms cubic-bezier(0.76, 0, 0.24, 1);
      position: fixed;
      inset: 0;
      background: var(--bg);
      z-index: 150;
      display: flex;
      flex-direction: column;
      justify-content: flex-start;
      align-items: center;
      gap: var(--sp-7);
      padding-block: max(var(--sp-8), 12vh) var(--sp-9);
      overflow-y: auto;
      visibility: hidden;
      pointer-events: none;
      clip-path: circle(0px at var(--burger-x) var(--burger-y));
      transition: clip-path var(--bloom), visibility 0s 640ms;
    }

    #nav-overlay.open {
      visibility: visible;
      pointer-events: all;
      clip-path: circle(150% at var(--burger-x) var(--burger-y));
      transition: clip-path var(--bloom), visibility 0s;
    }

    /* Links settle in behind the circle's leading edge, one after another.
       --i is set per <li> in the markup. */
    .overlay-links > li {
      opacity: 0;
      transform: translateY(14px);
      transition: opacity 300ms var(--ease), transform 400ms cubic-bezier(0.22, 1, 0.36, 1);
    }

    #nav-overlay.open > .overlay-links > li {
      opacity: 1;
      transform: none;
      transition-delay: calc(230ms + var(--i, 0) * 48ms);
    }

    /* ── Hamburger mark: "Pivot" ──────────────────────────────────────────
       Three bars that cross into an X while the whole mark turns a half
       rotation. Bars are real elements rather than a swapped-in lucide
       icon, so open and close are one continuous transition instead of two
       separate glyphs. */
    .hamburger-bars {
      position: relative;
      display: block;
      width: 22px;
      height: 16px;
      transition: transform 460ms cubic-bezier(0.76, 0, 0.24, 1);
    }

    .hamburger-bars i {
      position: absolute;
      left: 0;
      width: 100%;
      height: 2px;
      background: currentColor;
      border-radius: 2px;
      transition: transform 420ms cubic-bezier(0.76, 0, 0.24, 1), opacity 180ms var(--ease);
    }

    .hamburger-bars i:nth-child(1) { top: 1px; }
    .hamburger-bars i:nth-child(2) { top: 7px; }
    .hamburger-bars i:nth-child(3) { top: 13px; }

    .nav-hamburger[aria-expanded="true"] .hamburger-bars { transform: rotate(180deg); }
    .nav-hamburger[aria-expanded="true"] .hamburger-bars i:nth-child(1) { transform: translateY(6px) rotate(45deg); }
    .nav-hamburger[aria-expanded="true"] .hamburger-bars i:nth-child(2) { opacity: 0; transform: scaleX(0.2); }
    .nav-hamburger[aria-expanded="true"] .hamburger-bars i:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

    @media (prefers-reduced-motion: reduce) {
      #nav-overlay,
      #nav-overlay.open {
        clip-path: none;
        opacity: 0;
        transition: opacity var(--t-fast), visibility 0s var(--t-fast);
      }
      #nav-overlay.open { opacity: 1; transition: opacity var(--t-fast), visibility 0s; }
      .overlay-links > li { opacity: 1; transform: none; }
      .hamburger-bars,
      .hamburger-bars i { transition-duration: 1ms; }
    }

    .overlay-links {
      list-style: none;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: var(--sp-7);
    }

    .overlay-links a {
      font-family: var(--ff-head);
      font-size: var(--fs-h3);
      text-transform: uppercase;
      color: var(--text);
      text-decoration: none;
      transition: color var(--t-fast);
    }

    @media (hover: hover) {
      .overlay-links a:hover {
        color: var(--accent);
      }
    }

    /* ── Hero ── */
    @keyframes fadeUp {
      from {
        opacity: 0;
        transform: translateY(20px);
      }

      to {
        opacity: 1;
        transform: translateY(0);
      }
    }

    /* Sticky, not fixed: the photo holds still while the page scrolls over it,
       but it stays in flow and bounded by the home view, so it rubber-bands
       with the page and is already gone by the footer. A fixed layer would
       stay pinned to the viewport and show through under the footer on the
       elastic overscroll every Mac and phone does at the end of a page. */
    #hero {
      position: sticky;
      top: 0;
      min-height: calc(100svh / var(--zoom));
      display: flex;
      align-items: flex-end;
      overflow: hidden;
      padding: 0;
    }

    .hero-bg {
      position: absolute;
      inset: 0;
      z-index: 0;
      background-color: var(--surface-2);
      /* -v2 is the original file with 210px of studio wall extended off its
         LEFT edge (the outermost clean columns tiled outward — that strip is
         empty wall and floor, the first real pixel is a faint shoe shadow at
         x120). Measured on the source three ways — tight silhouette bbox,
         loose bbox including the low-contrast hand, and ink-mass centroid —
         all three put the content's centre at x~1090 while the 2400px frame
         centred on x1200, so the subject sat ~110px left of centre *inside
         the photo*. On any window wider than the photo's own aspect, `cover`
         shows the full width and there is no pan freedom left, so no
         background-position value could fix that. Padding, not cropping:
         cropping the right to match would have zoomed the whole picture in
         ~10% at every size and started clipping the lamp off the top.
         At 2610x1600 the content centre and the frame centre agree to 4px. */
      background-image: url(/assets/photos/yoschi-hero-desktop-v2.jpg);
      /* cover, not a width percentage: 115% sized off the container's width
         only, so on a tall window the photo ran out before the fold. */
      background-size: cover;
      /* Horizontal is `center` everywhere now (see above). Vertical 80%
         rather than centre because the composition is bottom-weighted: he
         sits on the floor, so the slack belongs above him, not below. The
         band that must survive is y506 (hat) to y1486 (floor under the shoe);
         80% is inside the valid range for every aspect from 1.63 to ~2.4 and
         holds his hat at a steady 23-27% of frame height across all of them.
         Overridden below outside that range. */
      --hero-pos: center 80%;
      background-position: var(--hero-pos);
      /* ── Scroll dissolve ──────────────────────────────────────────────
         The photo has to *end* somewhere, and a hard horizontal cut where
         the first section's opaque background slides over it is what reads
         as fake. So the photo is masked out just above that cut instead:
         --hero-seam (0-1, set by the header's scroll handler) is exactly
         where the incoming section's top edge crosses the sticky hero, and
         the mask runs to transparent by the time it gets there — the image
         dissolves into the page ground rather than being sliced by it.

         Masking, not a scrim: washing an eggshell gradient over the photo
         goes milky on the mobile crop's dark trousers. A mask removes the
         pixels, so both crops land on the same eggshell.

         Feather is zero at rest — the banner is untouched full-bleed until
         the page actually moves — but it opens ~4x faster than the seam
         travels, so the fade band is always several times taller than the
         sliver of photo already covered. It can never read as a cut.

         And the ramp is a 6-stop ease, not a straight two-stop fade: a
         linear mask has a visible corner where the gradient begins, and
         that corner is exactly what looks like a drawn line. */
      --seam: calc(var(--hero-seam, 1) * 100%);
      --feather: min(22vh, calc(var(--hero-fade, 0) * 300vh));
      --f0: calc(var(--seam) - var(--feather));
      --hero-mask: linear-gradient(to bottom,
        #000 var(--f0),
        rgba(0,0,0,0.94) calc(var(--f0) + var(--feather) * 0.15),
        rgba(0,0,0,0.76) calc(var(--f0) + var(--feather) * 0.35),
        rgba(0,0,0,0.44) calc(var(--f0) + var(--feather) * 0.58),
        rgba(0,0,0,0.16) calc(var(--f0) + var(--feather) * 0.78),
        rgba(0,0,0,0.04) calc(var(--f0) + var(--feather) * 0.91),
        transparent var(--seam));
      -webkit-mask-image: var(--hero-mask);
      mask-image: var(--hero-mask);
      /* Defocus stays gentle on purpose: past ~8px the subject turns into
         coloured blobs, which looks like a bug rather than depth of field. */
      filter: blur(calc(var(--hero-fade, 0) * 6px));
      opacity: calc(1 - var(--hero-fade, 0) * 0.2);
      transform: scale(calc(1 + var(--hero-fade, 0) * 0.02));
      will-change: filter, opacity, transform;
    }

    @media (prefers-reduced-motion: reduce) {
      /* Keep the dissolve (it is not motion), drop the push-in. */
      .hero-bg { transform: none; }
    }

    /* Everything after the hero scrolls over it, so it has to sit above the
       sticky photo and carry an opaque ground of its own. Sibling selector so
       a new home section can't forget either half. */
    #hero ~ * {
      position: relative;
      z-index: 1;
      background: var(--bg);
    }

    #hero h1 {
      font-family: var(--ff-head);
      font-size: var(--fs-hero);
      font-weight: 800;
      text-transform: uppercase;
      color: #F4F2ED;
      letter-spacing: -0.02em;
      line-height: 0.88;
      text-shadow: 0 2px 48px rgba(0, 0, 0, 0.85), 0 0 80px rgba(0, 0, 0, 0.4);
      animation: fadeUp 440ms cubic-bezier(0.22, 1, 0.36, 1) 100ms both;
    }

    /* ── View system ── */
    .view {
      display: none;
    }

    @keyframes pageEnter {
      from { opacity: 0; transform: translateY(10px); }
      to   { opacity: 1; transform: translateY(0); }
    }

    .view.active {
      display: block;
    }

    .view.active:not(#view-home) {
      animation: pageEnter 260ms cubic-bezier(0.22, 1, 0.36, 1) both;
    }

    .view.active:not(#view-home) {
      padding-top: calc(var(--nav-h) + var(--ticker-h));
      flex: 1;
    }

    /* Active nav link — indicator span handles the bracket marks.
       Scoped to > li > a: a bare ".nav-links a" also descendant-matches
       the nested .nav-drop-menu links (Past/Upcoming etc.), and this
       rule's "background: transparent" was winning the cascade over
       their own active-row tint and blanking it out. */
    .nav-links > li > a.nav-view-active {
      color: var(--accent);
      font-weight: 700;
      background: transparent;
    }

    /* ── Home hero content ── */
    .home-image {
      position: absolute;
      inset: 0;
      overflow: hidden;
    }

    @media (max-width: 767px) {
      .hero-bg {
        background-image: url(/assets/photos/yoschi-hero-mobile.jpg);
        background-size: cover;
        background-position: center 12%;
      }

    }

    /* ── Home hub — story teaser ── */
    /* The hero now fills the whole viewport, so the first scroll is a hard cut
       from a full-bleed photo into flat eggshell. That cut is the strongest
       moment on the page, so the tagline gets a band of its own to land in
       rather than a thin caption strip under the picture. */
    .home-teaser {
      background: var(--bg);
      display: flex;
      align-items: center;
      justify-content: center;
      /* Was 38svh + 3.5rem padding: that reserved a third of the viewport
         for one line of type, so the tagline floated in a band of cream
         with ~78px of slack above and below it on top of the padding. The
         band still exists, it just fits the type now, and with no min-height
         the gap either side of the tagline is pure section padding -- the
         same rhythm as every other block on the page. */
      padding: clamp(var(--sp-5), 4vw, var(--sp-7)) clamp(var(--sp-5), 6vw, var(--sp-9));
    }

    .home-teaser-inner {
      margin-inline: auto;
      text-align: center;
    }

    .home-teaser-rule {
      display: block;
      width: 36px;
      height: 2px;
      background: var(--accent);
      margin: 0 auto clamp(1rem, 1.8vw, 1.5rem);
    }

    .home-teaser-text {
      font-family: var(--ff-body);
      font-size: clamp(1.05rem, 1.5vw, 1.25rem);
      line-height: 1.85;
      color: rgba(10, 10, 11, 0.62);
      margin-bottom: var(--sp-5);
    }

    .home-teaser-punch {
      font-family: var(--ff-head);
      /* One line at every width, sized to read as a tagline rather than a
         headline. "GLOBAL SOUNDS. LOCAL ROOTS." inks at 13.44x its
         font-size in Neue Haas Display; the widest that still fits the band
         is ~6.5vw, so 4.6vw fills about two thirds of the measure and
         leaves cream on both sides. 3.8rem caps it past ~1320px; the
         1.2rem floor stops phones under ~420px dropping to body-copy size
         (at 320px that floor inks 258 of 272 available — the tightest
         case, still clear). ponytail: all three numbers are tuned to this
         exact string — a longer tagline needs the 13.44x measure re-taken
         and the floor re-checked at 320px. html{overflow-x:hidden} absorbs
         a font-fallback overrun rather than letting it scroll the page. */
      margin-inline: auto;
      white-space: nowrap;
      font-size: clamp(1.2rem, 4.6vw, 3.8rem);
      font-weight: 800;
      text-transform: uppercase;
      color: var(--text);
      line-height: 0.92;
      letter-spacing: -0.04em;
      /* -0.04em tracking squeezes the word spaces too, and on one line the
         sentence break lands mid-run — "SOUNDS. LOCAL" closes up into a
         single word. Widening only the spaces separates the two statements
         without loosening the tight display set. */
      word-spacing: 0.12em;
    }

    /* ── Section shared ── */
    .section-inner {
      max-width: var(--maxw);
      margin-inline: auto;
    }

    section {
      padding-block: clamp(var(--sp-5), 4vw, var(--sp-7));
      padding-inline: 20px;
    }

    @media (min-width: 480px) {
      section { padding-inline: 24px; }
    }

    @media (min-width: 768px) {
      section { padding-inline: 40px; }
    }

    @media (min-width: 1024px) {
      section { padding-inline: 48px; }
    }

    @media (min-width: 1280px) {
      section { padding-inline: 64px; }
    }

    @media (min-width: 1680px) {
      section { padding-inline: 0; }
    }

    section[id] {
      scroll-margin-top: calc(var(--nav-h) + var(--ticker-h) + var(--sp-5));
    }

    .eyebrow {
      font-family: var(--ff-mono);
      font-size: var(--fs-label);
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.2em;
      color: var(--accent);
      margin-bottom: var(--sp-5);
      display: inline-block;
      border-bottom: 1px solid currentColor;
      padding-bottom: 3px;
    }

    /* ── Story ── */
    /* No bespoke padding: the 64/24 split was propping up the old full-bleed
       portrait and left the block sitting low in its own band. #story now
       takes the same padding-block rhythm as every other section. */

    .story-grid {
      display: grid;
      /* #story used to run edge to edge because the portrait was full-bleed.
         A circle isn't, so the row now sits on the same measure as every
         other homepage section. */
      max-width: var(--maxw);
      margin-inline: auto;
      /* Both tracks are bounded and the pair is centred, so leftover width
         becomes equal margins either side instead of a wedge of dead cream
         to the right of the paragraph -- which is what made the block read
         as unplaced. 46rem is the 62ch cap on .story-lead-full expressed at
         the track level; whichever is smaller wins, so the text never
         outruns its measure. */
      grid-template-columns: clamp(240px, 28vw, 330px) minmax(0, 46rem);
      justify-content: center;
      gap: clamp(var(--sp-6), 4.5vw, var(--sp-8));
      /* A disc and four lines of text are never the same height; centring
         the text on the circle's midline is the only alignment that reads
         as deliberate at every width. */
      align-items: center;
    }

    @media (min-width: 768px) {
      .story-prose {
        padding: 0;
      }
    }

    /* .story-portrait-wrap carries the reveal-right slide-in animation, and
       is now the circle itself.

       The press shot sits on a light studio backdrop, not on the page's
       cream, so a plain circular crop reads as a disc pasted onto the page.
       brightness() lifts that backdrop until it clips to white; a cream
       layer multiplied over the whole frame then maps white back to exactly
       var(--bg), while leaving the black hat, shades and trousers alone --
       multiplying near-black by anything stays near-black. The backdrop
       becomes the page and only he is left. isolation keeps the multiply
       inside the figure instead of tinting what sits behind it, and the
       base must be #fff, not var(--bg): cream x cream multiplies down to
       olive.

       ponytail: this depends on the photo having a plain light backdrop.
       Swap in a location shot and the blend stops working -- then drop the
       ::after and put a border back on the circle. */
    .story-portrait-wrap {
      grid-column: 1;
      grid-row: 1;
      position: relative;
      isolation: isolate;
      aspect-ratio: 1;
      border-radius: 50%;
      overflow: hidden;
      background: #fff;
    }

    .story-portrait-wrap::after {
      content: "";
      position: absolute;
      inset: 0;
      background: var(--bg);
      mix-blend-mode: multiply;
      pointer-events: none;
    }

    .story-portrait {
      position: absolute;
      inset: 0;
      overflow: hidden;
      background: transparent;
    }

    /* display:contents so the <img> positions against the circle itself;
       the <source> swap for the mobile file still applies. */
    .story-portrait picture {
      display: contents;
    }

    /* Head-and-torso crop, picked by rendering a grid of candidates rather
       than guessed: the image is drawn at 185% of the disc's height, which
       is 123.26% of its width at the 1066x1600 source ratio, and offset to
       put the hat inside the top edge with headroom and him centred across
       the disc. left/top are the equivalent of background-position 28% 4%.
       ponytail: the three numbers are tied to this photo's framing -- a new
       press shot needs the crop re-picked, not nudged. */
    .story-portrait img {
      position: absolute;
      display: block;
      width: 123.26%;
      height: auto;
      left: -6.51%;
      top: -3.4%;
      filter: brightness(1.12) contrast(1.04) saturate(0.96);
    }

    .story-prose {
      grid-column: 2;
      grid-row: 1;
      display: flex;
      flex-direction: column;
      justify-content: center;
      padding-top: 0;
    }

    .story-lead {
      font-size: clamp(1.1rem, 1.7vw, 1.375rem);
      font-weight: 400;
      color: rgba(10, 10, 11, 0.72);
      line-height: 1.7;
      margin-bottom: 0;
      max-width: var(--maxw-text);
    }

    /* Scoped to the homepage story block only — doesn't touch .eyebrow or
       .story-lead elsewhere (placeholder sections). */
    /* The tagline band directly above is 5rem display type. A 1.9rem display
       ABOUT under it read as a competing headline, so this drops to a mono
       label with the same 2px accent rule the tagline band uses — same family
       of marks, one clear hierarchy. */
    .story-prose .home-head {
      /* Same 24px opening as every other section rule; the paragraph has no
         padding of its own to make up the difference. */
      margin-bottom: var(--sp-5);
    }

    /* Copy is the client's, unchanged. Three things were making it hard to
       read: 60 words of uppercase (no ascenders, so the eye loses its place),
       no measure cap (~110 characters a line at 1440), and 0.95rem × the 0.9
       page zoom = 15.2px on a phone. */
    .story-lead-full {
      font-family: var(--ff-body);
      font-weight: 400;
      text-transform: none;
      letter-spacing: 0;
      font-size: clamp(1.25rem, 1.55vw, 1.4375rem);
      line-height: 1.66;
      color: rgba(19, 21, 22, 0.78);
      max-width: 62ch;
    }

    .story-lead-strong {
      display: inline-block;
      font-family: var(--ff-head);
      font-weight: 700;
      font-size: clamp(2.1rem, 3vw, 2.75rem);
      line-height: 0.9;
      letter-spacing: -0.02em;
      color: var(--text);
      margin-right: 0.18em;
      vertical-align: -0.1em;
    }

    /* About: the name is the section's anchor, so it is set as a display word
       rather than a bold run-in — all caps and a clear step above the ABOUT
       header it sits under. Scoped to the lead paragraph: Collaborate puts a
       whole sentence in .story-lead-strong, which must stay sentence case. */
    .story-lead-full .story-lead-strong {
      text-transform: uppercase;
      font-size: clamp(2.6rem, 4vw, 3.6rem);
      letter-spacing: -0.025em;
    }

    @media (min-width: 768px) {
      .story-prose .eyebrow {
        margin-bottom: var(--sp-6);
      }
    }

    @media (max-width: 767px) {
      section {
        padding-block: var(--sp-6);
      }

      .story-grid {
        display: flex;
        flex-direction: column;
        gap: var(--sp-6);
      }

      .story-lead-full {
        font-size: 1.2rem;
        line-height: 1.62;
      }

      .story-lead-strong {
        font-size: 2.1rem;
      }

      .story-lead-full .story-lead-strong {
        font-size: 2.5rem;
      }

      .story-portrait-wrap {
        width: min(68vw, 280px);
        min-height: 0;
        order: -1;
        margin: 0 auto;
      }

    }

    /* ── Work ── */
    .section-header {
      margin-top: var(--sp-6);
      margin-bottom: 0;
    }

    /* Home-page teaser sections sit mid-page, not right under the header
       — they don't want the universal top gap the other pages get. */
    #home-gigs .section-header,
    #home-latest .section-header {
      margin-top: 0;
    }

    /* ── Homepage section header (About / Upcoming Gigs / Past Gigs / Releases) ──
       One treatment for every section on the home view, so the page reads as
       one document instead of four: left-aligned over the content it opens,
       display face at a step above the largest text in the section below it
       (~28px vs the 25px venue names) and well under the 66px teaser tagline,
       closed by a hairline with a short accent segment on it. The two gig
       tiers keep their green second word; <em> carries it, nothing else.

       --head-gutter lets a header widen to match a list that hangs its rows
       into a gutter, so every horizontal line in a section starts and ends at
       the same x. */
    .home-head {
      --head-gutter: 0px;
      margin: 0 calc(var(--head-gutter) * -1) 0;
      padding: 0 var(--head-gutter) var(--sp-3);
      border-bottom: 1px solid var(--border);
      position: relative;
    }

    .home-head h2 {
      font-family: var(--ff-head);
      font-size: clamp(1.25rem, 2.1vw, 1.75rem);
      font-weight: 800;
      line-height: 1;
      letter-spacing: -0.015em;
      text-transform: uppercase;
      color: var(--text);
      margin: 0;
    }

    /* One emphasis device for every home header: the second word drops out of
       the display face into Georgia italic lowercase, the way SAY hello. reads
       on the Contact page. It stays black — the accent already has a job here
       (the 56px segment on the rule below), and colouring the word as well
       made two marks compete for the same emphasis. */
    .home-head h2 em {
      font-family: Georgia, "Times New Roman", ui-serif, serif;
      font-style: italic;
      font-weight: 400;
      font-size: 1.06em;   /* Georgia's x-height runs small beside Neue Haas */
      /* The h2's -0.015em tracking also squeezes the space before the italic,
         which the serif's own sidebearing doesn't make up. */
      margin-left: 0.06em;
      letter-spacing: 0;
      text-transform: none;
      color: var(--text);
    }

    /* Gig heads keep the display face straight through and mark the noun in
       accent instead of dropping into Georgia italic. */
    /* The h2's -0.015em tracking eats the word space; 0.2em opens it back up. */
    .home-head h2 .head-accent { color: var(--accent); margin-left: 0.08em; }

    .home-head::after {
      content: "";
      position: absolute;
      left: var(--head-gutter);
      bottom: -1px;
      width: 56px;
      height: 2px;
      background: var(--accent);
    }

    /* A second header inside one section (Past Gigs under Upcoming Gigs). */
    .home-head--stacked { margin-top: var(--sp-7); }

    /* ── One vertical rhythm for the home view ─────────────────────────
       Three intervals, nothing else:
         96px  between sections   (48 padding-block each side)
         48px  between blocks inside a section (stacked header, CTA)
         24px  from a section rule down to the first thing under it

       The last one is optical, not boxed: the gig rows and the contact
       rows each open with 12px of their own padding, so their containers
       take 12 and the row padding makes up the rest. The releases grid
       has no such padding, so it takes the full 24. Before this, the
       three sections opened at 11px, 22px and 34px under their rules. */
    #home-releases-grid { margin-top: var(--sp-5); }
    #home-releases-grid > .ri-featured { margin-top: 0; }
    .home-gig-rows,
    .home-gig-past { margin-top: var(--sp-3); }

    .section-header .eyebrow {
      margin-bottom: var(--sp-3);
    }

    .section-header h2 {
      margin-bottom: var(--sp-2);
    }

    /* ── Releases ── */
    @keyframes shimmer {
      0%   { background-position: -600px 0; }
      100% { background-position: 600px 0; }
    }
    .skel {
      background: linear-gradient(90deg, var(--surface-2) 25%, var(--border) 50%, var(--surface-2) 75%);
      background-size: 600px 100%;
      animation: shimmer 1.4s infinite linear;
      border-radius: 4px;
    }
    .skel-row {
      display: grid;
      grid-template-columns: 24px 80px 1fr auto auto;
      align-items: center;
      gap: 20px;
      padding: 16px 12px;
      border-bottom: 1px solid var(--border);
    }
    .skel-row:first-child { border-top: 1px solid var(--border); }
    .skel-num  { width: 18px; height: 10px; opacity: .3; }
    .skel-art  { width: 112px; height: 112px; border-radius: 6px; }
    .skel-info { display: flex; flex-direction: column; gap: 8px; }
    .skel-title { height: 15px; width: 55%; }
    .skel-credit { height: 10px; width: 35%; opacity: .6; }
    .skel-date  { height: 24px; width: 72px; border-radius: 999px; opacity: .4; }
    .skel-btn   { height: 36px; width: 90px; border-radius: 6px; }
    @media (max-width: 767px) {
      .skel-row { grid-template-columns: 20px 72px 1fr auto; gap: 12px; }
      .skel-art { width: 72px; height: 72px; }
      .skel-date { display: none; }
    }

    /* ── Featured release: ticker + card ── */
    .ri-featured {
      background: var(--surface);
      border: 1px solid var(--accent);
      box-shadow: none;
      border-radius: 12px;
      overflow: hidden;
      margin-top: var(--sp-6);
      margin-bottom: var(--sp-6);
    }

    .ri-featured-ticker {
      overflow: hidden;
      border-bottom: 1px solid var(--border);
      padding: 10px 0;
      background: var(--surface-2);
    }
    .ri-featured-ticker-track {
      display: flex;
      gap: 40px;
      white-space: nowrap;
      width: max-content;
      animation: ri-ticker-scroll 22s linear infinite;
    }
    @keyframes ri-ticker-scroll {
      from { transform: translateX(0); }
      to { transform: translateX(-50%); }
    }
    .ri-featured-ticker-item {
      font-family: var(--ff-head);
      font-weight: 800;
      text-transform: uppercase;
      font-size: 0.85rem;
      letter-spacing: 0.02em;
      display: inline-flex;
      align-items: center;
      gap: 40px;
      color: var(--text);
    }
    .ri-featured-ticker-item .sep { color: var(--accent); font-weight: 400; }

    .ri-featured-row {
      display: grid;
      grid-template-columns: 148px 1fr auto;
      align-items: center;
      gap: 26px;
      /* even inset on both sides: the gap from the card edge to the icons
         matches the gap from the card edge to the artwork */
      padding: 28px 36px;
    }
    .ri-featured-art {
      width: 148px;
      height: 148px;
      border-radius: 8px;
      overflow: hidden;
      background: var(--surface-2);
      flex-shrink: 0;
    }
    .ri-featured-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
    .ri-featured-art.no-art { display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg, var(--surface) 0%, var(--surface-2) 100%); }
    .ri-featured-art.no-art::after { content: '♪'; font-size: 2.4rem; color: rgba(10,10,11,0.12); }

    .ri-featured-info { min-width: 0; }
    .ri-featured-title {
      font-family: var(--ff-head);
      font-size: clamp(1.4rem, 2.6vw, 1.9rem);
      font-weight: 800;
      text-transform: uppercase;
      color: var(--text);
      line-height: 1.05;
      margin-bottom: 8px;
      display: inline-block;
      max-width: 100%;
      position: relative;
    }
    .ri-featured-title::after {
      content: '';
      position: absolute;
      left: 50%;
      right: 50%;
      bottom: -3px;
      height: 1.8px;
      background: var(--accent);
      transition: left 200ms cubic-bezier(0.4, 0, 0.2, 1),
                  right 200ms cubic-bezier(0.4, 0, 0.2, 1);
    }
    @media (hover: hover) {
      .ri-featured-title:hover::after {
        left: 0;
        right: 0;
      }
    }
    .ri-featured-credit {
      font-family: var(--ff-body);
      font-size: 0.9rem;
      color: var(--text-muted);
      letter-spacing: 0.04em;
      text-transform: uppercase;
      margin-bottom: 12px;
    }
    .ri-featured-foot { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

    @media (max-width: 767px) {
      .ri-featured-row {
        grid-template-columns: 1fr;
        justify-items: center;
        text-align: center;
        padding: 20px 16px;
        row-gap: 12px;
      }
      .ri-featured-art { width: 100%; max-width: 220px; height: auto; aspect-ratio: 1 / 1; }
      .ri-featured-info { display: flex; flex-direction: column; align-items: center; }
      .ri-featured-title { font-size: 1.1rem; }
      .ri-featured-ticker-item { font-size: 0.7rem; }
    }

    .release-list {
      max-width: none;
    }

    .release-item {
      display: grid;
      grid-template-columns: 48px 1fr 360px auto; /* auto = the 5-slot rail, same width on every row */
      align-items: center;
      gap: 18px;
      padding: 22px var(--sp-3) 22px 0;
      border-bottom: 1px solid var(--border);
      transition: background 150ms ease;
    }
    .ri-art { grid-column: 1; grid-row: 1; }
    .ri-info { grid-column: 2; grid-row: 1; }
    .ri-pill-row {
      grid-column: 3;
      grid-row: 1;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .ri-meta {
      grid-column: 4;
      grid-row: 1;
      display: flex;
      align-items: center;
      justify-content: flex-end;
      gap: 14px;
    }
    .release-item:first-child { border-top: 1px solid var(--border); }
    @media (hover: hover) {
      @media (hover: hover) {
        .release-item:hover { background: rgba(255,255,255,0.025); }
      }
      @media (hover: hover) {
        .release-item:hover .ri-art img { transform: none; }
      }
    }

    .ri-art {
      width: 48px;
      height: 48px;
      border-radius: 5px;
      overflow: hidden;
      background: var(--surface-2);
      flex-shrink: 0;
    }
    .ri-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
    .ri-art.no-art {
      background: linear-gradient(135deg, var(--surface) 0%, var(--surface-2) 100%);
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .ri-art.no-art::after {
      content: '♪';
      font-size: 1.4rem;
      color: rgba(10,10,11,0.2);
    }

    .ri-info { min-width: 0; }
    .ri-title {
      font-family: var(--ff-head);
      font-size: clamp(0.95rem, 1.6vw, 1.1rem);
      font-weight: 800;
      text-transform: uppercase;
      color: var(--text);
      line-height: 1.15;
      margin-bottom: 5px;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      display: inline-block;
      max-width: 100%;
      vertical-align: top;
      position: relative;
      padding-bottom: 3px;
    }
    .ri-title::after {
      content: '';
      position: absolute;
      left: 50%;
      right: 50%;
      bottom: 0;
      height: 1.4px;
      background: var(--accent);
      transition: left 200ms cubic-bezier(0.4, 0, 0.2, 1),
                  right 200ms cubic-bezier(0.4, 0, 0.2, 1);
    }
    @media (hover: hover) {
      .ri-title:hover::after {
        left: 0;
        right: 0;
      }
    }
    .ri-credit {
      font-family: var(--ff-body);
      font-size: 1.02rem;
      line-height: 1.2;
      color: var(--text-muted);
      letter-spacing: 0.04em;
      text-transform: uppercase;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .ri-category-slot {
      display: flex;
      justify-content: flex-start;
      flex-shrink: 0;
      width: 80px;
    }
    .ri-pill-row .ri-category-slot {
      width: auto;
    }
    /* One width for every pill in the list so their left and right edges
       stack dead straight, not just their centres. 78px clears the widest
       label (ORIGINAL). */
    .ri-pill-row .ri-category {
      min-width: 78px;
    }

    .ri-category {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      flex-shrink: 0;
      line-height: 1;
      font-family: var(--ff-body);
      font-size: 0.6rem;
      font-weight: 700;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: var(--accent);
      background: transparent;
      border: 1.5px solid var(--accent);
      border-radius: 8px;
      cursor: pointer;
      -webkit-appearance: none;
      appearance: none;
      transition: background 180ms ease, color 180ms ease, border-color 180ms ease;
      /* right padding drops one letter-space: letter-spacing adds a trailing
         gap after the last letter, which otherwise pushes the glyphs left of
         centre. Vertical padding is the optical tune for all-caps. */
      padding: 6.4px calc(10px - 0.08em) 5.6px 10px;
      white-space: nowrap;
    }

    @media (hover: hover) {
      @media (hover: hover) {
        .ri-category:hover {
          background: var(--accent);
          border-color: var(--accent);
          color: var(--accent-ink);
        }
      }
    }
    .ri-category:focus-visible {
      background: var(--accent);
      border-color: var(--accent);
      color: var(--accent-ink);
      outline: 2px solid var(--accent-hover);
      outline-offset: 2px;
    }
    .ri-category:active { background: var(--accent-hover); border-color: var(--accent-hover); color: var(--accent-ink); }

    .release-filters {
      display: flex;
      column-gap: 8px;
      row-gap: 14px;
      margin-top: var(--sp-6);
      margin-bottom: 24px;
      flex-wrap: wrap;
    }

    /* Header nav-link look: mono uppercase label, underline-grow on
       hover, corner-tick brackets on the active one — see .nav-links a
       and .nav-indicator for the source pattern. */
    .filter-btn {
      position: relative;
      font-family: var(--ff-mono);
      font-size: var(--fs-label);
      font-weight: 600;
      letter-spacing: 0.10em;
      text-transform: uppercase;
      color: rgba(10, 10, 11, 0.65);
      background: transparent;
      border: none;
      padding: 3px 18px 0;
      height: 36px;
      display: inline-flex;
      align-items: center;
      cursor: pointer;
      white-space: nowrap;
      transition: color 200ms;
    }

    .filter-btn:not(.active)::after {
      content: '';
      position: absolute;
      left: 50%;
      right: 50%;
      bottom: 3px;
      height: 1.4px;
      background: var(--accent);
      transition: left 200ms cubic-bezier(0.4, 0, 0.2, 1),
                  right 200ms cubic-bezier(0.4, 0, 0.2, 1);
    }
    .filter-btn:not(.active):focus-visible {
      color: var(--text);
    }

    @media (hover: hover) {
      .filter-btn:not(.active):hover {
        color: var(--text);
      }
    }
    .filter-btn:not(.active):focus-visible::after {
      left: 16px;
      right: 16px;
    }

    @media (hover: hover) {
      .filter-btn:not(.active):hover::after {
        left: 16px;
        right: 16px;
      }
    }

    .filter-btn.active {
      color: var(--accent);
      font-weight: 700;
    }
    .filter-btn.active::before,
    .filter-btn.active::after {
      content: '';
      position: absolute;
      top: 2px;
      bottom: 2px;
      width: 6px;
      border: 1.5px solid var(--accent);
    }
    .filter-btn.active::before { left: 4px; border-right: none; border-radius: 5px 0 0 5px; }
    .filter-btn.active::after { right: 4px; border-left: none; border-radius: 0 5px 5px 0; }

    .ri-date {
      font-family: var(--ff-body);
      font-size: 0.63rem;
      font-weight: 700;
      letter-spacing: 0.1em;
      text-transform: uppercase;
      color: var(--text-muted);
      white-space: nowrap;
      border: 1px solid var(--border);
      border-radius: 999px;
      padding: 4px 10px;
    }

    .ri-download {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      text-decoration: none;
      font-family: var(--ff-body);
      font-size: 0.76rem;
      font-weight: 700;
      letter-spacing: 0.1em;
      text-transform: uppercase;
      color: var(--accent-ink);
      border: none;
      border-left: 3px solid var(--accent-hover);
      border-radius: 0;
      padding: 10px 18px;
      min-height: 40px;
      white-space: nowrap;
      background: var(--accent);
      transition: background 160ms ease;
    }
    @media (hover: hover) {
      .ri-download:hover { background: var(--accent-hover); }
    }

    .ri-featured .ri-download {
      font-size: 0.82rem;
      padding: 12px 24px;
    }

    /* Fixed 5-slot rail (Spotify · Apple · SoundCloud · YouTube · Download)
       so every row's icons sit in the same column, download always last. */
    .ri-platforms {
      display: grid;
      grid-template-columns: repeat(5, 40px);
      gap: clamp(20px, 2.6vw, 44px); /* breathes with the viewport */
      align-items: center;
      justify-items: center;
    }
    /* Unlinked slots keep their icon so every rail reads as the same five
       icons; faded and inert marks them as "no link" without a gap. Already
       aria-hidden in the markup, so screen readers skip them. */
    .ri-platform-link.is-empty { pointer-events: none; opacity: 0.3; }

    /* The featured card is a one-off, so it packs its icons tight against the
       right edge instead of holding the list's empty slots open. */
    .ri-featured .ri-platforms {
      display: flex;
      justify-content: flex-end;
    }
    .ri-platform-link {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      width: 40px;
      height: 40px;
      color: var(--text-muted);
      transition: color 160ms ease;
    }
    .ri-platform-link svg { width: 24px; height: 24px; }
    @media (hover: hover) {
      .ri-platform-link:hover { color: #000; }
    }

    @media (max-width: 767px) {
      .release-item {
        grid-template-columns: 56px 1fr auto;
        grid-template-rows: auto auto auto;
        column-gap: 12px;
        row-gap: 4px;
        padding: 18px var(--sp-3) 18px 0;
        align-items: start;
      }

      .ri-art {
        grid-column: 1;
        grid-row: 1 / 4;
        align-self: center;
        width: 56px;
        height: 56px;
      }

      .ri-info {
        grid-column: 2;
        grid-row: 1 / 3;
        align-self: end;
        padding-top: 2px;
        min-width: 0;
      }

      /* Wraps to as many lines as the title needs — see the clamp note in
         the later max-width:767px block. */
      .ri-title {
        font-size: 0.85rem;
        margin-bottom: 2px;
        white-space: normal;
        text-overflow: unset;
        line-height: 1.2;
      }

      .ri-date {
        display: inline-block;
        width: fit-content;
        font-size: 0.52rem;
        letter-spacing: 0.05em;
        padding: 3px 7px;
      }

      .ri-meta {
        grid-column: 3;
        grid-row: 1 / 4;
        align-self: center;
        flex-direction: column;
        align-items: flex-end;
        justify-content: flex-start;
        min-width: 0;
        gap: 6px;
      }

      .ri-pill-row {
        grid-column: 2;
        grid-row: 2;
        justify-content: center;
      }

      .ri-platforms {
        grid-template-columns: repeat(5, 24px);
        gap: clamp(3px, 2vw, 10px);
      }
      .ri-platform-link { width: 24px; height: 24px; }
      .ri-platform-link svg { width: 18px; height: 18px; }
    }

    /* ── Press Kit ── */
    .pk-category+.pk-category {
      margin-top: var(--sp-10);
    }

    .pk-cat-title {
      font-family: var(--ff-head);
      font-size: var(--fs-h3);
      font-weight: 700;
      text-transform: uppercase;
      color: var(--text);
      margin-bottom: var(--sp-5);
      padding-bottom: var(--sp-3);
      border-bottom: 1px solid var(--border);
    }

    #view-presskit .section-header {
      margin-bottom: var(--sp-7);
    }

    .pk-grid {
      display: grid;
      gap: var(--sp-4);
    }

    .pk-grid-logos {
      grid-template-columns: repeat(3, 1fr);
    }

    .pk-grid-photos {
      grid-template-columns: repeat(3, 1fr);
    }

    .pk-file-card {
      background: var(--surface-2);
      border: 1px solid var(--border);
      border-radius: var(--radius-md);
      padding: var(--sp-4);
      transition: border-color var(--t-fast), box-shadow var(--t-fast);
    }

    @media (hover: hover) {
      .pk-file-card:hover {
        border-color: var(--accent);
        box-shadow: var(--shadow-card-hover);
      }
    }

    .pk-file-preview {
      background: var(--surface);
      border: 1px solid var(--border);
      border-radius: var(--radius-sm);
      display: flex;
      align-items: center;
      justify-content: center;
      margin-bottom: var(--sp-3);
      color: var(--text-dim);
    }

    .pk-logo-preview {
      aspect-ratio: 1 / 1;
      overflow: hidden;
      padding: var(--sp-5);
      /* checkerboard so both light and dark logo colorways stay visible */
      background-color: #2a2a2e;
      background-image:
        linear-gradient(45deg, #1f1f22 25%, transparent 25%),
        linear-gradient(-45deg, #1f1f22 25%, transparent 25%),
        linear-gradient(45deg, transparent 75%, #1f1f22 75%),
        linear-gradient(-45deg, transparent 75%, #1f1f22 75%);
      background-size: 20px 20px;
      background-position: 0 0, 0 10px, 10px -10px, -10px 0;
    }

    .pk-logo-preview img {
      width: 100%;
      height: 100%;
      object-fit: contain;
      display: block;
    }

    .pk-photo-preview {
      aspect-ratio: 3 / 4;
      overflow: hidden;
      position: relative;
    }

    .pk-photo-preview img {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
      object-position: center top;
      display: block;
    }

    .pk-loop-list {
      border-top: 1px solid var(--border);
    }

    .pk-loop-row {
      display: grid;
      grid-template-columns: 2rem 1fr auto;
      align-items: center;
      gap: var(--sp-4);
      padding: var(--sp-4) var(--sp-3) var(--sp-4) 0;
      border-bottom: 1px solid var(--border);
      transition: background var(--t-fast);
    }

    @media (hover: hover) {
      .pk-loop-row:hover { background: rgba(255,255,255,0.025); }
    }

    .pk-loop-num {
      font-family: var(--ff-body);
      font-size: 0.68rem;
      font-weight: 700;
      color: var(--accent);
      letter-spacing: 0.04em;
      text-align: right;
      user-select: none;
    }

    .pk-loop-info { min-width: 0; }

    .pk-loop-name {
      font-family: var(--ff-head);
      font-size: clamp(0.9rem, 1.4vw, 1rem);
      font-weight: 800;
      text-transform: uppercase;
      color: var(--text);
      letter-spacing: -0.01em;
      line-height: 1.15;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    @media (max-width: 479px) {
      .pk-loop-name {
        white-space: normal;
        word-break: break-word;
      }
    }

    .pk-loop-meta {
      font-family: var(--ff-body);
      font-size: 0.72rem;
      color: var(--text-muted);
      margin-top: 2px;
    }

    .pk-loop-btn {
      white-space: nowrap;
      flex-shrink: 0;
    }

    .pk-file-name,
    .pk-file-type { display: none; }

    .pk-file-preview { margin-bottom: var(--sp-3); }

    .pk-dl-btn {
      width: 100%;
      justify-content: center;
    }

    .pk-viewall {
      display: flex;
      justify-content: center;
      margin-top: var(--sp-4);
    }

    @media (max-width: 1023px) {
      .pk-grid-logos,
      .pk-grid-photos {
        grid-template-columns: repeat(2, 1fr);
      }
    }

    @media (max-width: 767px) {
      .pk-grid-logos {
        grid-template-columns: repeat(2, 1fr);
        gap: var(--sp-2);
      }

      .pk-grid-photos {
        grid-template-columns: repeat(2, 1fr);
        gap: var(--sp-2);
      }

      .pk-grid-logos .pk-file-preview,
      .pk-grid-photos .pk-file-preview {
        margin-bottom: var(--sp-2);
      }

      .pk-logo-preview {
        padding: var(--sp-3);
      }

      .pk-file-card {
        padding: var(--sp-2);
      }

    }

    /* ── Tech Rider ── */

    .rider-layout {
      display: grid;
      grid-template-columns: 1.4fr 0.8fr;
      gap: var(--sp-6);
      align-items: start;
      margin-top: var(--sp-6);
    }

    @media (max-width: 1023px) {
      .rider-layout {
        grid-template-columns: 1fr;
      }
    }

    .rider-main,
    .rider-side-card {
      background: var(--surface);
      border: 1px solid var(--border);
      border-radius: var(--radius-md);
      box-shadow: var(--shadow-card);
    }

    .rider-main {
      padding: var(--sp-7);
    }

    .rider-mini-label,
    .rider-side-label {
      font-family: var(--ff-body);
      font-size: var(--fs-label);
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.16em;
      color: var(--accent);
      margin-bottom: var(--sp-4);
    }

    .rider-list {
      display: grid;
      gap: var(--sp-5);
    }

    .rider-item {
      display: grid;
      grid-template-columns: 32px 1fr;
      gap: var(--sp-4);
      align-items: start;
      padding-bottom: var(--sp-5);
      border-bottom: 1px solid var(--border);
    }

    .rider-item:last-child {
      border-bottom: none;
      padding-bottom: 0;
    }

    .rider-item-num {
      font-family: var(--ff-body);
      font-size: 0.75rem;
      font-weight: 700;
      color: var(--accent);
      letter-spacing: 0.04em;
      margin-top: 0.15rem;
    }

    .rider-item-label {
      font-family: var(--ff-body);
      font-size: 0.95rem;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.12em;
      color: var(--text-muted);
      margin-bottom: var(--sp-1);
    }

    .rider-item-value {
      font-family: var(--ff-body);
      font-size: 1.3rem;
      font-weight: 800;
      color: var(--text);
      margin-bottom: var(--sp-3);
    }

    .rider-item-bullets {
      display: grid;
      gap: 0.45rem;
      list-style: none;
      padding: 0;
      margin: 0;
    }

    .rider-item-bullets li {
      position: relative;
      padding-left: 1.1em;
      font-family: var(--ff-body);
      font-size: 0.85rem;
      line-height: 1.5;
      color: var(--text-muted);
    }

    .rider-item-bullets li::before {
      content: '—';
      position: absolute;
      left: 0;
      color: var(--accent);
    }

    .rider-side {
      display: flex;
      flex-direction: column;
      gap: var(--sp-5);
    }

    .rider-side-card {
      padding: var(--sp-5);
    }

    .rider-side-card h3 {
      font-family: var(--ff-head);
      font-size: var(--fs-h3);
      font-weight: 700;
      text-transform: uppercase;
      color: var(--text);
      margin-bottom: var(--sp-3);
    }

    .rider-actions {
      display: grid;
      gap: var(--sp-3);
    }

    .rider-actions .btn,
    .rider-actions a.btn {
      width: 100%;
      justify-content: center;
    }

    .rider-flow,
    .rider-notes {
      width: 100%;
      margin-top: var(--sp-6);
      padding: var(--sp-7);
      background: var(--surface);
      border: 1px solid var(--border);
      border-radius: var(--radius-md);
      box-shadow: var(--shadow-card);
    }

    .rider-flow-diagram {
      width: 100%;
      height: auto;
      margin-top: var(--sp-4);
    }

    .rider-flow-diagram .flow-node rect {
      fill: var(--surface-2);
      stroke: var(--border);
      stroke-width: 1;
    }

    .rider-flow-diagram .flow-node-accent rect {
      fill: var(--accent);
      stroke: var(--accent);
    }

    .rider-flow-diagram .flow-node text {
      font-family: var(--ff-body);
      font-size: 11px;
      font-weight: 600;
      letter-spacing: 0.04em;
      text-anchor: middle;
      dominant-baseline: central;
      fill: var(--text);
    }

    .rider-flow-diagram .flow-node-accent text {
      fill: var(--accent-ink, #fff);
    }

    .rider-flow-diagram .flow-line {
      stroke: var(--border);
    }

    .rider-flow-diagram marker path {
      fill: var(--border);
    }

    .rider-notes-list {
      display: grid;
      gap: 0.6rem;
      list-style: none;
      padding: 0;
      margin: var(--sp-4) 0 0;
    }

    .rider-notes-list li {
      position: relative;
      padding-left: 1.4em;
      font-family: var(--ff-body);
      font-size: var(--fs-body);
      color: var(--text);
    }

    .rider-notes-list li::before {
      content: '✓';
      position: absolute;
      left: 0;
      color: var(--accent);
      font-weight: 700;
    }

    .rider-footnote {
      margin-top: var(--sp-6);
      font-family: var(--ff-body);
      font-size: 0.85rem;
      color: var(--text-muted);
      font-style: italic;
    }

    .rider-footnote a {
      color: var(--accent);
      text-decoration: underline;
      text-underline-offset: 2px;
    }

    .rider-print-header {
      display: none;
    }

    @media print {
      body {
        background: white !important;
        color: black !important;
      }

      header,
      #hero,
      #story,
      #releases,
      #presskit,
      #contact,
      #commercials,
      footer,
      hr,
      .rider-side,
      .section-header {
        display: none !important;
      }

      #rider {
        display: block !important;
        padding: 24px 32px !important;
        background: white !important;
      }

      .rider-print-header {
        display: block !important;
        margin-bottom: 24px;
        padding-bottom: 16px;
        border-bottom: 2px solid #222;
      }

      .rider-print-header h2 {
        font-size: 1.4rem;
        font-weight: 800;
        text-transform: uppercase;
        letter-spacing: 0.06em;
        color: black;
        margin: 0 0 2px;
      }

      .rider-print-header p {
        font-size: 0.75rem;
        color: #666;
        margin: 0;
        letter-spacing: 0.08em;
        text-transform: uppercase;
      }

      #rider .section-inner {
        display: block !important;
        max-width: 100% !important;
        padding: 0 !important;
      }

      .rider-layout {
        display: block !important;
        max-width: 100% !important;
        margin-top: 0 !important;
      }

      .rider-main,
      .rider-flow,
      .rider-notes {
        background: white !important;
        color: black !important;
        border: 1px solid #ccc !important;
        box-shadow: none !important;
        break-inside: avoid;
      }

      .rider-notes-list li,
      .rider-item-bullets li {
        color: #333 !important;
      }

      .rider-footnote {
        color: #666 !important;
      }

      .rider-mini-label,
      .rider-item-label {
        color: #555 !important;
      }

      .rider-item-value {
        color: black !important;
      }

      .rider-dot {
        background: #555 !important;
      }

      .rider-item {
        border-bottom-color: #ddd !important;
      }

      .btn,
      .btn-ghost {
        display: none !important;
      }
    }

    /* ── Contact ── */
    .contact-hero {
      /* Bigger h2 = bigger font-metric leading above the cap-height, which
         reads as more gap from the header even though margin-top is the
         same var(--sp-6) every other .section-header uses (Past Gigs
         included). Pull it back up so the two pages feel equally tight. */
      margin-top: var(--sp-4);
    }

    .contact-hero h2 {
      /* No negative margin-top here: .contact-hero also carries
         reveal-clip, whose clip-path sits flush on the box's own top edge
         (zero tolerance) — pulling the glyph up risks slicing "SAY" the
         same way GET IN TOUCH/FOLLOW were getting cut. */
      font-size: clamp(3rem, 7.5vw, 6.5rem);
      font-weight: 700;
    }

    .contact-hero h2 em {
      font-family: Georgia, "Times New Roman", ui-serif, serif;
      font-style: italic;
      font-weight: 400;
      text-transform: none;
    }

    .contact-hero-lead {
      max-width: var(--maxw-text);
      font-size: var(--fs-lead);
      color: var(--text-muted);
      margin-top: var(--sp-2);
    }

    .contact-hero-email {
      display: block;
      width: fit-content;
      margin-top: 2px;
      font-family: var(--ff-body);
      font-size: var(--fs-lead);
      font-weight: 400;
      letter-spacing: normal;
      text-transform: none;
      color: var(--text);
      text-decoration: underline;
      text-underline-offset: 5px;
      text-decoration-color: var(--border);
      transition: text-decoration-color var(--t-fast);
    }

    @media (hover: hover) {
      .contact-hero-email:hover {
        text-decoration-color: var(--accent);
      }
    }


    /* ── Homepage contact ──────────────────────────────────────────────
       The Contact page's own layout, compressed to close the home view:
       no lead line, no GET IN TOUCH label, rows on a tighter rhythm, and
       FOLLOW beside the rows rather than under them. The heading matches
       every other home section (.home-head) instead of the Contact page's
       display size, so the page keeps one voice top to bottom. */
    /* .home-head already draws the rule above the rows, so the container's
       own border-top would read as a second hairline a few pixels below it. */
    .home-contact-links {
      border-top: 0;
      /* 12 here + 12 of .phone-block padding = the same 24px every other
         home section opens with. */
      padding-top: var(--sp-3);
    }

    #home-contact .phone-block { padding: var(--sp-3) 0; }

    @media (min-width: 1024px) {
      /* Five chips need their own width, not half the page. */
      .home-contact-links { grid-template-columns: minmax(0, 1fr) auto; }
    }

    .contact-links {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: var(--sp-7);
      border-top: 1px solid var(--border);
      padding-top: var(--sp-7);
    }

    .contact-links-col + .contact-links-col {
      border-left: 1px solid var(--border);
      padding-left: var(--sp-7);
    }

    @media (max-width: 1023px) {
      .contact-links {
        grid-template-columns: 1fr;
        gap: var(--sp-7);
      }
      .contact-links-col + .contact-links-col {
        border-left: none;
        padding-left: 0;
        border-top: 1px solid var(--border);
        padding-top: var(--sp-7);
      }
    }

    .contact-col-label {
      /* .contact-links-col carries .reveal, whose clip-path sits flush on
         the column's own top edge with zero tolerance. The inherited
         line-height:.92 (h1,h2,h3 rule) packs the line box tighter than
         this font's cap-height, so the very top of the letters pokes past
         it and gets sliced by that clip-path. line-height + a hair of
         padding-top gives it room to sit inside the box instead. */
      line-height: 1.4;
      padding-top: 4px;
      font-family: var(--ff-mono);
      font-size: var(--fs-label);
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.2em;
      color: var(--text-dim);
      margin-bottom: var(--sp-4);
    }

    .phone-block {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      justify-content: space-between;
      gap: var(--sp-3) var(--sp-4);
      padding: var(--sp-4) 0;
      border-bottom: 1px solid var(--border);
    }

    .phone-block-info {
      display: flex;
      align-items: baseline;
      gap: var(--sp-3);
      min-width: 0;
    }

    .phone-block-tag {
      /* Fixed to the same 132px column as .link-row-label so the phone
         number lines up with the Bookings/Music email values below it. */
      flex: 0 0 132px;
      font-family: var(--ff-head);
      font-size: var(--fs-sm);
      letter-spacing: 0.03em;
      text-transform: uppercase;
      color: var(--text);
    }

    .phone-block-value {
      flex: 0 1 auto;
      min-width: 0;
      font-family: var(--ff-body);
      font-size: clamp(1rem, 1.8vw, 1.25rem);
      color: var(--text-muted);
      white-space: nowrap;
    }

    .phone-block-actions {
      display: flex;
      flex: 0 0 auto;
      gap: var(--sp-5);
    }

    /* Card box. This used to be drawn as two caliper brackets (::before /
       ::after carrying inset box-shadows) plus separate 2px line spans for the
       top and bottom edges — needed back when those edges were a lighter tint.
       They are all one colour now, so it is a plain border: four edges drawn
       by one renderer, which is the only way the thickness is guaranteed
       identical on every side at any zoom. The old .phone-icon-line-* spans are
       still in the markup and are hidden below. Do not reintroduce the
       brackets — that mismatch is exactly what this replaced. */
    .phone-icon-btn {
      position: relative;
      display: flex;
      align-items: center;
      gap: var(--sp-2);
      padding: var(--sp-3) calc(var(--sp-4) + 4px);
      min-height: var(--tap);
      border: 2px solid var(--accent);
      border-radius: 14px;
      text-decoration: none;
      background-color: transparent;
      color: var(--text);
      transition: background-color var(--t-fast), border-color var(--t-fast), color var(--t-fast);
    }

    .phone-icon-line-top,
    .phone-icon-line-bottom { display: none; }

    .phone-icon-svg {
      flex: none;
      color: var(--accent-hover);
      transition: color var(--t-fast);
    }

    .phone-icon-label {
      font-family: var(--ff-head);
      font-size: var(--fs-sm);
      letter-spacing: 0.02em;
      white-space: nowrap;
    }

    .phone-icon-btn:focus-visible {
      background-color: var(--accent-hover);
      border-color: var(--accent-hover);
      color: var(--accent-ink);
    }

    @media (hover: hover) {
      .phone-icon-btn:hover {
        background-color: var(--accent-hover);
        border-color: var(--accent-hover);
        color: var(--accent-ink);
      }
    }

    .phone-icon-btn:focus-visible .phone-icon-svg {
      color: var(--accent-ink);
    }

    @media (hover: hover) {
      .phone-icon-btn:hover .phone-icon-svg {
        color: var(--accent-ink);
      }
    }

    /* Follow row — icon-only chips. Same outline-at-rest / solid-fill-on-hover
       behaviour as every other button on the site. */
    .social-chips {
      display: flex;
      flex-wrap: wrap;
      gap: var(--sp-5);
    }

    .social-chip {
      position: relative;
      width: 84px;
      height: 84px;
      flex: none;
      display: flex;
      align-items: center;
      justify-content: center;
      border: 2px solid var(--accent);
      border-radius: 16px;
      color: var(--text);
      transition: background-color var(--t-fast), border-color var(--t-fast), color var(--t-fast);
    }

    /* Same story as .phone-icon-btn above: one border, not brackets plus line
       spans, so all four edges are exactly 2px. The spans stay in the markup. */
    .social-chip-line { display: none; }

    .social-chip-tip {
      position: absolute;
      bottom: calc(100% + 8px);
      left: 50%;
      transform: translateX(-50%) translateY(4px);
      background: var(--text);
      color: var(--surface);
      font-family: var(--ff-mono);
      font-size: 0.6875rem;
      white-space: nowrap;
      padding: 4px 8px;
      border-radius: 3px;
      opacity: 0;
      pointer-events: none;
      transition: opacity var(--t-fast), transform var(--t-fast);
    }

    .social-chip:focus-visible {
      background-color: var(--accent-hover);
      border-color: var(--accent-hover);
      color: var(--accent-ink);
    }

    @media (hover: hover) {
      .social-chip:hover {
        background-color: var(--accent-hover);
        border-color: var(--accent-hover);
        color: var(--accent-ink);
      }
    }
    .social-chip:focus-visible .social-chip-tip {
      opacity: 1;
      transform: translateX(-50%) translateY(0);
    }

    @media (hover: hover) {
      .social-chip:hover .social-chip-tip {
        opacity: 1;
        transform: translateX(-50%) translateY(0);
      }
    }

    @media (max-width: 479px) {
      .phone-block {
        flex-direction: column;
        align-items: flex-start;
      }
      .phone-block-actions {
        width: 100%;
        justify-content: flex-start;
      }
    }

    .link-row {
      display: flex;
      align-items: baseline;
      gap: var(--sp-3);
      min-height: var(--tap);
      padding: var(--sp-4) 0;
      border-bottom: 1px solid var(--border);
      text-decoration: none;
      color: var(--text);
    }

    .link-row:last-child {
      border-bottom: none;
    }

    .link-row-icon {
      align-self: center;
      flex: none;
      color: var(--text);
      transition: color var(--t-fast);
    }

    .link-row-label {
      flex: 0 0 132px;
      min-width: 0;
      font-family: var(--ff-head);
      font-size: var(--fs-sm);
      letter-spacing: 0.03em;
      text-transform: uppercase;
      color: var(--text);
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .link-row-value {
      /* flex:0 (no grow) so the box hugs the text instead of stretching to
         fill the row — needed so the ::after underline below sizes to the
         actual word, not the row's empty trailing space. */
      flex: 0 1 auto;
      min-width: 0;
      position: relative;
      font-family: var(--ff-body);
      font-size: clamp(1rem, 1.6vw, 1.25rem);
      color: var(--text-muted);
      overflow-wrap: anywhere;
    }

    /* Underline Grow hover on the value only — same center-out sweep as
       .nav-links a (see line ~417). Label stays plain per design. */
    .link-row-value::after {
      content: '';
      position: absolute;
      left: 50%;
      right: 50%;
      bottom: -2px;
      height: 1.4px;
      background: var(--accent);
      transition: left 200ms cubic-bezier(0.4, 0, 0.2, 1),
                  right 200ms cubic-bezier(0.4, 0, 0.2, 1);
    }

    @media (hover: hover) {
      a.link-row:hover {
        color: var(--accent);
      }
    }

    @media (hover: hover) {
      a.link-row:hover .link-row-icon {
        color: var(--accent);
      }
    }

    @media (hover: hover) {
      a.link-row:hover .link-row-value::after {
        left: 0;
        right: 0;
      }
    }

    @media (max-width: 479px) {
      .link-row {
        flex-wrap: wrap;
      }
      .link-row-label {
        flex-basis: 100%;
        white-space: normal;
        overflow: visible;
        text-overflow: clip;
      }
      .link-row-value {
        padding-left: 0;
        font-size: 1.05rem;
      }
    }

    /* ── Footer ── */
    /* One block, not two. A quiet bar carrying the real links, capped to
       --maxw so it lines up with the content above it, and a full-bleed band
       of the wordmark drifting left on a 78s loop directly beneath it — no
       rule between them, so bar and band read as a single footer. The band is
       decoration only.

       The one rule is the top edge, and it is the only thing separating the
       footer from the page, so it carries a step more weight than a section
       divider: --footer-rule is one value darker than --border. Its thickness
       is divided by the page zoom, so 1px lands on a whole screen pixel
       instead of the 0.9 that the browser rounds unevenly. */
    .site-footer {
      --footer-rule: #C8C5AB;
      background: var(--bg);
      border-top: calc(1px / var(--zoom)) solid var(--footer-rule);
      /* Band sits above the bar. column-reverse rather than moving the markup:
         the band is aria-hidden decoration, so the links keep their natural
         DOM/tab position at the end of the document either way. Both children
         carry asymmetric padding-block, and those pairs are written flipped to
         match — the tight edge always faces the join between them. */
      display: flex;
      flex-direction: column-reverse;
    }

    /* --gutter mirrors the `section` padding-inline ladder, and max-width adds
       it back on top of --maxw. With border-box that leaves a content box of
       exactly --maxw, centred — the same rails .section-inner sits on, so the
       footer links line up with the content above them at every breakpoint. */
    .footer-bar {
      --gutter: 20px;
      /* width:100% because the footer is a flex column and the auto inline
         margins below suppress stretch — without it the bar shrinks to its
         own content and the links stop tracking the page rails. */
      width: 100%;
      max-width: calc(var(--maxw) + 2 * var(--gutter));
      margin-inline: auto;
      padding-inline: var(--gutter);
      /* asymmetric on purpose: the space above is the gap to the drift band
         now that no rule divides them, the space below closes the page — so
         the top is the tighter of the two. */
      padding-block: clamp(var(--sp-4), 2.2vw, var(--sp-5)) clamp(var(--sp-5), 3vw, var(--sp-6));
      display: flex;
      align-items: center;
      justify-content: space-between;
      flex-wrap: wrap;
      gap: var(--sp-4) var(--sp-6);
    }

    @media (min-width: 480px)  { .footer-bar { --gutter: 24px; } }
    @media (min-width: 768px)  { .footer-bar { --gutter: 40px; } }
    @media (min-width: 1024px) { .footer-bar { --gutter: 48px; } }
    @media (min-width: 1280px) { .footer-bar { --gutter: 64px; } }
    @media (min-width: 1680px) { .footer-bar { --gutter: 0px; } }

    .footer-nav {
      display: flex;
      flex-wrap: wrap;
      gap: 0 clamp(var(--sp-5), 3.4vw, var(--sp-7));
    }

    .footer-nav a {
      position: relative;
      display: inline-flex;
      align-items: center;
      min-height: var(--tap);
      font-family: var(--ff-mono);
      font-size: var(--fs-label);
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.10em;
      color: var(--text-muted);
      text-decoration: none;
      transition: color var(--t-fast);
    }

    /* Same centre-out underline as .nav-links a and .link-row-value */
    .footer-nav a::after {
      content: '';
      position: absolute;
      left: 50%;
      right: 50%;
      bottom: 11px;
      height: 1.4px;
      background: var(--accent);
      transition: left 200ms cubic-bezier(0.4, 0, 0.2, 1),
                  right 200ms cubic-bezier(0.4, 0, 0.2, 1);
    }

    .footer-nav a:focus-visible {
      color: var(--accent);
    }

    @media (hover: hover) {
      .footer-nav a:hover {
        color: var(--accent);
      }
    }

    .footer-nav a:focus-visible::after {
      left: 0;
      right: 0;
    }

    @media (hover: hover) {
      .footer-nav a:hover::after {
        left: 0;
        right: 0;
      }
    }

    .footer-social {
      display: flex;
      flex-wrap: wrap;
      gap: var(--sp-1);
      /* the round hit-areas overhang the text edge by ~10px; pull them back
         so the icon row optically aligns with the bar's right padding */
      margin-right: -10px;
    }

    .footer-social a {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      min-width: var(--tap);
      min-height: var(--tap);
      border-radius: var(--radius-pill);
      color: var(--text-muted);
      text-decoration: none;
      transition: color var(--t-fast), background var(--t-fast);
    }

    .footer-social a:focus-visible {
      color: var(--accent);
      background: var(--surface-2);
    }

    @media (hover: hover) {
      .footer-social a:hover {
        color: var(--accent);
        background: var(--surface-2);
      }
    }

    .footer-social a svg {
      display: block;
      flex-shrink: 0;
    }

    /* ── Drift band ── */
    /* No border-top: the bar's own bottom padding carries the gap, so the
       band hangs off the links as one footer rather than a second strip. */
    .footer-drift {
      /* one value drives every gap in the band: img-to-dot, dot-to-img, and
         the join between the two bands. Nothing may add space on top of it. */
      --drift-gap: clamp(var(--sp-3), 1.8vw, var(--sp-5));
      /* one ink value for wordmark and dot alike — they are the same mark, so
         they read wrong the moment the two numbers drift apart */
      --drift-ink: 0.40;
      display: flex;
      overflow: hidden;
      padding-block: clamp(var(--sp-5), 3.4vw, var(--sp-7)) clamp(var(--sp-2), 1.2vw, var(--sp-3));
      /* fade both ends so wordmarks enter and leave instead of cutting off */
      -webkit-mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
      mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
      -webkit-mask-repeat: no-repeat;
      mask-repeat: no-repeat;
    }

    /* Two identical bands side by side. Both slide one full band-width left,
       so B lands exactly where A began and the loop never seams.

       No min-width, no justify-content and no gap here, all three on purpose.
       min-width:100% made the band wider than its items, and space-around
       then shared that slack out *on top of* the gap — so every join inside
       a band got gap+slack while the join between the two bands got slack
       alone, leaving one visibly tight pair per loop. The band is now exactly
       as wide as its contents and the rhythm lives on the item's own
       margin-right, which sits after the last item too, so the band-to-band
       join is the same --drift-gap as every other one.

       The trade is that the band must out-measure the viewport on its own:
       15 items is ~3015px at the clamp ceiling, past any display this runs
       on. Add items, don't add slack, if that ever stops being true — a
       tighter --drift-gap costs band width, so it is the count that pays. */
    .footer-drift-band {
      flex: none;
      display: flex;
      align-items: center;
      animation: footerDrift 78s linear infinite;
      will-change: transform;
    }

    @keyframes footerDrift {
      to { transform: translateX(-100%); }
    }

    /* gap sets img-to-dot, margin-right sets dot-to-next-img. Same value, so
       the dot sits dead centre between two wordmarks, and the last item's
       margin carries the join to the next band. */
    .footer-drift-item {
      flex: none;
      display: flex;
      align-items: center;
      gap: var(--drift-gap);
      margin-right: var(--drift-gap);
    }

    /* The source PNG is 1890x1417 with the wordmark occupying only rows
       532-794 — over 80% of its height is transparent padding, which was
       inflating the band and throwing the spacing below the wordmarks out by
       ~40px. aspect-ratio crops the box down to the ink's own proportions and
       object-fit carries the overflow; object-position nudges to 47% because
       the wordmark sits marginally above the PNG's centre. Rendered width is
       unchanged — the same file, so the CMS logo hook still drives it. */
    .footer-drift-item img {
      display: block;
      width: clamp(104px, 9vw, 148px);
      aspect-ratio: 1289 / 262;
      object-fit: cover;
      object-position: 50% 47%;
      opacity: var(--drift-ink);
    }

    /* Same ink as the wordmark it sits between — black at the band's own
       --drift-ink — so the separator reads as part of the band rather than a
       second colour running through it. A touch larger than 4px to hold its
       weight now that it is no longer green. */
    .footer-drift-item i {
      flex: none;
      width: 5px;
      height: 5px;
      border-radius: var(--radius-pill);
      background: var(--text);
      opacity: var(--drift-ink);
    }

    @media (max-width: 767px) {
      /* Three stacked rows — wordmark band, links, icons — tuned to read as
         one evenly-spaced block. The numbers here are box gaps, and both link
         rows carry a 44px tap box around much smaller ink (~16px of slack per
         edge on the text, ~11px on the 22px icons), so every box gap lands
         ~28-33px larger than it looks in the file. Tuned against the ink, not
         the boxes: ~32px between all three rows, and the footer's own top and
         bottom air matched to ~24px so nothing reads lopsided. Change one of
         these and re-measure the ink gaps — the slack hides the arithmetic. */
      .footer-bar {
        flex-direction: column;
        align-items: center;
        gap: var(--sp-1);
        padding-block: var(--sp-3);
      }

      /* wider than desktop's ladder: centred on a narrow screen the three
         links crowd each other well before they run out of room. 10vw lands
         ~39px at 390 and stays inside the rails down to 320. */
      .footer-nav {
        justify-content: center;
        gap: 0 clamp(var(--sp-6), 10vw, var(--sp-7));
      }

      /* 5 icons x 44px tap = 220px before any gap, which leaves only 60px to
         spend at 320px wide. Fluid so the gap yields there instead of wrapping
         one icon onto a second line, and flat at the 16px ceiling from ~400px
         up where there is room for it. */
      .footer-social {
        justify-content: center;
        gap: clamp(var(--sp-2), 4vw, var(--sp-4));
        margin-right: 0;
      }

      /* Band sits directly above the links now, so this edge is a row gap,
         not the footer's bottom margin — the bar's padding-top carries the
         rest of it. The band's own padding-top is the air under the rule. */
      .footer-drift {
        padding-bottom: var(--sp-1);
      }
    }

    @media (prefers-reduced-motion: reduce) {
      .footer-drift-band { animation: none; }
    }

    /* ── Reveal ── */
    /* clip wipe from bottom-up */
    .reveal {
      opacity: 0;
      clip-path: inset(0 0 12% 0);
      transition:
        opacity 260ms cubic-bezier(0.16, 1, 0.3, 1),
        clip-path 340ms cubic-bezier(0.16, 1, 0.3, 1);
      transition-delay: var(--reveal-delay, 0ms);
      will-change: clip-path, opacity;
    }

    .reveal.in {
      opacity: 1;
      clip-path: inset(0 0 0% 0);
    }

    /* right element: clip from right side */
    .reveal-right {
      opacity: 0;
      clip-path: inset(0 12% 0 0);
      transition:
        opacity 280ms cubic-bezier(0.16, 1, 0.3, 1),
        clip-path 360ms cubic-bezier(0.16, 1, 0.3, 1);
      transition-delay: var(--reveal-delay, 0ms);
      will-change: clip-path, opacity;
    }

    .reveal-right.in {
      opacity: 1;
      clip-path: inset(0 0% 0 0);
    }

    /* full drop-in curtain for headings (top → bottom) */
    .reveal-clip {
      opacity: 0;
      clip-path: inset(0 0 100% 0);
      transition:
        opacity 240ms cubic-bezier(0.16, 1, 0.3, 1),
        clip-path 360ms cubic-bezier(0.16, 1, 0.3, 1);
      transition-delay: var(--reveal-delay, 0ms);
      will-change: clip-path, opacity;
    }

    .reveal-clip.in {
      opacity: 1;
      clip-path: inset(0 0 0% 0);
    }

    /* punch line clips up when parent enters view */
    @keyframes clipReveal {
      from {
        clip-path: inset(0 0 100% 0);
        opacity: 0;
      }

      to {
        clip-path: inset(0 0 0% 0);
        opacity: 1;
      }
    }

    .home-teaser-inner.in .home-teaser-punch {
      animation: clipReveal 520ms cubic-bezier(0.22, 1, 0.36, 1) 160ms both;
    }

    /* ── Home Latest Releases ── */
    #home-latest {
      background: var(--bg);
      border-top: 1px solid var(--border);
    }

    /* ── Home Collaborate teaser ──────────────────────────────────
       Same bracket construction as the Collaborate page, compressed to a
       tag: padding cut to the rails, icon and label sharing one row, the
       detail on one or two lines. Two differences from the page version:
       the top/bottom lines sit in full --accent at rest (not --accent-soft)
       so the four segments read as one continuous outline, and hover fills
       the whole bracket instead of only brightening the lines. */
    .home-collab-statement {
      font-family: var(--ff-head);
      font-size: clamp(1.45rem, 3.8vw, 2.4rem);
      font-weight: 800;
      line-height: 1.08;
      letter-spacing: -0.025em;
      color: var(--text);
      max-width: 22ch;
      text-wrap: balance;
      margin: var(--sp-5) 0 var(--sp-6);
    }

    .home-collab-statement em {
      font-style: italic;
      color: var(--accent);
    }

    #home-collab .collab-services {
      gap: 10px;
      margin-top: 0;
    }

    #home-collab .collab-service-card {
      padding: 9px 20px 11px;
    }

    #home-collab .collab-service-head {
      gap: 9px;
      min-height: 20px;
      margin-bottom: 3px;
    }

    #home-collab .collab-service-icon,
    #home-collab .collab-service-card h3,
    #home-collab .collab-service-card p {
      transition: color 200ms ease;
    }

    #home-collab .collab-service-icon svg {
      width: 16px;
      height: 16px;
    }

    #home-collab .collab-service-card h3 {
      font-size: 0.8rem;
    }

    #home-collab .collab-service-card p {
      font-size: 11.5px;
      line-height: 1.35;
      /* 16px icon + 9px gap, so the detail starts under the label, not the icon. */
      padding-left: 25px;
    }

    .home-releases-cta {
      text-align: center;
      margin-top: clamp(var(--sp-6), 4vw, var(--sp-7));
    }

    .home-platforms {
      margin-top: clamp(var(--sp-8), 6vw, var(--sp-9));
    }

    .home-platforms > .eyebrow {
      margin-bottom: var(--sp-5);
    }

    .platform-grid {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: var(--sp-4);
      align-items: start;
    }

    .platform-card {
      background: var(--surface);
      border: 1px solid var(--border);
      border-radius: 10px;
      padding: var(--sp-4);
      display: flex;
      flex-direction: column;
      gap: var(--sp-3);
      text-decoration: none;
      transition: border-color 160ms ease;
    }

    @media (hover: hover) {
      a.platform-card:hover { border-color: var(--text-dim); }
    }

    .platform-card--wide { grid-column: 1 / -1; }

    .platform-card-head {
      display: flex;
      align-items: center;
      gap: var(--sp-3);
    }

    .platform-card-icon {
      width: 30px; height: 30px; flex-shrink: 0;
      display: flex; align-items: center; justify-content: center;
      color: var(--text);
    }

    .platform-card-title {
      font-family: var(--ff-head);
      font-weight: 800;
      font-size: 0.95rem;
      color: var(--text);
      line-height: 1.1;
    }

    .platform-card-sub {
      font-family: var(--ff-body);
      font-size: 0.68rem;
      font-weight: 700;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: var(--text-muted);
      margin-top: 2px;
    }

    .platform-card-link {
      margin-left: auto;
      flex-shrink: 0;
      font-family: var(--ff-body);
      font-size: 0.68rem;
      font-weight: 700;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: var(--accent);
      text-decoration: none;
      border-bottom: 1px solid var(--border);
      padding-bottom: 2px;
      white-space: nowrap;
    }

    .platform-embed {
      width: 100%;
      border: none;
      border-radius: 6px;
      display: block;
    }

    .platform-embed--soundcloud { height: 166px; }
    .platform-embed--spotify { height: 352px; }
    .platform-embed--apple { height: 450px; }

    /* ── Gigs (home teaser): upcoming tier + past tier ──
       Both tiers sit on the Gigs-page index grid (90px 1fr 140px 70px), so the
       four columns line up across the two lists and across the two pages.
       The upcoming tier is louder only by type: bigger numeral, heavier venue. */
    /* Rows sit flush in the content column so every rule — header underlines
       included — starts and ends on the same x. The hover tint gets its air
       from a shadow spread instead of a negative margin, which would drag the
       dividers back out past the headers. */
    .home-gig-past .gpi-row {
      padding: var(--sp-3) 0;
      transition: background 200ms ease, box-shadow 200ms ease;
    }

    @media (hover: hover) {
      .home-gig-past .gpi-row:hover {
        background: var(--surface);
        box-shadow: 0 0 0 var(--sp-4) var(--surface);
      }
    }

    .home-gig {
      display: grid;
      grid-template-columns: 90px 1fr 140px 70px;
      gap: var(--sp-4);
      align-items: center;
      padding: var(--sp-3) 0;
      border-bottom: 1px solid var(--border);
      transition: background 200ms ease, box-shadow 200ms ease;
    }

    @media (hover: hover) {
      .home-gig:hover {
        background: var(--surface);
        box-shadow: 0 0 0 var(--sp-4) var(--surface);
      }
    }

    .home-gig-month {
      display: block;
      font-family: var(--ff-mono);
      font-size: var(--fs-label);
      font-weight: 700;
      letter-spacing: 0.14em;
      text-transform: uppercase;
      color: var(--accent);
      margin-bottom: 2px;
    }

    .home-gig-day {
      display: block;
      font-family: var(--ff-head);
      font-weight: 800;
      font-size: clamp(1.9rem, 3vw, 2.6rem);
      line-height: 0.85;
      letter-spacing: -0.03em;
      font-variant-numeric: tabular-nums;
      color: var(--text);
      white-space: nowrap;
    }

    /* Multi-day gigs ("02–04") step down so the range stays on one line. */
    .home-gig-day--range {
      font-size: clamp(1.4rem, 2.2vw, 1.85rem);
    }

    .home-gig-main { min-width: 0; }

    .home-gig-venue {
      font-family: var(--ff-head);
      font-weight: 800;
      font-size: var(--fs-h3);
      line-height: 1.1;
      text-transform: uppercase;
      margin: 0;
    }

    @media (max-width: 1023px) {
      .platform-grid { grid-template-columns: 1fr 1fr; }
      .platform-card--wide { grid-column: 1 / -1; }

      /* Both tiers narrow together — they share one column template. */
      .home-gig,
      .home-gig-past .gpi-row { grid-template-columns: 80px 1fr 110px 60px; gap: var(--sp-3); }
    }

    @media (max-width: 767px) {
      .platform-grid { grid-template-columns: 1fr; }
      .platform-embed--apple { height: 400px; }

      /* Was 0 — the only section on the page without it, which made the
         Releases -> Collaborate break half the size of every other one. */
      #home-latest {
        padding-block-end: var(--sp-6);
      }

      .home-gig {
        grid-template-columns: 1fr 1fr;
        grid-template-areas: "date date" "main main" "city day";
        row-gap: 6px;
        align-items: baseline;
        padding: var(--sp-4) 0;
      }
      .home-gig-date { grid-area: date; display: flex; align-items: baseline; gap: var(--sp-3); }
      .home-gig-month { margin-bottom: 0; }
      .home-gig-day { font-size: 2.1rem; }
      .home-gig-main { grid-area: main; }
      .home-gig .gpi-city { grid-area: city; text-align: left; }
      .home-gig .gpi-day { grid-area: day; text-align: right; }
      /* Past rows stack the same way the upcoming rows do, so the two tiers
         still read as one list on a phone. Selectors carry an extra class to
         outrank the .gpi-row mobile reflow further down (Gigs page order). */
      .home-gig-past .gpi-row {
        padding: var(--sp-4) 0;
        grid-template-areas: "date date" "venue venue" "city day";
        row-gap: 6px;
      }
      .home-gig-past .gpi-row .gpi-date { grid-area: date; }
      .home-gig-past .gpi-row .gpi-venue { grid-area: venue; font-size: 1.05rem; }
      .home-gig-past .gpi-row .gpi-city { grid-area: city; text-align: left; }
      .home-gig-past .gpi-row .gpi-day { grid-area: day; text-align: right; }
    }

    /* ── CTA band (shared: gigs upcoming / gigs past, any future page) ── */
    .cta-band {
      margin-top: var(--sp-8);
      padding-top: var(--sp-6);
      border-top: 1px solid var(--border);
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: var(--sp-6);
      flex-wrap: wrap;
    }

    .cta-band-headline {
      font-family: var(--ff-head);
      font-size: clamp(1.2rem, 2.5vw, 1.75rem);
      font-weight: 700;
      color: var(--text);
      letter-spacing: -0.01em;
    }

    @media (max-width: 767px) {
      .cta-band { flex-direction: column; align-items: stretch; }
      .cta-band .btn { text-align: center; justify-content: center; }
    }

    /* Services: no rule between the copy and its button — the sections are
       short enough that the line just adds a seam, not a separation. */
    [id^="services-"] .cta-band {
      border-top: 0;
      padding-top: 0;
      margin-top: var(--sp-6);
    }

    /* One line, whatever the width — three short clauses reading as a set
       lose their rhythm if the browser wraps one of them. */
    .svc-oneline {
      white-space: nowrap;
      font-size: clamp(0.95rem, 2.6vw, 1.6rem);
    }

    /* ── Gigs: past index ── */
    .gigs-stats {
      display: flex;
      flex-wrap: wrap;
      gap: var(--sp-8);
      padding-bottom: var(--sp-6);
      border-bottom: 1px solid var(--border);
      margin-bottom: var(--sp-6);
    }

    .gigs-stat {
      display: flex;
      flex-direction: column;
      gap: var(--sp-1);
    }

    .gigs-stat-value {
      font-family: var(--ff-head);
      font-weight: 800;
      font-size: var(--fs-stat);
      font-variant-numeric: tabular-nums;
      line-height: 1;
    }

    .gigs-stat-label {
      font-family: var(--ff-mono);
      font-size: var(--fs-label);
      text-transform: uppercase;
      letter-spacing: 0.14em;
      color: var(--text-muted);
    }

    .gpi-index-head {
      display: grid;
      grid-template-columns: 90px 1fr 140px 70px;
      gap: var(--sp-4);
      margin-top: var(--sp-6);
      font-family: var(--ff-mono);
      font-weight: 700;
      font-size: var(--fs-sm);
      letter-spacing: 0.1em;
      text-transform: uppercase;
      color: var(--text-dim);
      border-bottom: 1px solid var(--text);
      padding-bottom: var(--sp-3);
    }

    /* City and Day labels sit centred over their centred columns. */
    .gpi-index-head span:nth-child(3),
    .gpi-index-head span:nth-child(4) { text-align: center; }

    .gpi-year-row {
      display: flex;
      align-items: baseline;
      margin: var(--sp-5) 0 var(--sp-3);
    }

    .gpi-year-row .gpi-year-num {
      font-family: var(--ff-head);
      font-weight: 800;
      font-size: var(--fs-h3);
      color: var(--accent);
    }

    .gpi-row {
      display: grid;
      grid-template-columns: 90px 1fr 140px 70px;
      gap: var(--sp-4);
      align-items: baseline;
      padding: var(--sp-4) 0;
      border-bottom: 1px solid var(--border);
    }

    .gpi-venue {
      font-family: var(--ff-head);
      font-weight: 800;
      font-size: var(--fs-body);
      text-transform: uppercase;
      min-width: 0;
    }

    .gpi-city {
      font-family: var(--ff-head);
      font-weight: 700;
      font-size: var(--fs-sm);
      text-transform: uppercase;
      color: var(--text-muted);
      white-space: nowrap;
      text-align: center;
    }

    .gpi-date {
      font-family: var(--ff-mono);
      font-variant-numeric: tabular-nums;
      font-size: var(--fs-sm);
      font-weight: 600;
      color: var(--text);
    }

    .gpi-day {
      font-family: var(--ff-mono);
      font-size: var(--fs-label);
      font-weight: 600;
      letter-spacing: 0.06em;
      text-transform: uppercase;
      color: var(--text);
      text-align: center;
    }

    .gpi-thumb-inline {
      display: none;
    }

    #gpi-hover-preview {
      position: fixed;
      pointer-events: none;
      z-index: 9999;
      width: 220px;
      aspect-ratio: 4 / 5;
      overflow: hidden;
      opacity: 0;
      transition: opacity 200ms ease;
      box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
    }

    #gpi-hover-preview.visible {
      opacity: 1;
    }

    #gpi-hover-preview img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      display: block;
    }

    @media (max-width: 767px) {
      #gpi-hover-preview { display: none; }
      .gpi-index-head { display: none; }
      .gpi-row {
        grid-template-columns: 1fr 1fr;
        grid-template-areas: "venue venue" "date city" "day city";
        row-gap: 3px;
      }
      .gpi-row .gpi-venue { grid-area: venue; font-size: 1.05rem; }
      .gpi-row .gpi-date { grid-area: date; }
      .gpi-row .gpi-city { grid-area: city; text-align: right; }
      .gpi-row .gpi-day { grid-area: day; text-align: left; }
    }

    /* ── Shared bills wall ── */
    .shared-bills-wall {
      margin-top: var(--sp-9);
      padding-top: var(--sp-7);
      border-top: 1px solid var(--border);
    }

    .shared-bills-label {
      margin-bottom: var(--sp-5);
    }

    .shared-bills-names {
      display: flex;
      flex-wrap: wrap;
      gap: var(--sp-4) var(--sp-6);
    }

    .shared-bills-name {
      font-family: var(--ff-head);
      font-weight: 800;
      font-size: clamp(1.4rem, 4vw, 2.75rem);
      letter-spacing: -0.01em;
      text-transform: uppercase;
      color: var(--text-muted);
    }

    #view-home .home-teaser-inner {
      --reveal-delay: 0ms;
    }

    #view-home .story-portrait-wrap {
      --reveal-delay: 0ms;
    }

    #view-home .story-prose .eyebrow {
      --reveal-delay: 35ms;
    }

    #view-home .story-prose h2 {
      --reveal-delay: 70ms;
    }

    #view-home .story-prose .story-lead:first-of-type {
      --reveal-delay: 105ms;
    }

    #view-home .story-prose .story-lead:last-of-type {
      --reveal-delay: 140ms;
    }

    #view-home .reveal,
    #view-home .reveal-right,
    #view-home .reveal-clip {
      transition-delay: var(--reveal-delay, 0ms) !important;
    }
    /* COMMERCIALS — ACCORDION */
    /* COMMERCIALS — TAB ROW */
    .comm-tabs {
      position: relative;
      display: flex;
      gap: var(--sp-6);
      border-bottom: 1px solid var(--border);
    }
    .comm-tab-indicator {
      position: absolute;
      bottom: -1px;
      height: 2px;
      background: var(--accent);
      transition: left 280ms cubic-bezier(0.4,0,0.2,1), width 280ms cubic-bezier(0.4,0,0.2,1);
      pointer-events: none;
    }
    .comm-tab {
      /* <button> for keyboard reach — these were plain <div>s no one could tab to */
      appearance: none;
      background: none;
      border: 0;
      min-height: var(--tap);
      display: inline-flex;
      align-items: center;
      padding: var(--sp-3) 0;
      cursor: pointer;
      font-family: var(--ff-head);
      font-size: clamp(0.75rem, 1vw, 0.85rem);
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.08em;
      color: var(--text-muted);
      user-select: none;
      white-space: nowrap;
      transition: color var(--t-fast);
    }
    @media (hover: hover) {
      .comm-tab:hover { color: var(--text); }
    }
    .comm-tab.active { color: var(--text); }
    .comm-pricing-panel {
      display: none;
      margin-top: var(--sp-6);
    }
    .comm-pricing-panel.active { display: block; }
    /* COMMERCIALS — PRICE CARDS */
    .comm-price-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
      gap: var(--sp-4);
    }
    .comm-pcard {
      background: var(--surface-2);
      border: 1px solid var(--border);
      padding: var(--sp-6);
      display: flex;
      flex-direction: column;
    }
    .comm-pcard-label {
      font-family: var(--ff-body);
      font-size: 0.65rem;
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.12em;
      color: var(--text-muted);
      margin-bottom: 5px;
    }
    .comm-pcard-name {
      font-family: var(--ff-head);
      font-size: clamp(1rem, 1.5vw, 1.15rem);
      font-weight: 800;
      text-transform: uppercase;
      letter-spacing: 0.03em;
      color: var(--text);
      line-height: 1.2;
    }
    .comm-pcard-functions {
      font-family: var(--ff-body);
      font-size: var(--fs-sm);
      color: var(--text);
      margin-top: var(--sp-2);
      line-height: 1.6;
      letter-spacing: 0.01em;
    }
    .comm-pcard-subnote {
      font-family: var(--ff-body);
      font-size: var(--fs-sm);
      color: var(--text-muted);
      font-style: italic;
      margin-top: 4px;
      line-height: 1.4;
    }
    .comm-pcard-divider {
      height: 1px;
      background: var(--border);
      margin: var(--sp-5) 0;
      flex-shrink: 0;
    }
    .comm-pcard-price {
      font-family: var(--ff-head);
      font-size: clamp(2rem, 3.2vw, 2.6rem);
      font-weight: 800;
      color: var(--text);
      letter-spacing: -0.02em;
      line-height: 1;
    }
    .comm-pcard-unit {
      font-family: var(--ff-body);
      font-size: 0.68rem;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.12em;
      color: var(--text-muted);
      margin-top: 7px;
    }
    .comm-pcard-extras {
      font-family: var(--ff-body);
      font-size: var(--fs-sm);
      font-weight: 600;
      color: var(--text-muted);
      margin-top: var(--sp-4);
      padding-top: var(--sp-3);
      border-top: 1px solid var(--border);
      letter-spacing: 0.03em;
      line-height: 1.5;
    }

    .comm-cta-block {
      margin-top: var(--sp-7);
      padding-top: var(--sp-6);
      border-top: 1px solid var(--border);
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: var(--sp-6);
      flex-wrap: wrap;
    }

    .comm-cta-headline {
      font-family: var(--ff-head);
      font-size: clamp(1.2rem, 2.5vw, 1.75rem);
      font-weight: 700;
      color: var(--text);
      letter-spacing: -0.01em;
    }

    @media (max-width: 767px) {
      .comm-cta-block { flex-direction: column; align-items: stretch; }
      .comm-cta-block .btn { text-align: center; justify-content: center; }
    }

    /* ── Collaborate form ── */
    #collaborate .section-inner {
      container-type: inline-size;
    }

    .collab-h2 {
      /* .section-header carries reveal-clip, whose clip-path sits flush on
         the box's own top edge with zero tolerance. The inherited
         line-height:.92 (h1,h2,h3 rule) is too tight for the italic serif
         em's taller ascenders, which poke past it and get sliced — line-height
         + a hair of padding-top gives them room to sit inside the box.

         font-size is in cqi (not vw) so it tracks the actual content-box
         width, which plateaus once .section-inner hits its max-width —
         vw alone keeps growing past that point and overflows the line. */
      font-size: 5cqi;
      font-weight: 700;
      line-height: 1.05;
      padding-top: 6px;
      white-space: nowrap;
    }

    .collab-h2 em {
      font-family: Georgia, "Times New Roman", ui-serif, serif;
      font-style: italic;
      font-weight: 400;
      text-transform: none;
    }

    /* Was 640px here and 760px in #collaborate, which let the opening
       section's text run wider than every section under it. One measure now:
       the 760px override is gone. */
    .collab-lead {
      display: flex;
      flex-direction: column;
      gap: var(--sp-4);
      margin: var(--sp-6) 0 0;
      max-width: var(--maxw-text);
    }

    #collaborate .story-lead-strong {
      font-size: clamp(1.3rem, 2vw, 1.7rem);
    }

    /* ── Services pages ── */
    /* The tagline sits directly under the section h2 here, so it takes the
       Collaborate sizing instead of the 2.75rem display default — two display
       lines stacked read as two competing headlines. */
    [id^="services-"] .story-lead-strong {
      display: block;
      font-size: clamp(1.3rem, 2vw, 1.7rem);
      line-height: 1.25;
      margin-right: 0;
      vertical-align: baseline;
    }

    /* Each block's own heading ("Ghost Production", "How It Works", the
       intro's "Confidential By Default") is the thing a reader orients on,
       so it sits a step above the tagline underneath it — the tagline had
       grown past it at the wide end of both clamps. */
    [id^="services-"] .svc-head-grid h2,
    #services-process .section-header h2,
    [id^="services-"] .svc-lead-heading {
      font-size: clamp(1.7rem, 2.8vw, 2.3rem);
    }

    /* The tagline stays a size down from the heading above it, but still a
       step up from the body copy below it. */
    [id^="services-"] .story-lead-strong.svc-tagline:not(.svc-lead-heading) {
      font-size: clamp(1.2rem, 1.9vw, 1.5rem);
    }

    /* Eight short items in one column ran the page tall for no reason; the
       measure only fits one item per line anyway, so they spread across the
       band — three columns where there is room, two below that. */
    [id^="services-"] .collab-checklist {
      display: grid;
      grid-template-columns: repeat(3, minmax(0, 1fr));
      column-gap: var(--sp-7);
      max-width: none;
    }

    @media (max-width: 1000px) {
      [id^="services-"] .collab-checklist { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    }

    @media (max-width: 640px) {
      [id^="services-"] .collab-checklist { grid-template-columns: 1fr; }
    }

    /* Sub-labels inside a service block. The label carries the gap from the
       copy above it, so the grid or list it introduces sits tight under it
       instead of adding its own --sp-6 on top. */
    .svc-label {
      margin-top: var(--sp-7);
    }

    .svc-label + .collab-services,
    .svc-label + .collab-checklist,
    .svc-label + .collab-lead {
      margin-top: 0;
    }

    /* Client marked these lines "keep it all caps". Done here rather than in
       the markup so the copy stays readable to whoever edits it next. */
    .svc-tagline {
      text-transform: uppercase;
    }

    /* Three short lines, not eight — the two-column split above would leave a
       ragged orphan. */
    .svc-no-split {
      display: flex !important;
      grid-template-columns: none !important;
    }

    /* This list reads as three plain facts, not action items — a round dot
       fits that tone better than the dash rule the other checklists use. */
    .svc-no-split li::before {
      content: '';
      width: 5px;
      height: 5px;
      border-radius: 50%;
      margin-top: 0.6em;
    }

    /* ── Services preamble ──
       Two text blocks stacked left a 1320px band half empty and pushed the
       first actual service below the fold. Side by side they fill the measure
       and the page opens on the work. */
    .svc-intro-grid {
      display: grid;
      grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
      gap: var(--sp-7) var(--sp-9);
      align-items: start;
    }

    #services-intro .section-header { margin-top: 0; margin-bottom: var(--sp-5); }

    /* Matches the "Yoschi" display word in the homepage About lead exactly,
       per client request — SERVICES reads at the same scale as that name. */
    #services-intro .section-header h2 {
      font-size: clamp(2.6rem, 4vw, 3.6rem);
    }

    /* Lead copy at 1.7 line-height is set for a single column running the
       width of the page; in a half-width column it reads loose, so it tightens
       and the paragraph gap comes in with it. */
    .svc-intro-grid .collab-lead {
      gap: var(--sp-3);
      margin-top: 0;
      max-width: none;
    }

    .svc-intro-grid .story-lead {
      line-height: 1.55;
      max-width: none;
    }

    .svc-intro-grid .story-lead-strong { margin-bottom: var(--sp-1); }

    /* The discretion promise is the one claim on this page a client reads
       twice — it gets a card rather than another run of body copy. */
    .svc-intro-panel {
      background: var(--bg);
      border: 1px solid var(--border);
      border-radius: var(--radius-md);
      padding: var(--sp-6);
    }

    .svc-intro-panel .collab-checklist {
      margin-top: var(--sp-5);
      gap: var(--sp-3);
    }

    .svc-intro-panel .collab-checklist li { font-size: var(--fs-sm); }

    /* Closes the left column rather than the panel — it is the page's line,
       not the discretion clause's, and it fills the column the shorter copy
       block would otherwise leave short. */
    .svc-intro-tagline {
      margin: var(--sp-6) 0 0;
    }

    @media (max-width: 900px) {
      .svc-intro-grid { grid-template-columns: 1fr; gap: var(--sp-6); }
      .svc-intro-panel { padding: var(--sp-5); }
    }

    /* Every service opened with a heading, a tagline and two paragraphs all
       stacked down the left third of a 1320px band — the right two thirds sat
       empty until the cards below. Heading and tagline now hold the left
       column and the body copy runs beside them, which fills the measure and
       lifts the cards a screen higher. */
    .svc-head-grid {
      display: grid;
      grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
      gap: var(--sp-6) var(--sp-9);
      align-items: start;
    }

    .svc-head-grid .section-header { margin-top: 0; }

    .svc-head-grid .svc-tagline { margin-top: var(--sp-4); }

    .svc-head-grid .collab-lead {
      margin-top: 0;
      max-width: none;
      gap: var(--sp-3);
    }

    /* 1.7 is set for a paragraph running the full page width; at half that
       it reads loose. */
    .svc-head-grid .story-lead {
      line-height: 1.55;
      max-width: none;
    }

    @media (max-width: 900px) {
      .svc-head-grid { grid-template-columns: 1fr; gap: var(--sp-4); }
      .svc-head-grid .svc-tagline { margin-top: var(--sp-3); }
    }

    /* ── Collapsible FAQ ──
       Native <details>: the open/close state, keyboard support and
       find-in-page expansion all come free. No JS. */
    .svc-faq-item {
      border-top: 1px solid var(--border);
      border-bottom: 1px solid var(--border);
      margin-top: var(--sp-4);
    }

    .svc-faq-item + .svc-faq-item {
      border-top: 0;
      margin-top: 0;
    }

    /* Lower-case "s" appended to an all-caps heading reads as the plural
       marker it is, rather than SERVICE-style shouting. */
    .svc-faq-s {
      font-size: 0.5em;
      text-transform: lowercase;
    }

    .svc-fold-summary {
      list-style: none;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: var(--sp-5);
      padding: var(--sp-4) 0;
      color: var(--text);
      transition: color var(--t-fast);
    }

    /* Safari still draws its own triangle without this. */
    .svc-fold-summary::-webkit-details-marker { display: none; }

    .svc-fold-title {
      font-family: var(--ff-head);
      font-weight: 700;
      font-size: clamp(1.1rem, 1.8vw, 1.45rem);
      line-height: 1.25;
      letter-spacing: -0.01em;
    }

    .svc-fold-chev {
      flex: none;
      color: var(--accent);
      transition: transform var(--t-fast);
    }

    details[open] > .svc-fold-summary > .svc-fold-chev {
      transform: rotate(180deg);
    }

    .svc-fold-summary:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: 4px;
    }

    @media (hover: hover) {
      .svc-fold-summary:hover { color: var(--accent); }
    }

    .svc-fold-body {
      padding-bottom: var(--sp-4);
      display: flex;
      flex-direction: column;
      gap: var(--sp-4);
      max-width: var(--maxw-text);
    }

    /* ── How it works ──
       Numeral + title stack in a fixed-width left column so every step's
       marker lines up under the next, with the arrow centred under that
       column; the explanatory copy runs beside it in the remaining width
       instead of under it, so the wide 1320px band gets used. */
    .svc-steps {
      list-style: none;
      margin: var(--sp-7) 0 0;
      padding: 0;
      display: flex;
      flex-direction: column;
      gap: var(--sp-6);
      max-width: none;
    }

    .svc-step {
      position: relative;
      display: grid;
      grid-template-columns: var(--svc-step-marker-w, 180px) 1fr;
      column-gap: var(--sp-7);
      align-items: start;
    }

    .svc-step-marker {
      display: flex;
      flex-direction: column;
      gap: var(--sp-2);
    }

    .svc-step-body {
      display: flex;
      flex-direction: column;
      gap: var(--sp-2);
      max-width: var(--maxw-text);
    }

    /* The client's copy draws a downward arrow between steps; it belongs to
       the gap, not to either step, so it is drawn on the separator, centred
       under the marker column. */
    .svc-step:not(:last-child)::after {
      content: '\2193';
      position: absolute;
      left: 0;
      bottom: calc(var(--sp-6) * -1);
      width: var(--svc-step-marker-w, 180px);
      text-align: center;
      color: var(--accent);
      font-size: 0.95rem;
      line-height: var(--sp-6);
    }

    @media (max-width: 640px) {
      .svc-step {
        grid-template-columns: 1fr;
        row-gap: var(--sp-2);
      }
      .svc-step:not(:last-child)::after {
        width: auto;
        text-align: left;
      }
    }

    .svc-step-title {
      font-family: var(--ff-head);
      font-size: clamp(1.05rem, 1.6vw, 1.3rem);
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.02em;
      margin: 0 0 var(--sp-2);
      color: var(--text);
    }

    .svc-step p {
      font-family: var(--ff-body);
      color: var(--text-muted);
      line-height: 1.5;
      margin: 0 0 var(--sp-2);
      max-width: var(--maxw-text);
    }

    .svc-step p:last-child { margin-bottom: 0; }

    /* ── Enquiry form ── */
    .svc-form { margin-top: var(--sp-7); }

    .svc-form-label {
      margin: var(--sp-5) 0 0;
      padding-top: var(--sp-5);
      border-top: 1px solid var(--border);
    }

    .svc-form > .svc-form-label:first-child {
      margin-top: 0;
      padding-top: 0;
      border-top: 0;
    }

    /* The nested "Ghost Production" label sits beside "What are you looking
       for?", not below a full-width run of copy — the section divider above
       it would cut across empty space instead of separating anything. */
    .svc-form-label-tight {
      margin-top: 0;
      padding-top: 0;
      border-top: 0;
    }

    /* "What are you looking for?" beside the Ghost Production follow-ups —
       reuses the head-grid ratio so the conditional column has room to
       breathe once it appears. */
    .svc-lookingfor-grid {
      align-items: start;
    }

    .svc-lookingfor-col {
      display: flex;
      flex-direction: column;
      gap: var(--sp-4);
    }

    @media (max-width: 900px) {
      .svc-lookingfor-grid { grid-template-columns: 1fr; }
    }

    /* Toggled via [hidden] from JS — the layout rules above set their own
       `display`, which otherwise outranks the UA's [hidden] default. */
    .svc-form [hidden] {
      display: none !important;
    }

    .svc-fieldset {
      border: 0;
      margin: 0;
      padding: 0;
      min-width: 0;
    }

    .svc-fieldset legend {
      padding: 0;
      margin-bottom: var(--sp-3);
    }

    .svc-fieldset .svc-radio {
      display: flex;
      align-items: flex-start;
      gap: var(--sp-3);
      padding: var(--sp-2) 0;
      cursor: pointer;
      font-family: var(--ff-body);
      color: var(--text);
      line-height: 1.4;
    }

    .svc-radio input,
    .svc-check input {
      flex: none;
      margin: 0.15em 0 0;
      accent-color: var(--accent);
      width: 16px;
      height: 16px;
      cursor: pointer;
    }

    .svc-check {
      display: flex;
      align-items: flex-start;
      gap: var(--sp-3);
      cursor: pointer;
      font-family: var(--ff-body);
      color: var(--text);
      line-height: 1.5;
    }

    .svc-confid-note {
      font-family: var(--ff-body);
      color: var(--text-muted);
      line-height: 1.5;
    }

    /* ── FAQ ── */
    .svc-faq {
      margin-top: var(--sp-6);
      max-width: 880px;
    }

    .svc-faq .svc-fold-title {
      font-size: clamp(1rem, 1.4vw, 1.15rem);
      font-weight: 600;
    }

    /* These headings used to be centred while everything under them — the
       paragraphs, the card grid, the checklist, the form — started hard left.
       Three sections in a row built that way read as a template rather than a
       decision, so the headings now sit on the same left edge as the content
       they introduce, matching the page's own hero. */
    .collab-services-header {
      margin-top: 0;
    }

    .collab-services-header h2 {
      margin-bottom: 0;
    }

    .collab-cta-header {
      margin-top: 0;
      margin-bottom: var(--sp-6);
    }

    .collab-cta-header h2 {
      margin-bottom: 0;
    }

    .collab-row {
      display: grid;
      grid-template-columns: minmax(220px, 300px) 1fr;
      gap: var(--sp-8);
      align-items: start;
    }

    .collab-row-label.section-header {
      margin-top: 0;
    }

    .collab-row-body {
      min-width: 0;
    }

    .collab-row-body .collab-lead:first-child,
    .collab-row-body .collab-services,
    .collab-row-body .collab-split {
      margin-top: 0;
    }

    .collab-split {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: var(--sp-7);
      align-items: start;
      margin-top: var(--sp-6);
    }

    .collab-services {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: var(--sp-5);
      margin-top: var(--sp-6);
    }

    /* Bracket card — echoes the nav's active-link indicator (two open
       caliper brackets in accent green) instead of a plain bordered box.
       The side brackets keep their own full curve (corner radius
       included), same shape as the nav mark just scaled up; the top/bottom
       edges, which the nav bracket leaves open, get a separate straight
       line in a lighter tint via .collab-service-line-top/bottom, starting
       only where the dark curve ends — so the curve stays fully dark and
       never blends into the light line. */
    .collab-service-card {
      position: relative;
      padding: 30px 30px 32px;
      border-radius: 14px;
      transition: background-color 200ms ease, color 200ms ease;
    }

    /* The Collaborate and home-teaser cards are links into the collaboration
       form; the Ghost Production ones are not, so the anchor reset is scoped
       to the element rather than the class. */
    a.collab-service-card {
      display: block;
      color: inherit;
      text-decoration: none;
      cursor: pointer;
    }

    /* Jump target for those cards — clears the sticky nav, same offset the
       in-page section anchors use. */
    #collab-form {
      scroll-margin-top: calc(var(--nav-h) + var(--ticker-h) + var(--sp-5));
    }

    @media (hover: hover) {
      .collab-service-card:hover {
        background: var(--accent);
        color: var(--accent-ink);
      }
    }

    @media (hover: hover) {
      .collab-service-card:hover .collab-service-icon,
      .collab-service-card:hover h3,
      .collab-service-card:hover p {
        color: var(--accent-ink);
      }
    }

    .collab-service-card::before,
    .collab-service-card::after {
      content: '';
      position: absolute;
      top: 0;
      bottom: 0;
      width: 14px;
      border: 1.5px solid var(--accent);
    }
    .collab-service-card::before { left: 0; border-right: none; border-radius: 14px 0 0 14px; }
    .collab-service-card::after  { right: 0; border-left: none; border-radius: 0 14px 14px 0; }

    .collab-service-line-top,
    .collab-service-line-bottom {
      position: absolute;
      left: 14px;
      right: 14px;
      height: 0;
      border-top: 1.5px solid var(--accent);
    }
    .collab-service-line-top { top: 0; }
    .collab-service-line-bottom { bottom: 0; }

    .collab-service-head {
      display: flex;
      align-items: center;
      gap: var(--sp-4);
      margin-bottom: var(--sp-4);
    }

    .collab-service-icon {
      display: inline-flex;
      flex-shrink: 0;
      color: var(--accent);
    }

    .collab-service-card h3 {
      font-family: var(--ff-head);
      text-transform: uppercase;
      font-size: 1.05rem;
      letter-spacing: -0.01em;
      margin: 0;
    }

    .collab-service-card p {
      font-family: var(--ff-body);
      color: #4A4C44;
      line-height: 1.5;
      margin: 0;
    }

    .collab-cta-row {
      display: flex;
      flex-wrap: wrap;
      gap: var(--sp-4);
      margin-top: var(--sp-7);
    }

    .collab-cta-row .btn {
      padding: var(--sp-4) var(--sp-6);
    }

    .collab-checklist {
      list-style: none;
      margin: var(--sp-6) 0 0;
      padding: 0;
      max-width: none;
      display: flex;
      flex-direction: column;
      gap: var(--sp-4);
    }

    .collab-checklist li {
      font-family: var(--ff-body);
      color: var(--text);
      display: flex;
      align-items: flex-start;
      gap: var(--sp-3);
      line-height: 1.4;
    }

    /* Was an empty checkbox square per item, which read as something you could
       tick and could not be. This is advice, not a form — so it gets a dash.
       Drawn as a rule rather than an em dash glyph: a glyph sits wherever the
       typeface puts it (low, in this one), a rule can be placed exactly. The
       line box is 1.4em tall, so 0.7em down is its centre; half the rule's own
       thickness backs it off so the rule is centred rather than its top edge,
       and the extra 1px is optical — the geometric centre lands on the
       x-height, which reads low against lines that all start with a capital,
       so it lifts toward the cap centre. Measured, not guessed: cap centre and
       x-height centre are 1.9px apart at this size and the rule sits between
       them.

       --rule is divided by the page zoom so it comes out as a whole number of
       screen pixels. A plain 2px becomes 1.8 under the 0.9 zoom, and the
       browser rounds that per row — some rules landed on 2 pixels, some on 1,
       so one item in the list looked fainter than the rest. */
    .collab-checklist li::before {
      content: '';
      flex: none;
      width: 16px;
      --rule: calc(2px / var(--zoom));
      height: var(--rule);
      background: var(--accent);
      margin-top: calc(0.7em - var(--rule) / 2 - 1px);
    }

    #collaborate-checklist .collab-field-hint {
      margin-top: var(--sp-5);
    }

    .collab-field-hint.collab-checklist-note {
      font-family: var(--ff-body);
      font-size: var(--fs-body);
      color: var(--text);
      line-height: 1.4;
    }

    .collab-form {
      display: flex;
      flex-direction: column;
      gap: var(--sp-5);
      max-width: none;
      margin-top: 0;
      padding: var(--sp-6);
      border: 1px solid var(--border);
      background: var(--bg);
    }

    .collab-closer-inner {
      text-align: center;
    }

    .collab-closer-inner .collab-lead {
      margin-inline: auto;
      align-items: center;
    }

    @media (max-width: 1023px) {
      .collab-services { grid-template-columns: repeat(2, 1fr); }
      .collab-row { grid-template-columns: 1fr; gap: var(--sp-4); }
      .collab-split { grid-template-columns: 1fr; gap: var(--sp-6); }
    }

    @media (max-width: 640px) {
      .collab-services { grid-template-columns: 1fr; }
      .collab-cta-row { flex-direction: column; align-items: stretch; }
      .collab-cta-row .btn { text-align: center; justify-content: center; }
      .collab-form { padding: var(--sp-5); }
    }

    /* ── Collaborate, phone ──
       Scoped to #view-collaborate so the Services pages, which reuse
       .collab-lead / .collab-checklist / .collab-service-card, keep their own
       sizing. Desktop is untouched.

       The page opened with its hierarchy inverted: the hero h2 is sized in
       cqi and nowrap, which on a 350px container resolved to 17.5px — smaller
       than the 24px section headers under it. The hero now wraps and takes the
       biggest type on the page; the section headers step down below it. */
    @media (max-width: 767px) {
      #view-collaborate .collab-h2 {
        font-size: 8.2cqi;
        line-height: 1.08;
        white-space: normal;
      }

      #view-collaborate .collab-services-header h2,
      #view-collaborate .collab-cta-header h2 {
        font-size: 1.2rem;
        line-height: 1.12;
      }

      #view-collaborate .story-lead {
        font-size: 1rem;
        line-height: 1.6;
      }

      #view-collaborate .story-lead-strong {
        font-size: 1.15rem;
        line-height: 1.3;
      }

      /* The hero header already sits under the nav and the section's own
         padding; the universal 32px on top of that read as a dead band. */
      #view-collaborate .section-header { margin-top: var(--sp-4); }

      #view-collaborate section { padding-block: var(--sp-5) var(--sp-6); }

      #view-collaborate .collab-lead {
        margin-top: var(--sp-5);
        gap: var(--sp-3);
      }

      #view-collaborate .collab-services {
        margin-top: var(--sp-5);
        gap: 14px;
      }

      /* 62px of the card's 152px height was padding. */
      #view-collaborate .collab-service-card { padding: 18px 20px 20px; }

      #view-collaborate .collab-service-head {
        gap: var(--sp-3);
        margin-bottom: var(--sp-3);
      }

      #view-collaborate .collab-service-icon svg { width: 22px; height: 22px; }

      #view-collaborate .collab-service-card h3 { font-size: 1rem; }

      #view-collaborate .collab-service-card p {
        font-size: 0.95rem;
        line-height: 1.45;
      }

      #view-collaborate .collab-cta-header { margin-bottom: var(--sp-4); }

      #view-collaborate .collab-split {
        margin-top: var(--sp-5);
        gap: var(--sp-5);
      }

      #view-collaborate .collab-checklist {
        margin-top: var(--sp-4);
        gap: var(--sp-3);
      }

      #view-collaborate #collaborate-checklist .collab-field-hint { margin-top: var(--sp-4); }

      #view-collaborate .collab-form {
        padding: var(--sp-5);
        gap: var(--sp-4);
      }

      /* The row's own gap stacks on top of the form's gap once the two
         columns collapse, so the fields drifted twice as far apart as the
         rest of the form. */
      #view-collaborate .collab-form-row { gap: var(--sp-4); }

      /* .collab-row-body zeroes this for the CTA section; the checklist puts
         its lead in a split column instead, where the 24px kept stacking on
         the split's own 24px top margin. */
      #view-collaborate .collab-split-col > .collab-lead:first-child { margin-top: 0; }
    }

    .collab-form-row {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: var(--sp-5);
    }

    .collab-field {
      display: flex;
      flex-direction: column;
      gap: var(--sp-2);
    }

    .collab-field-label {
      font-family: var(--ff-mono);
      font-size: var(--fs-sm);
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.18em;
      color: var(--text-muted);
    }

    .collab-field-hint {
      font-family: var(--ff-mono);
      font-size: 0.75rem;
      color: var(--text-muted);
    }

    .collab-field-hint.collab-attach-note {
      font-size: 0.85rem;
    }

    .collab-field input[type="text"],
    .collab-field input[type="email"],
    .collab-field input[type="url"],
    .collab-field input[type="date"],
    .collab-field select,
    .collab-field textarea {
      font-family: var(--ff-body);
      font-size: 1rem;
      color: var(--text);
      background: transparent;
      border: none;
      border-bottom: 1px solid var(--border);
      border-radius: 0;
      padding: var(--sp-3) 0;
      outline: none;
      transition: border-color 160ms ease;
    }

    .collab-field select {
      appearance: none;
      -webkit-appearance: none;
      -moz-appearance: none;
      border-radius: 0;
      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23131516' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
      background-repeat: no-repeat;
      background-position: right center;
      padding-right: var(--sp-6);
      cursor: pointer;
    }

    /* ── Attachment field ──
       The browser's own "Choose File" chrome was the one control on this page
       still wearing the operating system's font and grey box. The input stays
       in the DOM — visually hidden but focusable, so keyboard and screen
       readers are unchanged — and the <label> around it forwards clicks to it,
       so the visible button needs no JS to open the picker. site.js only
       writes the chosen filename into .collab-file-name. */
    .collab-field input[type="file"] {
      position: absolute;
      width: 1px;
      height: 1px;
      padding: 0;
      margin: -1px;
      overflow: hidden;
      clip: rect(0 0 0 0);
      clip-path: inset(50%);
      white-space: nowrap;
    }

    .collab-file-row {
      display: flex;
      align-items: center;
      flex-wrap: wrap;
      gap: var(--sp-3);
      padding-top: var(--sp-1);
    }

    /* Borrows .phone-icon-btn (line ~2440) so it is the same button as "Send
       It Over", then shrinks it: this is a field control, not the form's main
       action, so it sits a size below the submit. Size and radius change here,
       never the border width — every outline on the site is the same 2px. */
    .collab-file-btn {
      cursor: pointer;
      flex: none;
      gap: 6px;
      padding: 7px var(--sp-3);
      min-height: 0;
      border-radius: 10px;
    }

    .collab-file-btn .phone-icon-svg { width: 14px; height: 14px; }
    .collab-file-btn .phone-icon-label { font-size: 0.75rem; }

    .collab-field input[type="file"]:focus-visible ~ .collab-file-row .collab-file-btn {
      background-color: var(--accent-hover);
      color: var(--accent-ink);
    }

    .collab-field input[type="file"]:focus-visible ~ .collab-file-row .phone-icon-svg {
      color: var(--accent-ink);
    }

    .collab-file-name {
      font-family: var(--ff-body);
      font-size: 0.9rem;
      color: var(--text-muted);
      overflow-wrap: anywhere;
    }

    .collab-file-name.has-file { color: var(--text); }

    .collab-field textarea { resize: vertical; }

    /* Chrome paints the date field's own white box and calendar glyph; the
       rest of the form is a ruled line on the page ground, so it is stripped
       back to match. */
    .collab-field input[type="date"] {
      appearance: none;
      background: transparent;
      color: var(--text);
      min-height: var(--tap);
    }

    .collab-field input[type="date"]::-webkit-calendar-picker-indicator {
      opacity: 0.55;
      cursor: pointer;
    }

    .collab-field input:focus,
    .collab-field select:focus,
    .collab-field textarea:focus {
      border-color: var(--accent);
    }

    /* Outline + fill now comes from .phone-icon-btn itself (line ~2401),
       which every button on the site shares — including its border, so do not
       reset the border here; this only makes the <button> element behave like
       the <a> versions. */
    .collab-form-submit {
      align-self: flex-start;
      font: inherit;
      cursor: pointer;
    }

    .collab-form-status {
      font-family: var(--ff-mono);
      font-size: 0.85rem;
      color: var(--text-muted);
      min-height: 1em;
    }

    @media (max-width: 640px) {
      .collab-form-row { grid-template-columns: 1fr; }
    }

    /* ═══════════════════════════════════════════════════════════════════
       MOBILE & TABLET
       Appended last on purpose: every rule here is a deliberate override of
       an earlier breakpoint, and keeping them in one block means the whole
       small-screen pass can be read — or reverted — in one place.
       ═══════════════════════════════════════════════════════════════════ */

    /* ── Phones: drop the global 0.9 density zoom ──
       html { zoom: .9 } is a desktop density trick. On a 390px phone it
       turns body copy into 14.4px and inflates the layout viewport to
       433px, so every media query fires against a width the layout does not
       actually have. Full scale on phones; tablets keep 0.9 — an iPad has
       the room for the denser desktop composition. */
    @media (max-width: 767px) {
      :root { --zoom: 1; }
    }

    /* iOS Safari zooms the whole page when a focused field renders under
       16px. calc() keeps it at exactly 16px rendered on both phone (zoom 1)
       and tablet (zoom .9) without hard-coding two values. */
    @media (max-width: 1023px) {
      .collab-field input,
      .collab-field select,
      .collab-field textarea {
        font-size: max(16px, calc(1rem / var(--zoom)));
      }
    }

    /* ── Hero framing ──
       Both source photos are landscape and the subject sits right of centre.
       `cover` on a portrait viewport is height-constrained, so the vertical
       component is inert and only the horizontal one does any work. */
    @media (max-width: 767px) {
      .hero-bg { background-position: 68% center; }
    }

    @media (min-width: 768px) and (max-width: 1023px) {
      /* Tablet portrait still gets the desktop file (no second download),
         but centre framed the empty left third and cropped the subject out.
         71%, not the old 66%: the source gained 210px on its left edge, and
         71% lands the same crop window on the same pixels it framed before. */
      .hero-bg { --hero-pos: 71% 30%; }
    }

    /* ── Desktop hero framing across window shapes ──
       A browser window is any shape the user drags it to, and `cover` flips
       which axis does the work at the photo's own aspect (2610/1600 = 1.63):
       wider than that and the full width shows (horizontal is inert, vertical
       pans); narrower and the full height shows (vertical inert, horizontal
       pans). So each regime gets the value that its live axis needs. */

    @media (min-width: 1024px) and (max-aspect-ratio: 1/1) {
      /* Square-ish and taller. The crop window (1600 x A px of source) is now
         narrower than the content (1872px), so something has to go. Down to
         1:1 a centred crop trims his toe and his fingertips by the same few
         percent, which stays balanced — below it the loss gets big enough to
         matter, and losing the trailing leg is cheaper than losing the hand
         he is leaning on, so pan right. */
      .hero-bg { --hero-pos: 72% center; }
    }

    @media (min-width: 1024px) and (max-aspect-ratio: 4/5) {
      /* Properly portrait (a rotated monitor, a half-screen split). The crop
         window is barely wider than his torso; 80% re-centres the frame on
         him rather than on the photo. */
      .hero-bg { --hero-pos: 80% center; }
    }

    @media (min-width: 1024px) and (min-aspect-ratio: 12/5) {
      /* Letterbox windows (21:9 monitors, a short maximised laptop window).
         Past ~2.4 the hat and the floor can no longer both fit the frame.
         72% keeps his head clear of the header and lets his legs bleed off
         the bottom instead — a banner is allowed to bleed at the bottom, and
         that is where the scroll dissolve eats the image anyway. Clipping the
         face is the one thing that is not allowed. */
      .hero-bg { --hero-pos: center 72%; }
    }

    /* ── Nav overlay ──
       Header is lifted above the overlay so the hamburger — which JS swaps
       to an X — stays tappable as the close button. The header has a
       transparent background, so nothing else leaks through. */
    @media (max-width: 1160px) {
      .site-header { z-index: 200; }

      /* --tap is a rendered-pixel promise; under html{zoom} it shrinks to
         39.6px on tablet. Dividing by the zoom keeps the real 44px. */
      .nav-hamburger {
        width: calc(var(--tap) / var(--zoom));
        height: calc(var(--tap) / var(--zoom));
        min-width: calc(var(--tap) / var(--zoom));
        min-height: calc(var(--tap) / var(--zoom));
      }

      /* "Oversized": the list sits from the top and flush left, so opening a
         sub-list only ever pushes rows downward. Every value is divided by
         --zoom, since html{zoom:0.9} would otherwise render the 48px type at
         43px. */
      #nav-overlay {
        justify-content: flex-start;
        align-items: stretch;
        /* clears the pinned logo, which now floats above the overlay */
        padding-block: calc(var(--nav-h) + 40px) var(--sp-7);
        padding-inline: calc(22px / var(--zoom));
        gap: var(--sp-5);
      }

      /* UA default padding-inline-start: 40px was pushing the whole
         menu 20px right of flush left. */
      .overlay-links {
        padding: 0;
        margin: 0;
        align-items: flex-start;
        gap: calc(15px / var(--zoom));
      }

      .overlay-links > li > a,
      #nav-overlay .nav-drop-trigger {
        display: inline-flex;
        align-items: center;
        gap: calc(10px / var(--zoom));
        min-height: var(--tap);
        font-family: var(--ff-head);
        font-weight: 700;
        /* 48px rendered, but COLLABORATE is the widest word on the site and
           would eat the 22px gutter below ~356px. vw isn't scaled by
           html{zoom}, so 12.5vw is the step-down that keeps the gutter.
           Crossover is ~384px wide; every mainstream phone gets the full 48. */
        font-size: min(calc(48px / var(--zoom)), 12.5vw);
        line-height: 1;
        letter-spacing: -0.045em;
        text-transform: uppercase;
        color: var(--text);
      }
    }

    /* ── Releases: list rows ──
       Phone layout is three tracks over two rows:
         [art] [title + credit ] [pill]
         [art] [        icons ->      ]
       Art spans both rows, so the text starts on the artwork's top edge and
       the icon rail lands on its bottom edge — the row reads as one block the
       height of the artwork. Pill rides the top right corner, same idea as
       the featured card, so it costs no vertical band of its own.
       The desktop rail holds five fixed slots so icons line up column-wise
       down the page; there is no room for that here, so empty slots collapse
       and the rail hangs flush right instead. */
    @media (max-width: 767px) {
      .release-item {
        grid-template-columns: 64px minmax(0, 1fr) auto;
        grid-template-rows: auto auto;
        column-gap: 12px;
        row-gap: 0;
        padding: 8px var(--sp-2) 8px 0;
        align-items: start;
      }

      /* 64px against the featured card's 92px — the list artwork has to read
         as the smaller of the two at a glance. Top-aligned, not centred: the
         title and credit together are 50.4px, so squaring their top edge with
         the artwork's puts the whole text block inside the artwork's 64px
         band with room to spare, which is the alignment the eye actually
         reads down a list. */
      .ri-art { grid-column: 1; grid-row: 1 / 3; width: 64px; height: 64px; align-self: start; }

      /* The pill and the icon rail share the third column — pill pinned to
         the top of it, icons to the bottom — so neither one costs the row a
         band of its own. That leaves the artwork as the tallest thing in the
         row again, which is what sets the row height: 64 + 16 padding. The
         text and the icons both live inside the artwork's band instead of
         hanging below it. */

      .ri-info {
        grid-column: 2;
        grid-row: 1 / 3;
        display: flex;
        flex-direction: column;
        gap: 2px;
        align-self: start;
        min-width: 0;
      }

      /* No line clamps on mobile: the info column is narrow enough that a
         long title ("Guru Randhawa x Rbor & Non Grata - Qatal x Party Throw")
         needs three lines and a long credit ("YOSCHI x Mehul Kukreja ft.
         Nidhi Wagle") needs two. Clamping ellipsed the artist off the end,
         so both wrap fully instead — the row just grows to fit. The credit
         also has to undo the desktop rule's white-space: nowrap, or it
         would stay on one line and ellipse regardless of the clamp. */
      .ri-title {
        font-size: 0.82rem;
        line-height: 1.15;
      }

      .ri-credit {
        font-size: 0.66rem;
        line-height: 1.25;
        white-space: normal;
      }

      .ri-pill-row {
        grid-column: 3;
        grid-row: 1;
        justify-content: flex-end;
        align-self: start;
      }

      .ri-pill-row .ri-category { min-width: 0; }

      /* Five slots always render now (unlinked ones greyed), so the rail is
         too wide to share a row with the title — in the narrow right column
         it squeezed the text column until titles clipped. Own row, full
         width, still right-aligned so Download stays last. */
      .ri-meta {
        grid-column: 2 / 4;
        grid-row: 3;
        align-self: end;
        justify-content: flex-end;
        gap: 0;
      }

      .ri-platforms {
        display: flex;
        justify-content: flex-end;
        gap: 2px;
      }

      /* Width stays 36 so the tap target does not narrow; only the 40px
         height comes off, which is where the row's vertical saving is. */
      .ri-platform-link { width: 34px; height: 30px; }
      .ri-platform-link svg { width: 18px; height: 18px; }

      /* Two centred rows, nothing hidden: ALL on its own line, the four
         category tabs on the next. Replaces the horizontal scroller, which
         hid half the tabs off the right edge. The line break is forced by
         the spacer pseudo-element below. */
      .release-filters {
        flex-wrap: wrap;
        justify-content: center;
        column-gap: 6px;
        row-gap: 0;
        margin-inline: 0;
        padding-inline: 0;
        margin-top: var(--sp-4);
        margin-bottom: var(--sp-4);
      }

      .filter-btn {
        flex: 0 0 auto;
        height: var(--tap);
        font-size: 0.625rem;
        letter-spacing: 0.06em;
        padding: 3px 9px 0;
      }

      /* The brackets are sized off the label, not off the button. The button
         stays 44px tall for the tap target, but at this font size a bracket
         inset only 2px from that box is a 40px-tall frame around a 10px word
         — it read as a vertical lozenge, not as corner ticks. Pulling the
         inset to 10px gives a 24px bracket around 10px type, the same ~2.4x
         ratio the desktop tabs have, and dropping the horizontal inset to 0
         buys back the room the 9px label padding needs to clear it. */
      .filter-btn.active::before,
      .filter-btn.active::after {
        top: 10px;
        bottom: 10px;
        width: 4px;
        border-width: 1.2px;
      }

      .filter-btn.active::before { left: 0; border-radius: 4px 0 0 4px; }
      .filter-btn.active::after  { right: 0; border-radius: 0 4px 4px 0; }

      /* Underline-grow on the inactive tabs is pinned 16px in from each edge
         at desktop widths — wider than these whole buttons, so the line
         collapsed to nothing. Matches the 9px padding instead. */
      .filter-btn:not(.active):focus-visible::after { left: 9px; right: 9px; }

      /* The break is a zero-height full-width flex item between ALL and the
         rest, not `flex: 0 0 100%` on ALL itself — ALL has to keep its own
         label width, or the active-state corner brackets (.filter-btn.active
         ::before/::after, pinned to the button's own edges) stretch to the
         full screen instead of hugging the word. */
      .filter-btn { order: 2; }
      .filter-btn:first-child { order: 0; }

      .release-filters::before {
        content: '';
        order: 1;
        flex: 0 0 100%;
        height: 0;
      }
    }

    /* Tablet keeps zoom .9, so rendered-pixel minimums are divided by it.
       Scoped above 767 so it cannot undo the phone values set just above. */
    @media (min-width: 768px) and (max-width: 1160px) {
      .filter-btn { height: calc(var(--tap) / var(--zoom)); }
      .ri-category { min-height: calc(32px / var(--zoom)); }
    }

    /* ── Gigs: past rows ──
       The "city day" area row was being laid onto the four-track desktop
       `grid-template-columns` that is still in force at this width, so DAY
       landed in the 1fr track (≈48% across) instead of flush right. Two
       areas need two tracks. */
    @media (max-width: 767px) {
      .home-gig-past .gpi-row { grid-template-columns: 1fr 1fr; }
    }

    /* ── Contact: phone row ──
       The 132px label column eats a third of a 390px row. All three rows on
       this page are .phone-blocks, so they only need to agree with each
       other: 4.8rem clears the longest label ("Bookings") at both scales and
       keeps the values in one column, 56px narrower than before. */
    @media (max-width: 1023px) {
      .phone-block-tag { flex: 0 0 auto; min-width: 4.8rem; }
    }

    /* ── Tap targets ──
       Inline text links need the height without the surrounding prose
       spacing changing, so it is padding, not min-height. */
    @media (max-width: 1160px) {
      /* Standalone line — padding can grow it without disturbing anything. */
      .contact-hero-email {
        display: inline-block;
        padding-block: calc(10px / var(--zoom));
      }

      /* Sits mid-sentence, so padding would make one line of a paragraph
         taller than its neighbours. An absolutely positioned pseudo-element
         grows the touch area and leaves the line box alone. */
      #view-rider li a { position: relative; }

      #view-rider li a::before {
        content: '';
        position: absolute;
        inset: calc(-12px / var(--zoom)) -4px;
      }
    }

    /* ── Releases: tablet rows ──
       The desktop row reserves a fixed 360px column for the category pill.
       At 768-1160 that plus the 5-slot icon rail left the title track around
       147px, so every title truncated to three characters. Pill column goes
       auto and the rail tightens; the title gets the leftover. */
    @media (min-width: 768px) and (max-width: 1160px) {
      .release-item {
        grid-template-columns: 56px minmax(0, 1fr) auto auto;
        gap: 16px;
      }

      .ri-pill-row { justify-content: flex-end; }
      .ri-platforms { gap: 8px; }
    }

    /* ═══════════════════════════════════════════════════════════════════
       HOMEPAGE MOBILE REVISION — client pass
       Phone-only refinements on top of the block above. Kept separate so the
       first responsive pass stays readable on its own.
       ═══════════════════════════════════════════════════════════════════ */
    @media (max-width: 767px) {

      /* ── Hero: the portrait that used to sit in a circle above About is
         now the banner itself, and About opens straight on its heading. ── */
      .hero-bg {
        background-image: url(/assets/photos/yoschi-story-mobile.jpg);
        /* Portrait source (1066x1600) in a taller-than-4:3 viewport is always
           height-constrained under cover, so only the horizontal value does
           anything here. The figure's own centre sits left of the frame's
           centre, and the subject (855 of 1066 source px wide) is wider than
           the crop window (739), so something is always outside the frame.
           Measured: 44% kept the whole shoe but left the right side reading
           empty; 0% is the only value with any left margin at all (10px) and
           it costs the entire shoe. 34% fills the right edge with the leg,
           clips ~13px of the shoe's toe, and still lands the face within 4%
           of the centre line under the logo. Percentage holds at any width. */
        background-position: 34% center;
        /* Overridden below — kept so the earlier reasoning stays readable. */
      }

      .story-portrait-wrap { display: none; }

      /* ── One button size on phones ───────────────────────────────────
         .btn is set for desktop (48px tall, 16/32 padding, 14px radius).
         Next to 7px gig rows and 34px contact buttons that reads oversized,
         so every .btn on the site steps down together — one rule, so View
         All Gigs, View All Releases, Pitch Me An Idea and every button on
         the inner pages stay identical to each other.
         40px is the floor here: below that these stop being comfortable
         thumb targets. */
      .btn {
        min-height: 40px;
        padding: 9px var(--sp-5);
        border-radius: 11px;
        font-size: 0.6875rem;
        letter-spacing: 0.09em;
        gap: 6px;
      }

      /* Collaborate's two form buttons are .phone-icon-btn, not .btn, so the
         rule above misses them — they sat at 38px and 49px. Matched to the
         same 40px box so every call to action on a phone is one size. */
      .collab-file-btn,
      .collab-form-submit {
        min-height: 40px;
        padding: 9px var(--sp-5);
        border-radius: 11px;
      }

      .collab-file-btn .phone-icon-label,
      .collab-form-submit .phone-icon-label {
        font-size: 0.6875rem;
        letter-spacing: 0.09em;
      }

      .collab-file-btn .phone-icon-svg,
      .collab-form-submit .phone-icon-svg { width: 16px; height: 16px; }

      /* Break between the two tiers. 96px (desktop's rhythm) read as a dead
         zone once the rows came down to 7px padding; 24px was too close to
         the 14px that separates one gig from the next, so the two lists ran
         together. 40px is clear of both. */
      .home-head--stacked { margin-top: 40px; }

      /* ── Gig rows, two lines:  OCT 23 · FRI  /  VENUE ......... CITY
         Flex, not grid: the day has to sit hard against the date on line 1
         while the venue and city split line 2, and no two-column grid can do
         both (column 1 would be sized by the venue, pushing the day away).
         Flex wrapping gets it in four declarations — the day grows to eat the
         rest of line 1, which forces the venue onto line 2, and the city
         rides along beside it. Upcoming and past share the shape so the two
         tiers read as one list. ── */
      .home-gig,
      .home-gig-past .gpi-row {
        display: flex;
        flex-wrap: wrap;
        align-items: baseline;
        column-gap: 6px;
        row-gap: 2px;
        padding: 7px 0;
      }

      .home-gig-date,
      .home-gig-past .gpi-row .gpi-date { order: 1; }

      .home-gig .gpi-day,
      .home-gig-past .gpi-row .gpi-day { order: 2; flex: 0 0 auto; text-align: left; }

      /* Zero-height full-width flex item = a hard line break after the day.
         The alternative is a wrapper div in the JS templates, which would
         have to be undone for the desktop grid. */
      .home-gig::after,
      .home-gig-past .gpi-row::after {
        content: '';
        order: 3;
        flex: 0 0 100%;
        height: 0;
      }

      /* Separator lives on the day so the markup stays untouched. */
      .home-gig .gpi-day::before,
      .home-gig-past .gpi-row .gpi-day::before {
        content: '\2022';
        font-size: 1.15em;
        margin-right: 7px;
        color: var(--text-muted);
      }

      .home-gig-main,
      .home-gig-past .gpi-row .gpi-venue { order: 4; flex: 1 1 0; min-width: 0; }

      /* City rides the LAST line of the venue, so a venue that wraps to two
         lines still ends with the city beside it at the bottom right.
         flex-end is the floor; `last baseline` refines it where supported. */
      .home-gig .gpi-city,
      .home-gig-past .gpi-row .gpi-city {
        order: 5;
        flex: 0 0 auto;
        text-align: right;
        align-self: flex-end;
        align-self: last baseline;
      }

      /* ── Type ───────────────────────────────────────────────────────
         Upcoming carries the big split date — month in accent mono over a
         large display day number:

           month      mono   --fs-sm   700  +0.14em  accent
           day num    head   1.25rem   800  -0.03em  text

         Past deliberately does NOT. Its date stays the flat small mono
         "SEP 11" it has always been (the .gpi-date base rule), which keeps
         the finished shows visually quieter than the ones still to come.
         renderHomePast still emits .gpi-date-month / .gpi-date-day inside
         the .gpi-date cell — they are simply left unstyled here, so both
         halves inherit the small mono treatment.

         The rest of the row is shared by both tiers:

           weekday    mono   --fs-label 600 +0.06em  muted
           venue      head   1rem      800  -0.01em  text
           city       head   --fs-sm   700  +0.06em  muted */
      .home-gig-date { display: inline-flex; align-items: baseline; gap: 6px; }

      .home-gig-month {
        font-family: var(--ff-mono);
        font-size: var(--fs-sm);
        font-weight: 700;
        letter-spacing: 0.14em;
        text-transform: uppercase;
        color: var(--accent);
        margin-bottom: 0;
      }

      .home-gig-day {
        font-family: var(--ff-head);
        font-size: 1.25rem;
        font-weight: 800;
        line-height: 1;
        letter-spacing: -0.03em;
        font-variant-numeric: tabular-nums;
        color: var(--text);
      }

      .home-gig-day--range { font-size: 1.05rem; }

      .home-gig .gpi-day,
      .home-gig-past .gpi-row .gpi-day { color: var(--text-muted); }

      .home-gig-venue,
      .home-gig-past .gpi-row .gpi-venue {
        font-family: var(--ff-head);
        font-size: 1rem;
        font-weight: 800;
        line-height: 1.15;
        letter-spacing: -0.01em;
      }

      .home-gig .gpi-city,
      .home-gig-past .gpi-row .gpi-city { font-size: var(--fs-sm); letter-spacing: 0.06em; }

      /* ── Releases: featured card ── */
      /* Art was 220px — over half the screen height of the card. */
      .ri-featured-art { max-width: 92px; }

      /* ── Featured card: the category pill moves to the corner ──────────
         It used to sit in the centre stack under the credit, which cost a
         whole 34px band (24px pill + 10px row gap) for one word, and it
         never actually centred: .ri-category-slot is a fixed 80px box with
         justify-content:flex-start, so a 63px pill sat 8.5px left of every
         other centred element in the card. Pulling it to the top right
         corner reclaims the band and sidesteps the slot's alignment. */
      .ri-featured-row { position: relative; }

      /* Credit carried a 12px bottom margin on top of the row gap, so the
         drop to the platform icons was 22px where every other step in the
         card is 10px. */
      .ri-featured-credit { margin-bottom: 0; }

      .ri-featured .ri-category-slot {
        position: absolute;
        top: 10px;
        right: 10px;
        width: auto;
      }

      .ri-featured-row { padding: 16px; row-gap: 10px; }

      /* Ticker words were 40px apart, which on a 390px screen reads as two
         unrelated phrases rather than one running strip. */
      .ri-featured-ticker-track { gap: 16px; }
      .ri-featured-ticker-item { gap: 16px; font-size: 0.65rem; }
      .ri-featured-ticker { padding: 7px 0; }

      /* Opposite problem down here: the list rows pack their icons tight to
         save width, but the featured card has the room to breathe. */
      .ri-featured .ri-platforms { justify-content: center; gap: 18px; }

      /* ── Category pill, everywhere it appears ── */
      .ri-category {
        min-height: 24px;
        font-size: 0.55rem;
        letter-spacing: 0.06em;
        border-width: 1.2px;
        border-radius: 6px;
        padding: 3px calc(9px - 0.06em) 2px 9px;
      }

      /* In a list row the pill is a label, not a control anyone hunts for,
         so it steps down again. The featured card's keeps the 24px size. */
      .release-item .ri-category {
        min-height: 20px;
        font-size: 0.5rem;
        border-radius: 5px;
        padding: 2px calc(7px - 0.06em) 1px 7px;
      }

      /* ── Contact rows: label left, value hard right, actions beneath.
         Same three-part shape on all three rows. ── */
      .phone-block {
        flex-direction: column;
        align-items: stretch;
        gap: var(--sp-3);
        padding: var(--sp-4) 0;
      }

      .phone-block-info {
        width: 100%;
        justify-content: space-between;
        align-items: baseline;
        gap: var(--sp-3);
      }

      .phone-block-tag { min-width: 0; }

      .phone-block-value {
        text-align: right;
        font-size: 0.95rem;
      }

      /* Buttons hang off the right edge, directly under the number or
         address they act on — the value is already right-aligned above them,
         so the whole right-hand side of the row lines up on one edge. */
      .phone-block-actions { gap: var(--sp-3); justify-content: flex-end; }

      /* Scoped to the contact rows so the form's submit button — which shares
         .phone-icon-btn — keeps its full size. */
      .phone-block-actions .phone-icon-btn {
        min-height: 34px;
        padding: 0 13px;
        gap: 7px;
        border-width: 1.5px;
        border-radius: 10px;
      }

      .phone-block-actions .phone-icon-svg { width: 15px; height: 15px; }
      .phone-block-actions .phone-icon-label { font-size: 0.72rem; }

      /* ── Follow: five chips, one line, no wrap. Equal flex tracks size
         themselves to whatever width is left, so 360 and 430 both fit. ── */
      .social-chips {
        flex-wrap: nowrap;
        gap: clamp(6px, 2.5vw, 14px);
      }

      .social-chip {
        flex: 1 1 0;
        width: auto;
        height: auto;
        min-width: 0;
        max-width: 68px;
        aspect-ratio: 1;
        border-radius: 12px;
      }

      .social-chip svg { width: 24px; height: 24px; }
    }

    /* ── Header: logo centred, hamburger on the left ── */
    @media (max-width: 1160px) {
      .site-logo {
        left: 50%;
        transform: translateX(-50%) translateY(calc(-50% + var(--logo-offset, 16px)));
      }

      .nav-right {
        right: auto;
        left: var(--sp-4);
      }
    }

    @media (max-width: 767px) {
      /* The last row's own rule plus the FOLLOW column's rule left two lines
         48px apart with nothing between them. One divider is enough. */
      /* ── One label idiom in Contact ──────────────────────────────────
         PHONE / BOOKINGS / MUSIC were display-face 13px/400 in black while
         FOLLOW, their peer one column down, was mono 12px/600 tracked and
         dim. Two label systems stacked in one section. They all take the
         mono treatment now, which is also what the gig-row month and
         weekday use, so the page has one small-label style everywhere.
         The value gains the weight the label gives up. */
      .phone-block-tag {
        font-family: var(--ff-mono);
        font-size: var(--fs-label);
        font-weight: 600;
        letter-spacing: 0.2em;
        color: var(--text-dim);
      }
      .phone-block-value { color: var(--text); }

      .contact-links-col .phone-block:last-child { border-bottom: 0; }

      .contact-links { gap: var(--sp-5); }

      .contact-links-col + .contact-links-col { padding-top: var(--sp-5); }
    }

    /* ── Mobile logo: fixed placement, size does the moving ──────────────
       Desktop slides the logo up as it shrinks (--logo-offset). On a 60px
       bar that read as the logo "dropping" on load and jumping up on
       scroll. Here the centre never moves — only the height interpolates,
       so the shrink reads as part of the glass-header transition. ── */
    @media (max-width: 1160px) {
      .site-logo { transform: translateX(-50%) translateY(-50%); }

      .site-logo img {
        max-height: none;
        /* --logo-t is the same 0->1 scroll progress that drives --logo-h. */
        height: calc(140px - 28px * var(--logo-t, 0));
      }
    }

    /* ── Mobile header bar: hamburger · logo · next stop ─────────────────
       One row, three anchors. The logo stays absolutely centred (it
       overflows the 60px bar and can't be a flow item), so the flex row
       only has to pin the other two to the edges. row-reverse puts the
       hamburger — second in source order — on the left without touching
       the markup, which keeps the desktop tab order intact. ── */
    @media (max-width: 1160px) {
      .nav-inner { padding: 0 var(--sp-4); }

      .nav-right {
        position: static;
        transform: none;
        width: 100%;
        flex-direction: row-reverse;
        justify-content: space-between;
        align-items: center;
        gap: var(--sp-3);
      }

      /* The 44px tap box is 12px wider than the glyph on each side, so a
         flush box leaves the burger looking inset against the next-stop's
         flush text edge. Pulling the box out by that 12px lines the ink up
         on both sides while keeping the full target. */
      .nav-hamburger { margin-left: -12px; }


      /* Right-aligned so both of its lines end on the same edge the logo is
         measured against. */
      .next-stop:not([hidden]) {
        display: inline-flex;
        align-items: flex-end;
        gap: 3px;
      }

      .next-stop-label { font-size: 0.5625rem; letter-spacing: 0.14em; }
      .next-stop-place { gap: 4px; }
      .next-stop-pin { width: 12px; height: 12px; margin-bottom: 4px; }

      .next-stop-city {
        font-size: 0.8125rem;
        padding-bottom: 3px;
        max-width: 11ch;
        overflow: hidden;
        text-overflow: ellipsis;
      }

      /* The wordmark sits 3.2% of the PNG's height above the file's own
         centre, so box-centring reads low. Same expression as the height
         below, scaled, so the correction tracks the shrink. */
      /* Measured off the rendered glyphs, not the PNG box. The file has
         uneven transparent padding, so box-centring put the ink's bounding
         box 1.25px right of the frame's centre line; on top of that the
         wordmark's own mass leans right ("CHI" is denser than "YO"), putting
         its ink centroid 4.8px right. Correcting to the midpoint of those
         two lands the bbox 1.7px left and the centroid 1.9px right — the
         closest the shape gets to reading centred. Both terms are written
         against the same height expression as the image below, so the
         correction tracks the scroll shrink. */
      .site-logo {
        transform:
          translateX(calc(-50% - 0.0207 * (140px - 28px * var(--logo-t, 0))))
          translateY(calc(-50% + 0.0321 * (140px - 28px * var(--logo-t, 0))));
      }
    }

    /* ── Hero framing, take two: zoom instead of pan ─────────────────────
       Panning alone could never fill the frame. At the natural cover scale
       the figure renders 467px wide in a ~400px viewport, so its edges land
       just inside the frame and leave wall showing beside the body — the
       white the client saw on the right. Scaling the image to 112% of the
       hero's height pushes the figure's rendered width to ~560px, which
       bleeds it off BOTH sides: no wall beside the body at any phone width.

       45% / 20% is not eyeballed. Solving "face on the centre line" for
       390x844, 402x874, 430x932 and 360x780 gives 44.8% every time — phone
       aspect ratios are near enough identical that one value holds. 20%
       vertical is the midpoint of the band where the hat clears the header
       and the shoe still lands above the fold; that band also scales with
       viewport height, so it holds across the same set.

       Ceiling: past ~115% the hat and the shoe can no longer both fit, so
       this is roughly as tight as the crop goes without losing one of them. */
    @media (max-width: 767px) {
      .hero-bg {
        background-size: auto 112%;
        /* Horizontal moved 45% -> 35% so the wall beside his head reads even
           on both sides. Lower % pans the crop window left in the source,
           which pushes the subject right in the frame. Costs ~50px of face
           offset from the centre line; the client chose balanced whitespace
           over an exactly centred face. Zoom stays at 112%. */
        background-position: 25% 20%;
      }
    }
