/* The Long Line — public content pages (composer, later work/home).
   Same palette as the timeline island; this is the server-rendered, crawlable
   surface, so styles are global here (no shadow root). */
:root{
  --paper:#EAE2CF; --paper-hi:#F3ECDA; --paper-lo:#DED4BC;
  --ink:#2A2621; --ink-soft:#5c5544; --rule:#C4B896;
  --brass:#C9A227; --brass-deep:#A2801A; --muted:#8A7F66;
  --serif:"Iowan Old Style","Palatino Linotype",Palatino,Georgia,serif;
  --sans:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,sans-serif;
  /* UI control tokens — the toolbar search box, segmented toggle and icon buttons all read
     from these so the "chrome" stays one design language and doesn't drift per-edit. These
     mirror the timeline island header (--ll-ctrl-radius / --ll-search-w in
     frontend/src/styles.ts); change both together. Editorial type stays --serif; all chrome
     is --sans. */
  --ctrl-radius:2px;                   /* corner radius: search, segmented toggle, buttons */
  --ctrl-h:30px;                       /* height of the segmented toggle + icon buttons */
  --icon-btn:31px;                     /* square icon-button cell */
  --search-w:clamp(180px,24vw,300px);  /* centred search box — responsive, capped */
  --pad-x:10px;                        /* the one page gutter: bio, Works table, header, footer all read it.
                                          10px on phones; bumped to 20px on the wider iPad-portrait below. */
  --tri-size:.72rem;                   /* filled-triangle glyph size — sort arrows + the bio "Show more ▼" disclosure (DRY). Dropdown combos use a chevron, not this. */
}
/* iPad PORTRAIT is much wider than a phone, so 10px lets the prose run too wide and hugs the
   edge — give it a 20px gutter. Phones keep 10px; landscape/desktop use the centred 56rem column. */
@media (pointer:coarse) and (min-width:768px) and (max-width:1023.98px){
  :root{--pad-x:20px}
}
*{box-sizing:border-box}
html{background:var(--paper);scrollbar-gutter:stable}   /* always reserve the scrollbar gutter, so filtering the Works list (which changes the page height) never reflows the content width — the 1fr Title column was jumping when the scrollbar came and went */
/* Sticky footer: a full-height flex column so a short page (e.g. a sparse WDP) pushes the
   footer to the bottom of the viewport instead of floating it mid-screen. */
body{margin:0;color:var(--ink);font-family:var(--serif);line-height:1.6;
  min-height:100vh;min-height:100dvh;display:flex;flex-direction:column;
  background:
    radial-gradient(1200px 400px at 50% -10%, #f6f0e2 0%, transparent 70%),
    var(--paper);}
body > main{flex:1 0 auto}         /* the content grows to fill; the footer sits below it */
.site-footer{flex-shrink:0}

/* chrome */
.site-header,.site-footer{font-family:var(--sans);font-size:.8rem;letter-spacing:.02em}
.site-header{display:flex;align-items:center;height:46px;padding:0 var(--pad-x);
  position:sticky;top:0;z-index:4;border-bottom:1px solid var(--rule);
  background:linear-gradient(180deg,var(--paper-hi),var(--paper))}
.wordmark{display:inline-flex;align-items:center;gap:.5rem;color:var(--brass-deep);font-family:var(--serif);font-weight:600;
  font-size:1.05rem;text-decoration:none;letter-spacing:.01em}
.wordmark:hover{color:var(--brass)}
.site-logo{height:24px;width:auto}   /* the "f" mark, left of the wordmark */
/* tagline beside the wordmark — mirrors the timeline header's .ll-tag (desktop only) */
.site-tag{margin-left:.5rem;font-family:var(--sans);font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;margin-top:3px;color:var(--muted);white-space:nowrap}
/* iPad PORTRAIT (and phones): drop the tagline — the page header AND the docked Works bar — so
   the wordmark + Works controls have room. Landscape (≥1024) and desktop keep it. */
@media (pointer:coarse) and (max-width:1023.98px){
  .site-tag,.wh-tag{display:none}
}
/* the page's title (composer/work name) docks here, centred, once the reader scrolls past the
   on-page <h1> (works.js toggles .show). Same serif as the name, sized like the wordmark. It
   sits in the header (z-index 4) BELOW the works toolbar (z-index 5), so the toolbar replaces
   it when that docks. */
.site-dock{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);max-width:55%;
  font-family:var(--serif);font-weight:600;font-size:1.05rem;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  opacity:0;pointer-events:none;transition:opacity .2s ease}
.site-dock.show{opacity:1}
/* Matches the timeline island footer: small sans text, wordmark in brass serif. */
.site-footer{padding:.55rem var(--pad-x);margin-top:0;color:var(--muted);font-size:.72rem;
  border-top:1px solid var(--rule);text-align:center;
  position:sticky;bottom:0;z-index:5;background:var(--paper)}
.site-footer a{color:var(--brass-deep);text-decoration:none;font-family:var(--serif);font-weight:600;font-size:14px}
/* Global focus: a brass keyboard-focus ring, not the browser blue. */
:focus-visible{outline:2px solid var(--brass-deep);outline-offset:2px}
:focus:not(:focus-visible){outline:none}

/* layout */
.composer{max-width:56rem;margin:0 auto;padding:1rem var(--pad-x) .75rem;
  overflow-wrap:break-word}   /* matches the Works-table width; break long bio words/URLs so a narrow
                                 phone doesn't overflow sideways (they'd otherwise push past the gutter) */

/* Two-column header: photo + facts LEFT (¼), name + bio RIGHT (¾) — full 56rem, like Works. */
.c-head{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,3fr);column-gap:1.8rem;row-gap:0;align-items:start;margin-bottom:1.6rem;
  grid-template-areas:"side name" "side tag" "side body";
  grid-template-rows:auto auto 1fr}   /* name/tagline pack at the top; the flexible body row absorbs the
                                         photo column's extra height, so a short first paragraph sits UP
                                         under the tagline instead of floating to the middle */
.c-name{grid-area:name}
.c-head>.c-tagline{grid-area:tag}
.c-side{grid-area:side}
.c-body{grid-area:body}
.work-detail .c-head{display:block}   /* the work page has no portrait column — full-width title, not the CDP's 1fr photo / 3fr body split */
.c-name,.c-side,.c-body{min-width:0}
/* Guard: clip any stray horizontal overshoot in the name/portrait/bio area. `clip` NOT `hidden` —
   hidden forces overflow-y:auto, making .c-head a scroll container that JIGGLES under iOS momentum
   scroll. clip establishes no scroll container, so it can't jiggle; the real width fix is the
   max-width caps on .c-head + .c-body below. Scoped to .c-head (a SIBLING of .works-block). */
.c-head{overflow-x:clip}
.c-facts .c-line{font-size:.85rem;margin:.16rem 0}
.c-facts .timeline-link-p{margin:.9rem 0 0}
@media (max-width:560px){
  .site-tag{display:none}                    /* compact header: logo + wordmark only */
  .site-dock{display:none}                   /* no centred docked name on the narrow mobile header */
  /* Phones: name leads, then photo beside facts, then the bio below. minmax(0,1fr) — NOT 1fr — so the
     column can't be widened past the viewport by a grid item's min-content (the portrait's intrinsic
     image width bleeding through the nested .c-side flex is what pushed the bio wide on iOS; min-width:0
     on the items didn't cap the track). This is the real fix for the sideways-nudge; the clip was only
     ever a backstop. */
  .c-head{grid-template-columns:minmax(0,1fr);grid-template-areas:"name" "tag" "side" "body";grid-template-rows:none;row-gap:1rem}
  .c-side{display:flex;gap:1rem;align-items:flex-start}
  .portrait{flex:0 0 38%;width:38%;margin:0}
  .c-facts{flex:1;min-width:0}
  .c-name{font-size:30px}
  .timeline-link-p{margin:.6rem 0 0}
  /* Hard-cap the bio to the viewport (JH: it's really .c-body). Belt to the grid-track suspenders:
     even if some descendant re-widens the track, .c-body itself can never exceed the .composer content
     box, so the bio text always wraps within view AND stays aligned with the name/facts/Works above and
     below. Subtract the gutter on BOTH sides (2 * --pad-x = 20px on phones) — a smaller value would let
     the text run to the screen edge with no right gutter. */
  .c-body{max-width:calc(100vw - 2 * var(--pad-x))}
  .c-head{max-width:calc(100vw - 2 * var(--pad-x))}   /* same cap on the header — the width fix, no scroll container */
}

.portrait{margin:0 0 .8rem;width:100%}
.portrait img{width:100%;height:auto;aspect-ratio:4/5;object-fit:cover;object-position:center top;
  display:block;background:var(--paper-lo);
  border:1px solid var(--rule);border-radius:2px;padding:6px;
  box-shadow:0 6px 22px #2a262114;
  /* engraving-on-a-mat feel: cream border via padding + inner rule */
  outline:1px solid var(--paper-hi);outline-offset:-7px}
.portrait figcaption{font-family:var(--sans);font-size:.66rem;color:var(--muted);
  margin-top:.4rem;line-height:1.35}

h1{font-size:36px;line-height:1.1;margin:0 0 .35rem;font-weight:600}
/* meta beside the portrait — same treatment as the timeline panel: name, then
   tagline / years / era / tier all in the sans font, muted colour, no chips */
.c-tagline{font-family:var(--sans);font-size:1rem;color:var(--muted);line-height:1.4;margin:.15rem 0 .7rem}
.c-line{font-family:var(--sans);font-size:.9rem;color:var(--muted);margin:.12rem 0}
.timeline-link{font-family:var(--sans);font-size:.82rem;color:var(--brass-deep);text-decoration:none}
.timeline-link:hover{color:var(--brass);background-size:100% 1px}

/* text */
.lead{font-size:1.2rem;line-height:1.55;color:var(--ink);margin:1.4rem 0 1rem}
/* append IPA-capable sans fonts so the Wikipedia pronunciation marks (ˈ ː ◌̩) don't box in the serif */
.bio{font-size:1.125rem;font-family:var(--serif),"Segoe UI","Helvetica Neue",Arial,sans-serif;
  /* "Show more" reveals later paragraphs that can hold long compound names, foreign words, or the
     odd wide element. Break tokens ANYWHERE (stronger than .composer's break-word — it also shrinks
     min-content so a grid track can't be forced wide) and cap wide children, so expanding never lets
     a phone scroll sideways. The .c-head overflow-x clip is only the backstop. (NTI-379) */
  overflow-wrap:anywhere}
.bio :is(img,svg,video,iframe,table,pre){max-width:100%}
.bio pre{white-space:pre-wrap}
.bio table{display:block;overflow-x:auto}   /* a wide table scrolls within itself, not the page */
.bio p{margin:0 0 1rem}
/* Editorial bios can carry headings (H1–H3 from the WYSIWYG). Size them explicitly — otherwise the
   browser default (h2 ≈ 1.5em bold) looks oversized against the 1.125rem serif body. */
.bio h1,.bio h2,.bio h3{line-height:1.25;font-weight:600;margin:1.3rem 0 .5rem}
.bio h1{font-size:1.5em}
.bio h2{font-size:1.25em}
.bio h3{font-size:1.1em}
/* Collapsed bio (NTI-379): paragraph 1 in full, then a fading PEEK of paragraph 2 — Amazon "See more"
   style, a stronger "there's more here" cue than a hard cut. The mask fades the text to transparent so
   it blends into the page on any background; paragraph 3+ stays hidden. Expanded state is untouched. */
.bio.collapsed .bio-extra{display:none}
.bio.collapsed .bio-teaser{
  display:block;margin-bottom:0;
  max-height:3.1em;overflow:hidden;                 /* ~2 lines — a first-sentence-ish peek */
  -webkit-mask-image:linear-gradient(to bottom,#000 55%,transparent);
          mask-image:linear-gradient(to bottom,#000 55%,transparent);
}
/* same button treatment as the timeline panel's Open/Close Bio, but not full-width */
.bio-toggle{display:inline-flex;align-items:center;justify-content:center;width:120px;
  margin:1rem 0;padding:.4rem .5rem;font-family:var(--sans);font-size:.72rem;
  letter-spacing:.06em;text-transform:uppercase;color:var(--brass-deep);
  background:none;border:1px solid var(--rule);border-radius:2px;cursor:pointer}
.bio-toggle[hidden]{display:none}
.bio-toggle:hover{border-color:var(--brass);background:color-mix(in srgb, var(--brass) 8%, transparent);color:var(--brass)}
ul.movements{font-size:1.125rem}
.bt-tri{font-size:1em;line-height:0;margin-left:.4em;vertical-align:-.075em}

/* Primary CTA — same shape as .bio-toggle (uppercase sans, radius 2), but INVERTED into
   a filled button: brass-deep background, ink text. The one strong action on a page or
   popup. Reusable — apply `class="cta"` to that action's link/button. */
.cta{
  align-items: center;
  background: var(--orange-muted);
  border-radius: 2px;
  border: 1px solid var(--orange-muted);
  color: #fff;
  cursor: pointer;
  display: inline-flex;
  font-family: var(--sans);
  font-size: .72rem;
  font-weight: 400;
  justify-content: center;
  letter-spacing: .06em;
  line-height: normal;
  margin: 1rem 0;
  padding: .4rem .5rem;
  text-decoration: none;
  text-transform: uppercase;
  transition: background-color .2s ease, border-color .2s ease;   /* muted → bright on hover (NTI-395) */
}
/* Hover/focus brightens to full orange; text stays white — no more black-on-orange. */
.cta:hover,.cta:focus-visible{background:var(--brass);border-color:var(--brass);color:#fff}
.attribution{font-family:var(--sans);font-size:.76rem;color:var(--muted);margin:.2rem 0 0}
.attribution a{color:var(--brass-deep);text-decoration:none}
.attribution a:hover{background-size:100% 1px;color:var(--brass)}

/* blocks */
.block{margin-top:2.2rem;border-top:1px solid var(--rule);padding-top:1.2rem}
.block h2{font-family:var(--sans);font-size:.78rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);margin:0 0 .8rem;font-weight:600}

/* works */
.works{list-style:none;margin:0;padding:0}
/* Column grid shared by the sortable header and every row, so Title | Year | Genre align. */
.works li,.w-thead{display:grid;grid-template-columns:minmax(0,1fr) 3.5rem 4.5rem;gap:.9rem;align-items:baseline}   /* Title gets the room; Year needs only 4 digits, Genre only a funnel + short label */
.works li{padding:.45rem var(--pad-x);margin-inline:calc(-1 * var(--pad-x));border-bottom:1px dotted var(--rule)}   /* full-bleed rows: content stays bio-aligned, but the divider runs to the gutter like the HP list (padding:0 10px) */
.works li:last-child{border-bottom:0}
.works .w-title{font-style:italic;min-width:0}
.works .w-sub{font-style:italic;color:var(--ink-soft)}
.works .w-cat{font-family:ui-monospace,Menlo,monospace}
.works .w-flag{color:var(--brass-deep);border:1px solid var(--brass);border-radius:10px;padding:0 .4rem}
.works .gateway .w-title{font-weight:600}
.works .gateway{background:linear-gradient(90deg,#c9a2270f,transparent)}
.works .w-year{font-family:ui-monospace,Menlo,monospace;font-style:normal;font-size:.82rem;color:var(--muted);white-space:nowrap}
.works .w-genre{font-family:var(--sans);font-size:.76rem;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Sortable column header (Title / Year), matching the composers-page header. */
/* Docks just below the works toolbar as you scroll (all devices), so the column labels stay
   with the rows. Opaque bg + z-index so rows pass under it; top matches the toolbar height. */
.w-thead{padding:.5rem var(--pad-x);margin-inline:calc(-1 * var(--pad-x));border-bottom:1px solid var(--rule);align-items:center;
  position:sticky;top:var(--nav-h,56px);z-index:4;background:var(--paper)}
.w-thead[hidden]{display:none}
.w-th{font-family:var(--sans);font-size:.78rem;letter-spacing:.08em;text-transform:uppercase;font-weight:600;
  color:var(--muted);background:none;border:0;padding:0;text-align:left;display:flex;align-items:center;gap:.3rem;min-width:0}
button.w-th{cursor:pointer}
button.w-th:hover{color:var(--brass)}   /* hover previews bright orange */
.w-th.on{color:var(--brass-deep)}       /* committed sort column sits at the deep colour */
.w-arw{font-size:var(--tri-size);line-height:1;color:var(--brass-deep)}
/* Genre filter — a multi-select combo box that IS the Genre column header. It shows only a
   funnel icon (no "All genres"/selection label), so the column stays narrow and the Title column
   gets the room. The funnel goes brass + filled when a filter is active. Panel holds the checkboxes. */
.w-multi{position:relative;display:inline-flex;align-items:center;justify-self:start}
.w-multi[open]{z-index:31}
.w-multi-btn{list-style:none;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:.28rem;
  height:1.7rem;padding:0 .25rem;cursor:pointer;color:var(--brass-deep);font-size:.78rem;
  background:none;border:0;border-radius:var(--ctrl-radius)}   /* brass like the header accents; it's a dropdown, so it carries a chevron */
.w-multi-btn::-webkit-details-marker{display:none}
.w-multi-btn:hover{background:var(--paper-hi)}
.w-multi-btn:focus-visible{outline:2px solid var(--brass-deep);outline-offset:1px}
.w-multi-funnel{display:block;width:15px;height:15px}
/* the dropdown chevron (a bordered square rotated 45°, brass); flips up when open */
.w-multi-car{flex:0 0 auto;box-sizing:border-box;width:.5em;height:.5em;
  border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:rotate(45deg)}
.w-multi[open] .w-multi-car{transform:rotate(225deg)}
.w-multi.is-filtering .w-multi-funnel{fill:currentColor}   /* active filter → filled funnel */
.w-multi-panel{position:absolute;z-index:31;top:calc(100% + 4px);right:0;min-width:max-content;
  background:var(--paper-hi);border:1px solid var(--rule);border-radius:var(--ctrl-radius);
  box-shadow:0 4px 14px #2a262122;padding:.25rem;white-space:nowrap}
.w-multi-opt{display:flex;align-items:center;gap:.45rem;padding:.3rem .45rem;border-radius:2px;
  font-family:var(--sans);font-size:.72rem;font-weight:400;letter-spacing:0;text-transform:none;
  color:var(--ink);cursor:pointer}
.w-multi-opt:hover{background:var(--paper-lo)}
.w-multi-opt input{accent-color:var(--brass-deep);cursor:pointer;margin:0}
/* "Clear all" footer — shown only while something is selected (JS toggles [hidden]). */
.w-multi-clear{display:block;width:100%;text-align:left;margin-top:.15rem;padding:.34rem .45rem;
  border:0;border-top:1px solid var(--rule);background:none;cursor:pointer;
  font-family:var(--sans);font-size:.7rem;letter-spacing:.02em;color:var(--muted)}
.w-multi-clear[hidden]{display:none}
.w-multi-clear:hover{color:var(--brass)}
/* Shared styling for every native <select> on the server pages (works genre, /composers/
   filters). Add class="dropdown" to any new select. Brass control look, brass focus — never
   the browser's blue: a mouse click just tints the border, keyboard focus keeps a brass ring.
   (The Shadow-DOM timeline dropdown, .ll-genre, is a separate stylesheet and mirrors this.) */
.dropdown{font-family:var(--sans);font-size:.8rem;color:var(--brass-deep);background:var(--paper-hi);
  border:1px solid var(--rule);border-radius:var(--ctrl-radius);padding:.2rem .4rem;cursor:pointer}
.dropdown:hover{border-color:var(--brass)}
.dropdown:disabled{opacity:.5;cursor:default}
.dropdown:focus{outline:none;border-color:var(--brass-deep)}
.dropdown:focus-visible{outline:2px solid var(--brass-deep);outline-offset:1px}
.works .w-link{color:var(--brass-deep);text-decoration:none}   /* clickable → link colour (has a detail page) */
.works .w-link:hover{background-size:100% 1px;color:var(--brass)}
.works .w-plain{color:inherit;cursor:default}                  /* no extra info → plain, non-clickable text */

/* work detail page */
.recordings{list-style:none;margin:0;padding:0}
.recordings li{padding:.6rem 0;border-bottom:1px dotted var(--rule)}
.recordings li:last-child{border-bottom:0}
/* custom audio player — styled to match the toolbar buttons */
.player{display:flex;align-items:center;gap:.6rem;max-width:34rem}
.player-btn{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  width:34px;height:34px;border:1px solid var(--rule);border-radius:4px;
  background:var(--paper-hi);color:var(--brass-deep);cursor:pointer;line-height:0}
.player-btn:hover{border-color:var(--brass);background:color-mix(in srgb, var(--brass) 12%, transparent)}
.player-btn svg{width:14px;height:14px;fill:currentColor}
.player-bar{flex:1;height:7px;background:var(--paper-lo);border:1px solid var(--rule);
  border-radius:4px;overflow:hidden;cursor:pointer}
.player-fill{height:100%;width:0;background:var(--brass)}
.player-time{flex:0 0 auto;font-family:ui-monospace,Menlo,monospace;font-size:.72rem;
  color:var(--muted);min-width:6.5em;text-align:right}
.rec-cred{font-family:var(--sans);font-size:.72rem;color:var(--muted);margin:.4rem 0 0}
.rec-cred a{color:var(--brass-deep);text-decoration:none}
.rec-cred a:hover{background-size:100% 1px;color:var(--brass)}
.w-crumb{font-family:var(--sans);font-size:.8rem;margin:0 0 .35rem}
.w-crumb a{color:var(--brass-deep);text-decoration:none}
.w-crumb a:hover{color:var(--brass);background-size:100% 1px}
.w-back{margin-top:2.2rem}

/* --- works toolbar (list / timeline / sort / fullscreen) ------------------ */
.works-block{position:relative;padding-top:0;scroll-margin-top:60px}   /* #works anchor clears the sticky bar */
/* (The works section is now the full 56rem of .composer — no break-out needed.) */
/* toolbar pins to the top of the window while the works section is in view. A fixed
   min-height (matching the site header) means docking doesn't change the bar's height. */
.works-head{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;column-gap:.8rem;
  position:sticky;top:0;z-index:3;background:var(--paper);   /* BELOW the site header (z-4): the gray bar + "Works" label slide UNDER the header when docked */
  min-height:var(--nav-h,56px);padding:.35rem 0;margin-bottom:.4rem;border-bottom:1px solid var(--rule);box-sizing:border-box}   /* in-flow: no own gutter (composer's --pad-x), so "Works" + buttons line up with the table + bio */
/* Search + right-side controls: a SECOND sticky layer overlaying the .works-head row, with a z-index
   ABOVE the site header (z-4) — so on docking they float over the header while the gray .works-head
   (z-3) slides under it. Same grid/geometry as .works-head so search stays centred, tools stay right. */
.works-ctrls{position:sticky;top:0;z-index:6;box-sizing:border-box;
  display:grid;grid-template-columns:1fr auto 1fr;align-items:center;column-gap:.8rem;
  min-height:var(--nav-h,56px);padding:.35rem 0;margin-top:calc(-1 * var(--nav-h,56px));   /* pull up to sit exactly over .works-head */
  pointer-events:none}   /* transparent gaps don't swallow clicks meant for the row/content below */
.works-ctrls > *{pointer-events:auto}
/* Docked, DESKTOP ONLY: both docked layers break full-width so they align with the full-width site
   header — the controls land on the header's right gutter, the gray .works-head slides under. On a
   phone the header gutter already fills the width, so a 100vw breakout only overflows .composer's
   max-width (iOS Safari renders that as a horizontal scroll that shoves the fixed logo and stretches
   the search). Below 561px the docked bar stays in the content box, so the logo lines up with the
   header's at the same gutter. */
@media (min-width:561px){
  .works-head.stuck{width:100vw;margin-left:calc(50% - 50vw);padding:.35rem var(--pad-x)}
  .works-head.stuck ~ .works-ctrls{width:100vw;margin-left:calc(50% - 50vw);
    padding-left:var(--pad-x);padding-right:calc(var(--pad-x) + 42px)}   /* extra right pad so the tools land LEFT of the header's hamburger (26px @ right:--pad-x), not over it */
}
/* Desktop: a homepage wordmark on the left (a quick way back once you've scrolled and the
   bar has docked over the site header), the search centred, controls on the right — the
   same three-zone shape as the timeline island header. */
/* Left slot: the "Works" heading in normal flow; when the bar DOCKS it swaps to the "f"
   logo, so the docked bar merges into the page header (which also leads with the logo).
   Only one shows at a time — both live in grid column 1. */
.wh-title{grid-column:1;justify-self:start;display:block}
.works-head h2.wh-title{margin:0}
.wh-home{grid-column:1;justify-self:start;display:none;align-items:center;gap:.5rem;text-decoration:none}
.wh-logo{height:24px;width:auto}   /* same as .site-logo so the docked bar lines up with the page header */
/* name + tagline beside the logo — they live inside .wh-home, which only shows when docked or
   full-window, so the docked bar reads exactly like the page header. Hidden on mobile (the
   fixed narrow left column only has room for the mark). */
.wh-brand{font-family:var(--serif);font-weight:600;font-size:1.05rem;color:var(--brass-deep);white-space:nowrap}
.wh-tag{font-family:var(--sans);font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);white-space:nowrap}
.works-head.stuck .wh-title{display:none}
.works-head.stuck .wh-home{display:flex}
.works-sentinel{display:block;height:1px;margin-bottom:-1px}
/* Docked bar goes FULL-WIDTH (like the page header it merges into, and like the full-window
   bar): logo + wordmark hug the left, controls hug the right, the search stays centred in the
   viewport (unchanged from the in-flow bar, since it's the centre grid column either way). The
   in-flow bar, by contrast, is the narrow 44rem column with "Works" on its left. 10px sides
   line the logo up with the page header. `.stuck` is toggled by works.js. */
.works-head.stuck{z-index:5}   /* docked layering; the full-bleed breakout is desktop-only (min-width:561px block above) */
.works-block.fs-on .works-head .wh-title{display:none}   /* full-window reads as docked: logo, not "Works" */
.works-block.fs-on .wh-home{display:flex}
.works-tools{grid-column:3;justify-self:end;display:flex;align-items:center;gap:.5rem;font-family:var(--sans)}
.works-tools[hidden]{display:none}

/* Works search — centred; sizing + placeholder styling standardized to the timeline island
   header search (.ll-search / .ll-q): same padding, radius, font and muted placeholder, just
   a touch wider. Fills the bar on mobile (see the media query). The autocomplete mirrors its
   width so long titles are readable; selecting a result scrolls to + highlights the work. */
/* Search box: dark pill (#28282D), light text on the dark fill — so the "search" affordance reads the
   same across the site. A transparent 1px border at rest (no layout shift with border-box) turns
   orange on focus, matching the homepage search. */
.wt-search{grid-column:2;justify-self:center;width:var(--search-w);min-width:0;
  box-sizing:border-box;height:var(--ctrl-h);   /* match the 30px toggle + icon buttons */
  display:flex;align-items:center;gap:.4rem;font-family:var(--sans);
  background:#28282D;border:1px solid transparent;border-radius:999px;padding:0 .6rem}
.wt-search[hidden]{display:none}
.wt-search:focus-within{border-color:var(--brass)}   /* orange focus border, like the homepage search */
.wt-q-ic{flex:0 0 auto;color:#C9C3B6}
.wt-q{flex:1;min-width:0;border:0;background:none;font:inherit;font-size:.8rem;line-height:normal;color:#F6F2EC}
.wt-q::placeholder{color:#C9C3B6}
.wt-q:focus{outline:none}
.wt-q::-webkit-search-cancel-button,.wt-q::-webkit-search-decoration{-webkit-appearance:none}
/* "/" shortcut hint — same treatment as the island header's .ll-slash; JS focuses the box
   on "/" and hides this while there's text (see works.js) */
.wt-slash{flex:0 0 auto;font:inherit;font-size:.7rem;line-height:1;color:#C9C3B6;
  background:#0C0C0E;border:1px solid #37342E;border-radius:3px;padding:.12rem .34rem}
.wt-slash[hidden]{display:none}
.wt-qx{flex:0 0 auto;border:0;background:none;color:#C9C3B6;cursor:pointer;
  font-size:1.05rem;line-height:1;padding:0 .1rem}
.wt-qx:hover{color:#F6F2EC}
.wt-qx[hidden]{display:none}
/* SEARCH-RESULT BOX — shares its shape (drop, radius, shadow, max-height+scroll, "SUGGESTED …" head,
   name+year row) with .hp-results (home.css/page.css) and .ll-results (styles.ts, Shadow DOM). Only the
   palette differs (light here, dark there). When one next changes, lift the common shell into a shared
   search-results.css that home/work/composer all load. See [[search-result-box-convention]]. */
/* Anchored to .works-ctrls (the full-width row), NOT the narrow centred search box, so long work
   titles get the whole column: the left edge lines up under the search (50% − half the search width),
   the right edge reaches the column edge. right:0 tracks the docked full-bleed bar automatically.
   Mobile re-anchors it to the (stretched) search — see the phone media block. */
.wt-ac{position:absolute;left:calc(50% - var(--search-w)/2);right:0;top:calc(50% + var(--ctrl-h)/2 + 5px);z-index:30;
  background:var(--paper-hi);border:1px solid var(--rule);border-radius:5px;
  box-shadow:0 10px 28px #2a262122;max-height:min(60vh,340px);overflow-y:auto;padding:.25rem}
.wt-ac[hidden]{display:none}
.wt-ac-head{font-family:var(--sans);font-weight:600;font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);padding:.45rem .55rem}   /* like "SUGGESTED COMPOSERS" on the timeline/homepage */
.wt-ac-opt{display:block;width:100%;text-align:left;font:inherit;font-size:.82rem;
  border:0;background:none;color:var(--ink);padding:.4rem .55rem;border-radius:3px;cursor:pointer}
.wt-ac-opt:hover,.wt-ac-opt.active{background:color-mix(in srgb,var(--brass) 14%,transparent)}
.wt-ac-yr{color:var(--muted);font-family:ui-monospace,Menlo,monospace;font-size:.9em;margin-left:.4em}
.wt-ac-empty{padding:.5rem .6rem;font-size:.78rem;color:var(--muted)}
/* the work a search result jumps to — highlighted in high brass, and it stays put so the
   title link is easy to find and click. Clears on the next jump or when search is cleared. */
.works .w-hit,.tl-row.w-hit{background:color-mix(in srgb,var(--brass) 42%,transparent);
  border-radius:3px;transition:background .3s ease;cursor:pointer}   /* whole highlighted row is clickable */
.works .w-hit{box-shadow:0 0 0 3px color-mix(in srgb,var(--brass) 42%,transparent)}

/* view toggle — a segmented control. Desktop matches the HP orientation toggle (squared,
   --ctrl-radius); mobile rounds it into an iOS pill (see the media query). overflow:hidden
   clips the active brass segment to the shape. The Settings button stays separate, outside. */
.wt-seg{flex:0 0 auto;display:inline-flex;height:var(--ctrl-h)}
/* Each chip is its own bordered button (orange outline), rounded on its OUTER corners; the right chip
   drops its left border so the shared edge stays a single 1px divider — so the un-engaged side always
   reads as a complete button. Radius: squared on desktop (--ctrl-radius), pill on mobile (media query). */
.wt-chip{display:inline-flex;align-items:center;justify-content:center;font:inherit;
  border:1px solid var(--orange-muted);background:var(--paper-hi);
  color:var(--brass);padding:0 .5rem;cursor:pointer;line-height:0}   /* mobile widens these (see media query) */
.wt-chip-left{border-radius:var(--ctrl-radius) 0 0 var(--ctrl-radius)}
.wt-chip-right{border-left:0;border-radius:0 var(--ctrl-radius) var(--ctrl-radius) 0}
.wt-chip svg{display:block}
.wt-chip:hover{color:var(--brass-deep)}
.wt-chip.on{background:var(--brass);color:#fff}

/* single-icon buttons, all squared to a 31px cell so the toolbar reads as an even row */
.wt-btn{display:inline-flex;align-items:center;justify-content:center;width:var(--icon-btn);height:var(--ctrl-h);
  font:inherit;border:1px solid var(--rule);border-radius:var(--ctrl-radius);background:var(--paper-hi);
  color:var(--brass);cursor:pointer;line-height:0}
.wt-btn:hover:not(:disabled){border-color:var(--brass);color:var(--brass-deep)}
.wt-btn:disabled{opacity:.38;cursor:not-allowed}
.wt-btn.active,.wt-btn.active:hover:not(:disabled){border-color:var(--brass-deep);color:#fff;
  background:var(--brass)}

.wt-sort,.wt-filter{position:relative}
.wt-menu{position:absolute;right:0;top:calc(100% + 5px);z-index:20;min-width:196px;
  max-height:min(60vh,340px);overflow-y:auto;
  background:var(--paper-hi);border:1px solid var(--rule);border-radius:5px;
  box-shadow:0 10px 28px #2a262122;padding:.25rem}
.wt-menu[hidden]{display:none}
.wt-opt{display:block;width:100%;text-align:left;font:inherit;font-size:.78rem;
  border:0;background:none;color:var(--ink);padding:.4rem .55rem;border-radius:3px;cursor:pointer}
.wt-opt:hover{background:color-mix(in srgb, var(--brass) 14%, transparent)}
.wt-opt.on{color:var(--brass-deep);font-weight:600}
.wt-opt.on::after{content:"\2713";float:right}

/* settings menu (mobile) — View / Sort / Filter grouped behind one icon */
.wt-settings{position:relative;display:none}
/* Settings sits outside the toggle capsule as a bare black glyph — no border, no fill */
#wt-setbtn{border:0;background:none;color:var(--ink)}
#wt-setbtn:hover:not(:disabled){color:var(--ink)}
/* Titles sit in a tinted band, full-bleed across the menu, so each section reads
   as a distinct block above its (larger) options. */
.wt-grouplabel{font-family:var(--sans);font-size:.62rem;letter-spacing:.12em;text-transform:uppercase;
  color:var(--ink-soft);font-weight:700;background:var(--paper-lo);
  margin:.3rem -.25rem .14rem;padding:.3rem .55rem}
.wt-group:first-child .wt-grouplabel{margin-top:0}
/* The settings menu holds all three groups, so give it room — it shouldn't scroll
   until it genuinely runs out of viewport. */
.wt-setmenu{max-height:min(82vh,640px)}
/* Below 560px the three controls collapse into the settings menu; only the
   settings icon and the full-viewport button remain on the toolbar (sized to match). */
@media (max-width:560px){
  .wt-sort,.wt-filter{display:none}        /* sort + filter fold into the settings menu */
  .wt-settings{display:inline-block}        /* …the view toggle now stays out on the bar */
  #wt-fs{display:none}                       /* no full-viewport on mobile — just scroll */
  .wt-q{font-size:16px}                      /* iOS: an input ≥16px doesn't trigger focus-zoom */
  /* phone: search fills; the left slot (Works heading ↔ logo) is governed by the dock state.
     Fixed left column so the search box doesn't resize/shift when "Works" swaps to the logo
     on docking (auto would size to each, jarring the search). */
  .works-head{grid-template-columns:3.5rem 1fr auto}
  .works-ctrls{grid-template-columns:3.5rem minmax(0,1fr) auto}   /* search+tools moved here; minmax(0,1fr) lets the search shrink instead of overflowing the toggle off-screen */
  .wt-search{grid-column:2;justify-self:stretch;width:auto;min-width:0;border-radius:999px}   /* pill; min-width:0 so it can shrink */
  .wt-ac{left:calc(3.5rem + .8rem)}   /* phone: same right-reaching dropdown, but start at the search's left (past the 3.5rem logo column + .8rem gap) since the search isn't --search-w wide here */
  /* (No docked-bar override needed here: the full-bleed breakout is now gated to min-width:561px, so
     on a phone both docked layers already sit in the content box — logo aligned with the header's,
     no sideways overflow, no toggle jump.) */
  .wt-chip-left{border-radius:999px 0 0 999px}    /* mobile: iOS pill segmented control */
  .wt-chip-right{border-radius:0 999px 999px 0}
  .wt-chip{padding:0 .9rem}                   /* match the component's phone view-toggle chip (.ll-viewseg .ll-chip: 24px glyph + .9rem → ~53px) so the two toggles read the same; 1.25rem made these ~66px, too wide */
  .wh-brand,.wh-tag{display:none}             /* docked mobile bar shows just the mark */
  .wt-slash{display:none}                     /* no "/" shortcut on touch */
  /* year + age drop to their own second line (the ", " stays up on line 1 with the
     title), kept together so "age" and the number never split across a wrap */
  .tl-ya{display:block;white-space:nowrap}
}

/* --- timeline (dot-plot) view --------------------------------------------- */
/* Each work is a dot at its year on a full-width track; its label sits beside
   the dot — to the right when the dot is in the left half, to the left when it's
   in the right half — so labels stay inside the panel. Labels may wrap to 2 lines. */
.tl{position:relative;overflow-x:clip}   /* clip the edge dot/label overhang so the page never scrolls sideways */
/* Vertical gridlines at the labeled years, in BOTH views, so a work reads against a
   year the same way whether the panel is inline or full-viewport. Sits behind the rows. */
.tl-grid{display:block;position:absolute;inset:0;z-index:0;pointer-events:none}
.tl-grid-line{position:absolute;top:0;bottom:0;width:1px;background:var(--rule);
  opacity:.55;transform:translateX(-.5px)}
/* Vertical gridlines carry the sense of the timeline; horizontal per-row rules would
   just add noise, so the rows have no borders — only the year lines run through. */
.tl-row{position:relative;min-height:2.7em}
.tl-row.gateway{background:linear-gradient(90deg,#c9a2270f,transparent)}
.tl-dot{position:absolute;top:50%;width:9px;height:9px;border-radius:50%;
  background:var(--brass);border:1px solid var(--brass-deep);transform:translate(-50%,-50%)}
.tl-label{position:absolute;top:50%;transform:translateY(-50%);font-style:italic;
  font-size:.92rem;line-height:1.2;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.tl-label.tl-right{text-align:left;padding-left:14px}
.tl-label.tl-left{text-align:right;padding-right:14px}
a.tl-label{color:var(--brass-deep);text-decoration:none}   /* clickable → link colour */
a.tl-label:hover{background-size:100% 1px}
.tl-label.tl-plain{color:inherit;cursor:default}           /* no extra info → plain, non-clickable */
.tl-row.gateway .tl-label{font-weight:600}
.tl-y{font-style:normal;font-family:ui-monospace,Menlo,monospace;font-size:.82em;color:var(--muted)}
.tl-nd{font-style:normal;font-family:var(--sans);font-size:.7rem;color:var(--muted)}

/* year ruler — mirrors the canvas timeline's bottom tick style (monospace).
   Pins to the bottom of the window, sitting just above the (also-pinned) footer
   so scrolling text never shows below it. --footer-h is set by works.js. */
.tl-axis{position:sticky;bottom:var(--footer-h,0);z-index:2;height:46px;margin-top:.4rem;
  background:var(--paper);border-top:1px solid var(--rule);padding:.35rem 0 10px}
.tl-tick{position:absolute;top:0;transform:translateX(-50%);text-align:center}
.tl-tick::before{content:"";display:block;width:1px;height:12px;margin:0 auto .18rem;
  background:var(--ink);opacity:.6}
.tl-tick.minor::before{height:6px;opacity:.4}
.tl-ticklabel{font-family:ui-monospace,Menlo,monospace;font-size:.78rem;color:var(--ink);opacity:.85}

/* --- full-window view (an in-page overlay; the browser window is unchanged) - */
.fs-ic{display:inline-block}
.fs-collapse{display:none}
.works-block.fs-on{position:fixed;inset:0;z-index:1000;margin:0;border-top:0;
  background:var(--paper);padding:0 var(--pad-x);overflow:auto;scrollbar-gutter:stable both-edges}   /* full-window escapes .composer, so the block supplies the gutter */
.works-block.fs-on .works-head{padding-top:.5rem;margin-bottom:0}
/* Timeline fills the window below the header, and the year axis is pushed to the bottom
   (margin-top:auto) — so with few works the ruler sits at the browser bottom, never mid-screen.
   For many works the timeline grows past the viewport and the sticky axis rides the bottom. */
.works-block.fs-on .tl{display:flex;flex-direction:column;min-height:calc(100vh - var(--nav-h, 46px))}
.works-block.fs-on .tl-axis{margin-top:auto}
/* Full-window mode is already full-width, so the docked re-inset (which targets the 44rem
   in-page container) would wrongly pull the logo + controls toward the centre on scroll.
   Keep the docked bar full-width here so nothing moves; the 1rem side padding + symmetric
   scrollbar-gutter above give the logo and the controls equal space from each edge. */
.works-block.fs-on .works-head.stuck{width:auto;margin-left:0;padding-left:0;padding-right:0}
.works-block.fs-on .tl-axis{bottom:0}
.works-block.fs-on .fs-expand{display:none}
.works-block.fs-on .fs-collapse{display:inline-block}

/* links */
.links{list-style:none;margin:0;padding:0}
.links li{padding:.35rem 0;font-family:var(--sans);font-size:.76rem}
.links a{color:var(--brass-deep);text-decoration:none}
.links a:hover{background-size:100% 1px;color:var(--brass)}
.links .l-src{font-family:var(--sans);font-size:.72rem;color:var(--muted);margin-left:.5rem}


/* --- Program page — custom-focus split view (Phase 7.5) -----------------------
   Only custom-focus pages use this (timeline/program.html); /timeline/ + the homepage
   are unchanged. Bounded to one screenful on desktop: the full-width header + footer
   cross the page, a two-pane split sits between. The LEFT pane scrolls INTERNALLY —
   never the host page (the embed rule, NTI-335) — and the RIGHT pane is the vertical
   miniature timeline filling its box. Phones stack it (playlist, then timeline). */
body.program-page{height:100svh;overflow:hidden}          /* desktop: no page scroll */
.program-page .site-header{flex:0 0 auto}
/* EMBED (NTI-336): the bounded iframe card swaps the site header/footer for one slim brand bar;
   .program-split below fills the rest of the iframe. Deliberately minimal so it doesn't fight a
   host site's own sticky chrome (a white-label / no-bar option can drop it later). */
.embed-bar{flex:0 0 auto;display:flex;align-items:center;gap:.5rem;height:38px;padding:0 12px;
  border-bottom:1px solid var(--rule);background:linear-gradient(180deg,var(--paper-hi),var(--paper));
  font-family:var(--sans)}
.embed-brand{color:var(--brass-deep);font-family:var(--serif);font-weight:600;font-size:1rem;
  text-decoration:none;white-space:nowrap}
.embed-brand:hover,.embed-explore:hover{color:var(--brass)}
.embed-title{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  color:var(--muted);font-size:.75rem}
.embed-explore{color:var(--brass-deep);font-family:var(--serif);font-weight:600;font-size:.85rem;
  text-decoration:none;white-space:nowrap;flex:0 0 auto}
.program-split{flex:1;min-height:0;display:flex;align-items:stretch;
  overflow:hidden;max-width:none;margin:0;padding:0}
.program-text{flex:1 1 0;min-width:0;overflow-y:auto;
  padding:0.75rem var(--pad-x) 2rem;border-right:1px solid var(--rule)}   /* even 50-50 split */
.program-stage{flex:1 1 0;min-width:0;position:relative}
.program-stage long-line{display:block;width:100%;height:100%;border:0;border-radius:0}
.program-handle{display:none}   /* desktop: no bubble — the timeline fills the right pane directly */

/* Draggable split: desktop + iPad landscape only. A slim divider between the panes drags the even
   50/50 split leftward down to 25/75 — handing the timeline more width when the playlist titles are
   short. Below 1024px (iPad portrait, phones) the divider is hidden and the split stays a fixed 50/50. */
.split-resizer{display:none}
@media (min-width:1024px){
  .program-text{flex-grow:0;flex-shrink:0;flex-basis:var(--split,50%);border-right:0}   /* basis driven by the drag; JS clamps to 25–50% */
  .split-resizer{display:flex;flex:0 0 12px;align-items:center;justify-content:center;position:relative;z-index:3;
    background:var(--paper);border-inline:1px solid var(--rule);cursor:col-resize;touch-action:none;user-select:none}
  .split-resizer::before{content:"";width:4px;height:38px;border-radius:2px;background:var(--rule);transition:background .15s}
  .split-resizer:hover::before,
  .split-resizer:focus-visible::before,
  .program-split.resizing .split-resizer::before{background:var(--brass)}   /* grip warms to orange on hover / drag */
  .split-resizer:focus-visible{outline:none}
  .program-split.resizing{cursor:col-resize;user-select:none}   /* hold the resize cursor while dragging over either pane */
}

/* Playlist typography — editorial serif, same language as the bio/composer pages. */
.program-title{font-family:var(--serif);font-size:1.8rem;line-height:1.15;font-weight:600;
  color:var(--brass-deep);margin:0 0 1rem}
.program-text h1,.program-text h2,.program-text h3{font-family:var(--serif);color:var(--ink);
  margin:.2rem 0 .4rem;font-weight:600}
.program-text h1{font-size:1.5rem}
.program-text h2{font-size:1.25rem; margin-top:2.4rem}
/* Roomy top margin so each entry (an <h3> "Composer: Work" per piece on an ingested play history) has
   air — a less-dense left column lets the right-side scroll-sync reveal read one piece at a time. */
.program-text h3{font-size:1.05rem; margin-top:2.4rem}
.program-text h3:first-child{margin-top:0}
.program-text p{margin:0;line-height:1.6}
.program-text strong{font-weight:600}
.program-text em{font-style:italic}

/* ── Global link hover: a 1px underline that wipes in from the left, the same effect as the program
   .pl-ref / .ll-ref refs. One rest-state definition for every text link on the page; the individual
   :hover rules elsewhere just set `background-size:100% 1px`. Buttons (.cta) and the docked logo
   (.wh-home) carry their own background, so they're not in this list and stay unaffected. */
.timeline-link,.attribution a,.works .w-link,.rec-cred a,.w-crumb a,a.tl-label,.links a,
.site-footer a,.ref-lb-cta{
  text-decoration:none;background-image:linear-gradient(currentColor,currentColor);
  background-repeat:no-repeat;background-position:left bottom;background-size:0 1px;
  transition:background-size .8s ease}
/* Auto-linked composer names: click → light up the matching name on the timeline (no popup). */
.program-text .pl-ref{color:var(--brass-deep);text-decoration:none;cursor:pointer;padding-bottom:1px;
  /* underline is a 1px bar drawn in the text colour; it wipes in from the LEFT on hover (200ms) */
  background-image:linear-gradient(currentColor,currentColor);
  background-repeat:no-repeat;background-position:left bottom;background-size:0% 1px;
  transition:background-size 800ms ease}
.program-text .pl-ref:hover{background-size:100% 1px;color:var(--brass)}
.program-text .pl-ref.active{background-color:color-mix(in srgb,var(--brass) 20%,transparent);
  border-radius:2px;box-shadow:0 0 0 2px color-mix(in srgb,var(--brass) 20%,transparent)}

/* Auto-linked work titles (.ll-ref): click → the reference lightbox (like the composer bio popup).
   Uses the brass link colour like composer names, so it reads as clickable before you hover. */
.program-text .ll-ref{color:var(--brass-deep);text-decoration:none;cursor:pointer;
  background-image:linear-gradient(var(--brass-deep),var(--brass-deep));
  background-repeat:no-repeat;background-position:left bottom;background-size:0% 1px;
  transition:background-size 800ms ease}
.program-text .ll-ref:hover{background-size:100% 1px;color:var(--brass)}

/* Reference lightbox — ONE card for any .ll-ref kind (works today; composers/… later). Cream paper, serif. */
.ref-lb{position:fixed;inset:0;z-index:60;display:flex;align-items:center;justify-content:center;padding:1.2rem}
.ref-lb[hidden]{display:none}
.ref-lb-backdrop{position:absolute;inset:0;background:rgba(20,17,12,.5)}
.ref-lb-card{position:relative;max-width:34rem;width:100%;max-height:82vh;
  display:flex;flex-direction:column;overflow:hidden;   /* the card is fixed — only the description scrolls */
  background:var(--paper-hi);color:var(--ink);border:1px solid var(--rule);border-radius:6px;
  box-shadow:0 18px 60px rgba(20,17,12,.4)}
.ref-lb-card:focus{outline:none}   /* focused programmatically for a11y (tabindex=-1) — not a visible focus target */
.ref-lb-body{display:flex;flex-direction:column;min-height:0;flex:1}
/* Sticky header (like the bio panel's .ll-pt): sub + title + meta stay put; the blurb scrolls below. */
.ref-lb-head{flex:0 0 auto;padding:1.5rem 1.7rem .9rem;border-bottom:1px solid var(--rule)}
/* Close X — matches the composer bio lightbox's .ll-x (a 23px SVG in a 34×34 button). */
.ref-lb-x{position:absolute;top:.35rem;right:.4rem;z-index:2;display:flex;align-items:center;justify-content:center;
  width:34px;height:34px;margin:0;padding:0;border:0;background:none;color:var(--muted);cursor:pointer}
.ref-lb-x svg{width:23px;height:23px}
.ref-lb-x:hover{color:var(--ink)}
.ref-lb-sub{font-family:var(--sans);font-size:.82rem;letter-spacing:.04em;color:var(--muted);margin:0 0 .15rem}
.ref-lb-title{font-family:var(--serif);font-size:1.5rem;font-weight:600;line-height:1.15;margin:0 0 .7rem;color:var(--ink)}
.ref-lb-meta{display:flex;flex-wrap:wrap;gap:.4rem;margin:0}   /* last row in the fixed header — its padding gives the gap */
.ref-lb-tag{font-family:var(--sans);font-size:.72rem;color:var(--ink-soft);
  background:var(--paper-lo);border:1px solid var(--rule);border-radius:999px;padding:.15rem .6rem}
/* The scrolling region — the description only. */
.ref-lb-blurb{flex:1 1 auto;min-height:0;overflow-y:auto;padding:1.1rem 1.7rem;
  font-family:var(--serif);font-size:1.02rem;line-height:1.55;color:var(--ink)}
.ref-lb-blurb p{margin:0 0 .8rem}.ref-lb-blurb p:last-child{margin-bottom:0}
/* CTA — pinned footer under the scroll, so "Open the work page" stays reachable. */
.ref-lb-cta{flex:0 0 auto;display:block;padding:.85rem 1.7rem 1.1rem;border-top:1px solid var(--rule);
  font-family:var(--sans);font-size:.82rem;font-weight:600;color:var(--brass-deep);text-decoration:none}
.ref-lb-cta:hover{background-size:100% 1px;color:var(--brass)}
.ref-lb-loading{padding:1.4rem 1.7rem;font-family:var(--sans);color:var(--muted)}
body.ref-lb-open{overflow:hidden}

/* Preview banner (draft shown to staff / ?preview token) — pink on brass, like the timeline page. */
.program-preview{position:fixed;z-index:10;top:0;left:50%;transform:translateX(-50%);
  background:#A2801A;color:#F7D2D8;font:700 12px/1 var(--sans);letter-spacing:.09em;
  text-transform:uppercase;padding:7px 14px;border-radius:0 0 7px 7px;box-shadow:0 2px 8px #0003}

/* Phone: the playlist is the page (scrolls normally); the timeline is a bottom SHEET. Collapsed it's
   an "Explore the composers" bubble that rides above the Safari bar and hides on scroll-down (like the
   URL bar); tapping it flies up to a full-screen card, tapping the top handle sends it back down. */
@media (max-width:760px){
  body.program-page{height:auto;overflow:visible}
  body.program-page.sheet-open{overflow:hidden}          /* full-screen sheet up → lock the page behind it */
  .program-split{flex-direction:column;overflow:visible}
  .program-text{flex:0 0 auto;overflow:visible;border-right:0;padding-bottom:5rem}   /* clear the bubble */

  /* Anchored at the bottom; grows its HEIGHT to fly up (no `top` jump). Column: handle then canvas. */
  .program-stage{
    position:fixed;left:12px;right:12px;bottom:calc(env(safe-area-inset-bottom,0px) + 10px);
    height:52px;z-index:40;flex:none;display:flex;flex-direction:column;
    background:#FDFDFB;border:1px solid var(--rule);border-radius:26px;   /* near-white → pops off the paper page, reads as a popup layer that invites a tap */
    box-shadow:0 6px 22px #00000030;overflow:hidden;
    transition:left .3s ease, right .3s ease, bottom .3s ease, height .3s ease,
               border-radius .3s ease, transform .28s ease}
  .program-stage long-line{display:none}                 /* collapsed: just the bubble */
  .program-handle{display:flex;align-items:center;justify-content:center;position:relative;
    flex:1 1 auto;width:100%;background:none;border:0;cursor:pointer;padding:0;touch-action:none}
  .program-grip{position:absolute;top:7px;left:50%;transform:translateX(-50%);
    width:36px;height:4px;border-radius:2px;background:var(--muted);opacity:.55}
  .program-cta{font-family:var(--sans);font-weight:600;font-size:1.25rem;color:var(--brass-deep)}

  /* Hidden on scroll-down (mimics the Safari toolbar collapsing). */
  .program-stage.bubble-hidden{transform:translateY(calc(100% + env(safe-area-inset-bottom,0px) + 18px))}

  /* Expanded → full-screen card. 16px top corners + the handle read as "slide me back down". The
     handle is a 28px strip ABOVE the canvas (never overlapping the timeline's own header). */
  .program-stage.expanded{left:0;right:0;bottom:0;height:100svh;
    border-radius:16px 16px 0 0;transform:none;box-shadow:0 -6px 30px #0000003a}
  .program-stage.expanded .program-handle{flex:0 0 28px}   /* top strip = tap to fly back down */
  .program-stage.expanded .program-cta{display:none}
  .program-stage.expanded .program-grip{top:9px;width:52px;opacity:.6}
  .program-stage.expanded long-line{display:block;flex:1 1 auto;width:100%;min-height:0;
    /* the whole popup reads on the near-white popup paper (matches the collapsed capsule); component re-resolves on expand */
    --ll-paper:#FDFDFB;--ll-paper-hi:#FFFFFF;--ll-paper-lo:#F1ECE2}
}

/* Recording / release list — box sets & recent recordings on the composer page (NTI-231/234).
   Mirrors .rec-list in page.css (work page); composer.html loads site.css, not page.css, so the
   component is defined here too. No page loads both stylesheets, so there's no conflict. */
.rec-list{list-style:none;margin:0;padding:0}
.rec-list li{position:relative;padding:11px 0;border-top:1px solid var(--rule);font-family:var(--sans);font-size:15.5px}
.rec-list li:first-child{border-top:0}
.rec-perf{font-weight:500}
.rec-year{color:var(--grey);font-variant-numeric:tabular-nums}
.rec-tag{display:inline-block;margin-left:.45em;padding:.05em .5em;border:1px solid var(--rule);border-radius:999px;
  font-family:var(--sans);font-size:11.5px;color:var(--grey);vertical-align:middle}
.rec-links{display:flex;flex-wrap:wrap;gap:.9em;margin-top:.3rem}
.rec-links a.rec-svc{display:inline-flex;align-items:center;gap:.35em;font-size:13.5px;white-space:nowrap}
.rec-ico{width:16px;height:16px;flex:0 0 16px}
.rec-note{margin:.7rem 0 0;font-family:var(--sans);font-size:12.5px;color:var(--grey)}
