@font-face {
  font-family: "Geist";
  src: url("assets/fonts/Geist-Variable.woff2") format("woff2");
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
}
@font-face {
  font-family: "Geist Mono";
  src: url("assets/fonts/GeistMono-Variable.woff2") format("woff2");
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
}
@font-face {
  font-family: "Familjen Grotesk";
  src: url("assets/familjen-500.ttf") format("truetype");
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: "Familjen Grotesk";
  src: url("assets/familjen-700.ttf") format("truetype");
  font-weight: 700;
  font-display: swap;
}
@font-face {
  font-family: "Instrument Sans";
  src: url("assets/instrument-400.ttf") format("truetype");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Instrument Sans";
  src: url("assets/instrument-600.ttf") format("truetype");
  font-weight: 600;
  font-display: swap;
}
:root {
  color-scheme: light;
  font-synthesis: none;
  --ease: cubic-bezier(.22, 1, .36, 1);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body { margin: 0; min-width: 320px; }
img { display: block; max-width: 100%; }
a { color: inherit; }
button, a { -webkit-tap-highlight-color: transparent; }
button { font: inherit; }
[hidden] { display: none !important; }
.concept { min-height: 100vh; font-family: "Instrument Sans", Arial, sans-serif; }
.site-header {
  position: absolute; z-index: 20; top: 0; left: 0; width: 100%; display: flex; justify-content: space-between; align-items: center;
}
.site-header nav { display: flex; align-items: center; gap: clamp(18px, 2.4vw, 38px); }
.site-header a { text-decoration: none; }
.site-header nav a:not(.client-link) { position: relative; }
.site-header nav a:not(.client-link)::after {
  content: ""; position: absolute; left: 0; right: 100%; bottom: -4px; height: 1px;
  background: currentColor; transition: right .35s var(--ease);
}
.site-header nav a:hover::after, .site-header nav a:focus-visible::after { right: 0; }
.client-link { padding: 10px 14px; border: 1px solid currentColor; }
.eyebrow { margin: 0; font-size: 10px; line-height: 1.2; letter-spacing: .16em; text-transform: uppercase; }
/* CONCEPT A — RESONANT INDEX */
.concept-a { --paper: #e8e8e3; --ink: #0a0b0d; --oxide: #865d10; --rule: #bec0ba; background: var(--paper); color: var(--ink); font-family: "Geist", "Instrument Sans", Arial, sans-serif; font-weight: 300; }
.a-header { padding: 24px 30px 0; font-size: 12px; }
.a-header .site-name { font-family: "Geist", "Instrument Sans", sans-serif; font-size: 13px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; }
.a-header nav, .concept-a .eyebrow, .string-note, .string-preview, .a-evidence cite, .work-meta, .work-note, .work-action, .footer-meta { font-family: "Geist Mono", ui-monospace, monospace; }
.a-header nav { font-size: 11px; letter-spacing: .12em; text-transform: uppercase; }
.a-header .client-link { border-color: var(--rule); }
.a-hero { min-height: 100svh; position: relative; overflow: hidden; }
.a-composition { position: absolute; top: 50%; right: 0; left: 0; height: clamp(390px, 58vh, 540px); transform: translateY(-50%); }
.a-title-field { position: absolute; z-index: 1; top: 0; right: 30px; left: 30px; }
.a-title-field h1 { margin: 0; font: 300 clamp(108px, 13vw, 176px)/.74 "Geist", "Instrument Sans", sans-serif; letter-spacing: -.045em; text-transform: uppercase; }
.a-title-field h1 > span { display: block; white-space: nowrap; }
.a-title-field h1 i { font-style: normal; }
body[data-title-type="2"] .a-title-field h1 {
  font-family: "Anybody", "Geist", sans-serif;
  font-size: clamp(102px, 12.5vw, 170px);
  font-weight: 300;
  font-variation-settings: "wdth" 132, "wght" 300;
  line-height: .76;
  letter-spacing: -.035em;
}
body[data-title-type="3"] .a-title-field h1 {
  font-family: "Syne", "Geist", sans-serif;
  font-size: clamp(102px, 12.7vw, 172px);
  font-weight: 400;
  line-height: .74;
  letter-spacing: -.065em;
}
body[data-title-type="4"] .a-title-field h1 {
  font-family: "Newsreader", Georgia, serif;
  font-size: clamp(106px, 13.2vw, 180px);
  font-weight: 300;
  font-optical-sizing: auto;
  line-height: .75;
  letter-spacing: -.055em;
}
.string-index { position: absolute; z-index: 2; top: clamp(248px, 20vw, 285px); right: 0; left: 0; display: grid; height: clamp(150px, 18vh, 190px); grid-template-rows: repeat(4, 1fr); }
.string-row {
  --label-x: 50%; --label-w: 128px; --ring-size: 90px; min-height: 36px; position: relative; color: inherit; text-decoration: none;
}
.string-row:nth-child(1) { --label-x: 18%; --label-w: 150px; }
.string-row:nth-child(2) { --label-x: 64%; --label-w: 130px; }
.string-row:nth-child(3) { --label-x: 39%; --label-w: 112px; }
.string-row:nth-child(4) { --label-x: 78%; --label-w: 150px; }
.string-title { position: absolute; z-index: 2; top: 50%; left: var(--label-x); width: max-content; height: 34px; display: grid; grid-template-columns: minmax(0, 1fr); place-items: center; overflow: visible; font-size: clamp(16px, 1.25vw, 20px); font-weight: 300; letter-spacing: -.025em; white-space: nowrap; transform: translate(-50%, -50%); transition: color .25s ease; }
/* No-JS fallback for the string labels.
   The break in the line is drawn by the script as a stroke-dasharray gap, so
   with it absent the line runs straight through every label — reproduced by
   serving the page with the <script> removed, which is what Finder's Quick
   Look, Mail's preview pane and several chat previewers do. The script sets
   html.js as its first act, so scoping the old paper knockout to html:not(.js)
   restores the gap for those viewers and changes nothing when it does run. */
html:not(.js) .string-title,
html:not(.js) .rail-item .string-title {
  background: var(--paper); padding: 0 12px;
}

.string-title-text, .string-note { min-width: 0; grid-area: 1 / 1; }
.string-title-text { transition: opacity .1s linear; }
.string-note { position: relative; width: 100%; height: 100%; place-self: center; opacity: 0; color: #684708; transform: scale(.35) rotate(-38deg); }
.string-note { transition: opacity .18s ease, transform .4s var(--ease); }
.string-note-character { position: absolute; top: 50%; left: 50%; width: 11px; height: 12px; margin: -6px 0 0 -5.5px; font: 600 var(--ring-font-size, 9.5px)/12px "Geist Mono", ui-monospace, monospace; letter-spacing: 0; text-align: center; transform: rotate(var(--ring-angle)) translateY(-34px); }
.string-line { position: absolute; z-index: 0; top: 50%; right: 0; left: 0; height: 60px; color: var(--ink); transform: translateY(-50%); transition: color .25s ease; }
.string-line svg { width: 100%; height: 100%; overflow: visible; }
.string-line path { fill: none; stroke: currentColor; stroke-width: 1.25; vector-effect: non-scaling-stroke; }
.string-preview { display: none; }
.string-row:hover .string-title, .string-row:focus-visible .string-title { color: var(--oxide); }
.string-row:hover .string-title-text, .string-row:focus-visible .string-title-text { opacity: 0; transform: none; }
.string-row:hover .string-note, .string-row:focus-visible .string-note { opacity: 1; transform: scale(1) rotate(0); }
.string-row:hover .string-line, .string-row:focus-visible .string-line { color: var(--oxide); }
.string-row:focus-visible { outline: 0; }
.string-row:focus-visible .string-title { outline: 0; }
.a-evidence { position: absolute; z-index: 3; right: 30px; bottom: 28px; left: 30px; display: grid; grid-template-columns: 1fr 1fr; gap: 8vw; align-items: end; pointer-events: none; }
.a-evidence blockquote { width: fit-content; max-width: min(46vw, 720px); min-width: 0; margin: 0; }
.a-evidence blockquote:last-child { justify-self: end; text-align: left; }
.a-evidence p { margin: 0 0 10px; font-size: clamp(19px, 1.55vw, 26px); font-weight: 300; line-height: 1.18; letter-spacing: -.025em; }
.a-evidence cite { display: block; max-width: 100%; color: var(--oxide); font-size: 9px; font-style: normal; line-height: 1.45; letter-spacing: .1em; text-transform: uppercase; }
.a-evidence cite span { display: block; margin: 1px 0 0; color: #5a5a55; }
/* 64px, not 140: the grid starts closer here than it did on the old
   one-pager. This lived in a slug-scoped override until the category rename
   (film-series/stage-art/ds-project/collaborations -> screen/stage/records/
   arrangements) silently orphaned every one of its selectors, and the pages
   fell back to 140px without anything failing visibly. .a-works appears only
   on the four category pages — works.html and reel.html load the old
   stylesheet — so the base rule can carry it and there is no slug list left
   to go stale. */
.a-works { padding: 64px 30px 120px; }
.section-heading { margin-bottom: 90px; }
.section-heading h2 { margin: 0; font: 300 clamp(40px, 4.5vw, 72px)/.96 "Geist", "Instrument Sans", sans-serif; letter-spacing: -.03em; }
.a-work-group { margin-bottom: 150px; scroll-margin-top: 28px; }
.a-work-group:last-child { margin-bottom: 0; }
.a-work-group-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 34px; padding-top: 18px; border-top: 1px solid var(--ink); }
.a-work-group-head h3 { margin: 0; font: 300 clamp(28px, 3vw, 46px)/1 "Geist", "Instrument Sans", sans-serif; letter-spacing: -.035em; }
.a-work-group-head a, .a-streams { font: 400 9px/1.4 "Geist Mono", ui-monospace, monospace; letter-spacing: .1em; text-transform: uppercase; }
.a-work-group-head a { text-decoration: none; }
.a-work-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; align-items: start; }
.a-work { display: grid; grid-template-columns: 1fr auto; gap: 4px 12px; color: inherit; text-decoration: none; }
.a-work figure { grid-column: 1 / -1; margin: 0 0 14px; aspect-ratio: 3 / 4; overflow: hidden; background: #151310; position: relative; }
.a-work-grid-square .a-work figure { aspect-ratio: 1; }
.a-work img { width: 100%; height: 100%; object-fit: cover; filter: grayscale(1) contrast(.96) brightness(.92); transition: transform .9s var(--ease), filter .55s ease; }
a.a-work:hover img, a.a-work:focus-visible img { transform: scale(1.055); filter: grayscale(0) saturate(1.12) contrast(1.07) brightness(.96); }
.work-action { position: absolute; right: 10px; bottom: 10px; left: 10px; display: flex; justify-content: space-between; padding: 9px 10px; background: rgba(239,232,217,.94); color: var(--ink); font-size: 9px; text-transform: uppercase; letter-spacing: .12em; opacity: 0; transform: translateY(8px); transition: opacity .22s ease, transform .35s var(--ease); }
.a-work:hover .work-action, .a-work:focus-visible .work-action { opacity: 1; transform: none; }
.a-work:focus-visible { outline: 2px solid var(--oxide); outline-offset: 5px; }
.work-title { font-size: 18px; letter-spacing: -.025em; }
.work-meta, .work-note { color: #686258; font-size: 10px; line-height: 1.4; }
.work-meta { text-align: right; }
.work-note { grid-column: 1 / -1; }
.a-streams { grid-column: 1 / -1; display: flex; gap: 16px; margin-top: 7px; color: var(--oxide); }
.a-streams a { text-underline-offset: 3px; }
.a-about { display: grid; grid-template-columns: minmax(260px, .8fr) 1.3fr; gap: 7vw; padding: 120px 30px; }
.a-about img { width: 100%; aspect-ratio: 1; object-fit: cover; filter: grayscale(1); }
.a-about h2 { max-width: 800px; margin: 0 0 46px; color: var(--oxide); font: 300 clamp(40px, 4.5vw, 68px)/1 "Geist", "Instrument Sans", sans-serif; letter-spacing: -.03em; }
.a-about p { max-width: 670px; margin: 0 0 18px; font-size: clamp(15px, 1.25vw, 19px); line-height: 1.55; }
.a-about .a-about-lede { margin-bottom: 30px; font-size: clamp(21px, 2vw, 30px); line-height: 1.3; letter-spacing: -.02em; }
.text-link { display: inline-block; margin-top: 22px; text-decoration: none; border-bottom: 1px solid; }
.a-footer { padding: 100px 30px 30px; }
.a-footer .eyebrow { color: var(--oxide); }
.contact-call { display: flex; justify-content: space-between; margin: 28px 0 100px; font: 300 clamp(48px, 8vw, 128px)/.94 "Geist", "Instrument Sans", sans-serif; letter-spacing: -.035em; text-decoration: none; }
.footer-meta { display: flex; justify-content: space-between; color: #686258; font-size: 10px; text-transform: uppercase; letter-spacing: .12em; }
@media (max-width: 900px) {
  .site-header { align-items: flex-start; }
  .site-header nav { gap: 14px; flex-wrap: wrap; justify-content: flex-end; }
  .site-header nav a { font-size: 10px; }
  .client-link { padding: 7px 9px; }
  .a-title-field h1 { font-size: clamp(92px, 16vw, 140px); }
  body[data-title-type="2"] .a-title-field h1 { font-size: clamp(88px, 15vw, 132px); }
  body[data-title-type="3"] .a-title-field h1 { font-size: clamp(88px, 15.2vw, 134px); }
  body[data-title-type="4"] .a-title-field h1 { font-size: clamp(90px, 15.5vw, 138px); }
  .string-index { top: clamp(270px, 40vh, 340px); height: 150px; }
  .a-evidence { gap: 32px; }
  .a-work-grid { grid-template-columns: repeat(2, 1fr); gap: 42px 14px; }
  .a-about { grid-template-columns: 1fr 1.4fr; gap: 32px; }
}
@media (max-height: 800px) and (min-width: 641px) {
  .a-composition { top: 51%; height: 380px; }
  .a-title-field h1 { font-size: clamp(94px, 14vw, 150px); }
  body[data-title-type="2"] .a-title-field h1 { font-size: clamp(90px, 13.5vw, 144px); }
  body[data-title-type="3"] .a-title-field h1 { font-size: clamp(90px, 13.7vw, 146px); }
  body[data-title-type="4"] .a-title-field h1 { font-size: clamp(92px, 13.8vw, 148px); }
  .string-index { top: 220px; height: 150px; }
  .string-row { min-height: 36px; }
  .string-line { height: 54px; }
  .a-evidence { bottom: 18px; }
}
@media (max-width: 640px) {
  .switcher-label { display: none; }
  .site-header { padding-left: 16px; padding-right: 16px; }
  .site-header > .site-name,
  .site-header nav a { min-height: 44px; display: flex; align-items: center; }
  .site-header > .site-name { min-width: 44px; }
  .site-header nav a:not(.client-link) { min-width: 44px; justify-content: center; }
  .a-header .site-name { max-width: 130px; font-size: 11px; line-height: 1.1; }
  .a-composition { top: 48%; height: 310px; }
  .a-title-field { top: 0; right: 16px; left: 16px; }
  .a-title-field h1 { font-size: clamp(58px, 17.5vw, 74px); line-height: .78; }
  body[data-title-type="2"] .a-title-field h1 { font-size: clamp(42px, 13.3vw, 56px); }
  body[data-title-type="3"] .a-title-field h1 { font-size: clamp(54px, 16.5vw, 69px); }
  body[data-title-type="4"] .a-title-field h1 { font-size: clamp(57px, 17.2vw, 72px); }
  .string-index { top: 132px; height: 148px; }
  .string-row { min-height: 36px; }
  .string-row:nth-child(1) { --label-x: 27%; --label-w: 118px; }
  .string-row:nth-child(2) { --label-x: 69%; --label-w: 105px; }
  .string-row:nth-child(3) { --label-x: 34%; --label-w: 88px; }
  .string-row:nth-child(4) { --label-x: 67%; --label-w: 122px; }
  .string-line { height: 48px; }
  .string-title { font-size: 14px; }
  .string-row { --ring-size: 78px; }
  .a-evidence { right: 16px; bottom: 64px; left: 16px; grid-template-columns: 1fr; gap: 10px; }
  .a-evidence blockquote { max-width: 100%; }
  .a-evidence blockquote:last-child { justify-self: start; }
  .a-evidence p { margin-bottom: 5px; font-size: 15px; line-height: 1.2; }
  .a-evidence cite { font-size: 7px; }
  .a-works { padding: 100px 16px 80px; }
  .section-heading h2 { font-size: 48px; }
  .a-work-group { margin-bottom: 100px; scroll-margin-top: 18px; }
  .a-work-group-head { margin-bottom: 24px; }
  .a-work-group-head h3 { font-size: 30px; }
  .a-work-grid { grid-template-columns: 1fr 1fr; }
  .a-work { display: block; }
  .a-work .work-title, .a-work .work-meta, .a-work .work-note { display: block; text-align: left; margin-bottom: 3px; }
  .a-work .work-title { font-size: 16px; }
  .a-about { grid-template-columns: 1fr; padding: 80px 16px; }
  .a-about img { max-width: 72%; }
  .a-footer { padding: 72px 16px 84px; }
  .contact-call { margin-bottom: 70px; font-size: 50px; }
  .footer-meta { display: grid; gap: 8px; }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
.skip-link { position: fixed; z-index: 100; top: 8px; left: 8px; padding: 10px 14px; transform: translateY(-150%); background: var(--ink); color: var(--paper); text-decoration: none; }
.skip-link:focus { transform: none; }


/* ═══ THE STRING BREAKS FOR ITS LABEL ═════════════════════
   No knockout, no covering layer: stroke-dasharray stops the
   line before the label and resumes after it, the way an
   engraver leaves room on a staff. Dash values are measured
   per row in app.js; the transition matches the label's own
   .55s expansion so the gap opens as the note grows.        */
.string-line path { transition: stroke-dasharray .55s var(--ease), stroke .25s ease; }
html.js:not(.strings-ready) .page-index .string-line path { transition: none; }
@media (prefers-reduced-motion: reduce) { .string-line path { transition: none; } }


/* ═══ WORKS: THE POSTER NAMES WHERE IT GOES ═══════════════
   Three linking models became one. The card is no longer a
   link; each destination is named and is its own link, so a
   card with nowhere to go simply stays quiet instead of
   inviting a click that does nothing.
   Progressive enhancement: without JS the original whole-card
   links and stream links still work, so only hide them once
   the script has actually run.                                */
.js .a-streams   { display: none; }

.a-work figure { position: relative; }

/* grey at rest; colour and a small lift on hover */
.a-work img { transition: transform .9s var(--ease), filter .55s ease; }
.a-work.has-dest:hover img,
.a-work.has-dest:focus-within img {
  filter: none;
  transform: scale(1.04);
}

/* just enough scrim under the name to keep it legible on a
   bright poster, without undoing the colour it just gained */
.a-work.has-dest figure::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(to bottom, rgba(10,11,13,.14), rgba(10,11,13,.52));
  opacity: 0; transition: opacity .35s ease; pointer-events: none;
}
.a-work.has-dest:hover figure::after,
.a-work.has-dest:focus-within figure::after { opacity: 1; }

.dests {
  position: absolute; inset: 0; z-index: 2;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 4px;
  padding: 14px; text-align: center;
  opacity: 0; transform: translateY(9px); pointer-events: none;
  transition: opacity .28s ease, transform .45s var(--ease);
}
.a-work.has-dest:hover .dests,
.a-work.has-dest:focus-within .dests { opacity: 1; transform: none; pointer-events: auto; }

.dest {
  font: 300 clamp(19px, 2vw, 30px)/1.1 "Geist", "Instrument Sans", sans-serif;
  letter-spacing: -.03em; color: var(--paper);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: .17em;
  text-shadow: 0 1px 20px rgba(10,11,13,.6);
  transition: opacity .25s ease;
}
.dest:hover { opacity: .72; }
.dest:focus-visible { outline: 2px solid var(--paper); outline-offset: 6px; }

/* same rule everywhere else a link appears: plain text, underline */
.a-work-group-head a {
  text-decoration: underline; text-decoration-thickness: 1px;
  text-underline-offset: .28em; text-decoration-color: transparent;
  transition: text-decoration-color .25s ease;
}
.a-work-group-head a:hover, .a-work-group-head a:focus-visible { text-decoration-color: currentColor; }
.contact-call {
  text-decoration: underline; text-decoration-thickness: 1px;
  text-underline-offset: .12em; text-decoration-color: transparent;
  transition: text-decoration-color .3s ease, color .3s ease;
}
.contact-call:hover, .contact-call:focus-visible { text-decoration-color: currentColor; }

@media (max-width: 640px) {
  /* no hover on touch — the name rides with the caption instead */
  .dests { position: static; opacity: 1; transform: none; pointer-events: auto;
           inset: auto; padding: 0; align-items: flex-start; gap: 2px; margin-top: 6px; }
  .a-work.has-dest figure::after { display: none; }
  .dest { font-size: 15px; color: var(--oxide); text-shadow: none; }
}
@media (prefers-reduced-motion: reduce) {
  .a-work.has-dest:hover img, .a-work.has-dest:focus-within img { transform: none; }
  .dests, .a-work img, .a-work.has-dest figure::after { transition: none; }
}

/* ═══════════════════════════════════════════════════════════
   MULTI-PAGE: title-card index + category / about / contact
   ═══════════════════════════════════════════════════════════ */

/* the index is one screen exactly: name, strings, press, and a slim
   footer — the hero takes whatever height is left rather than each
   claiming its own, so nothing spills past the first viewport. */
.page-index { min-height: 100svh; display: flex; flex-direction: column; }
.page-index .a-hero { flex: 1 1 auto; min-height: 0; }

/* the strings are links now, so give them a real hit area */
.string-row { display: block; }

/* ── inner-page hero ────────────────────────────────────── */
.page-hero { padding: 168px 30px 0; }
.page-hero h1 {
  margin: 0; font: 300 clamp(52px, 9vw, 132px)/.92 "Geist", "Instrument Sans", sans-serif;
  letter-spacing: -.045em; text-transform: uppercase;
}
.page-count, .page-intro {
  margin: 0 0 14px; font-family: "Geist Mono", ui-monospace, monospace;
  font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: var(--oxide);
}
.page-intro { margin: 22px 0 0; color: #686258; letter-spacing: .1em; }
.page-index .page-hero { display: none; }

/* ── onward: the strings return as the way out ──────────── */
.onward { padding: 40px 30px 120px; }
.onward-label {
  margin: 0 0 6px; font-family: "Geist Mono", ui-monospace, monospace;
  font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: #8b8578;
  padding-top: 20px; border-top: 1px solid var(--rule);
}
.string-index-compact { position: static; height: auto; display: block; }
.string-index-compact .string-row { position: relative; height: 62px; }
.string-index-compact .string-title { font-size: clamp(15px, 1.1vw, 18px); }
.string-row.is-current { pointer-events: none; }
.string-row.is-current .string-title-text { color: var(--oxide); }
.string-row.is-current .string-line { color: var(--oxide); opacity: .45; }

/* ── contact ────────────────────────────────────────────── */
.contact-grid {
  display: grid; grid-template-columns: minmax(240px, .75fr) 1.25fr;
  gap: 6vw; padding: 60px 30px 130px;
}

.gotcha { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
.form-field { margin-bottom: 22px; }
.form-field label {
  display: block; margin-bottom: 7px;
  font-family: "Geist Mono", ui-monospace, monospace; font-size: 10px;
  letter-spacing: .14em; text-transform: uppercase; color: #686258;
}
.form-field input, .form-field textarea {
  width: 100%; padding: 12px 0; background: transparent; color: var(--ink);
  border: 0; border-bottom: 1px solid var(--rule); border-radius: 0;
  font: 300 17px/1.5 "Geist", "Instrument Sans", sans-serif;
}
.form-field input:focus, .form-field textarea:focus { outline: none; border-bottom-color: var(--oxide); }
.form-field textarea { resize: vertical; }
.btn {
  margin-top: 8px; padding: 14px 30px; background: var(--ink); color: var(--paper);
  border: 1px solid var(--ink); cursor: pointer;
  font-family: "Geist Mono", ui-monospace, monospace; font-size: 10px;
  letter-spacing: .16em; text-transform: uppercase;
  transition: background .25s ease, color .25s ease;
}
.btn:hover { background: transparent; color: var(--ink); }
.btn[disabled] { opacity: .5; cursor: default; }
.form-status {
  margin: 16px 0 0; min-height: 1.3em; color: var(--oxide);
  font-family: "Geist Mono", ui-monospace, monospace; font-size: 11px; letter-spacing: .06em;
}

/* ── footer ─────────────────────────────────────────────── */
.site-footer { padding: 60px 30px 30px; border-top: 1px solid var(--rule); }
.page-index .site-footer { border-top: 0; padding-top: 0; }
.footer-links { display: flex; gap: 22px; flex-wrap: wrap; }
.footer-links a, .footer-meta span {
  font-family: "Geist Mono", ui-monospace, monospace; font-size: 10px;
  letter-spacing: .12em; text-transform: uppercase; color: #686258;
}
.footer-links a { text-decoration: underline; text-decoration-color: transparent; text-underline-offset: .3em; transition: text-decoration-color .25s ease, color .25s ease; }
.footer-links a:hover { color: var(--ink); text-decoration-color: currentColor; }
.footer-meta { display: flex; justify-content: space-between; margin-top: 42px; padding-top: 16px; border-top: 1px solid var(--rule); }

@media (max-width: 900px) {
  .contact-grid { grid-template-columns: 1fr; gap: 40px; }
  .contact-figure { max-width: 62%; }
}
@media (max-width: 640px) {
  .page-hero { padding: 128px 16px 0; }
  .onward, .recognition, .contact-grid, .site-footer { padding-left: 16px; padding-right: 16px; }
  .recognition li { grid-template-columns: 66px 1fr; }
  .rec-for { grid-column: 2; }
  .footer-meta { display: grid; gap: 8px; }
}

/* ═══════════════════════════════════════════════════════════
   ONE NAVIGATION, TWO REGISTERS
   The strings are the navigation — they are the work. The top
   row is utility only (About / Contact / Client access), so it
   is small and right-aligned and never competes. Removing the
   wordmark is what makes that hierarchy legible: with a mark on
   the left, the top row read as a second, equal nav.
   ═══════════════════════════════════════════════════════════ */
.site-header { justify-content: flex-end; }
.a-header nav a[aria-current="page"] { color: var(--oxide); }

/* ── index: one centred composition, no stranded blocks ────
   Everything was absolutely positioned, so on a tall viewport a
   void opened between the strings and the quotes. Now the hero
   is a flex column and the parts sit together as one group. */
.page-index .a-hero {
  display: flex; flex-direction: column; justify-content: center;
  padding: 0 30px; overflow: visible;
}
.page-index .a-composition { position: static; transform: none; height: auto; }
.page-index .a-title-field { position: static; right: auto; left: auto; }
.page-index .string-index {
  position: static; height: auto; display: block;
  margin-top: clamp(14px, 2.4vh, 30px);
}
.page-index .string-index .string-row { position: relative; height: clamp(38px, 5vh, 52px); }

/* ── the quotes: bigger, and part of the composition ─────── */
.page-index .a-evidence {
  position: static; right: auto; bottom: auto; left: auto;
  margin-top: clamp(46px, 8vh, 104px);
  gap: clamp(32px, 6vw, 92px);
  align-items: start;
}
.page-index .a-evidence p {
  font-size: clamp(20px, 2.05vw, 38px);
  line-height: 1.14; letter-spacing: -.03em; margin-bottom: 14px;
  text-wrap: balance;
}
/* let the grid column set the measure — a tight max-width was
   forcing "A world-class composer" to break at its hyphen */
.page-index .a-evidence blockquote { max-width: 46ch; }
.page-index .a-evidence p { hyphens: none; }
.page-index .a-evidence cite { font-size: 10px; line-height: 1.7; }
.page-index .a-evidence cite span { margin-top: 0; }

/* ── footer: one line, no oversized Contact ──────────────── */
.site-footer { padding: 26px 30px 30px; }
.page-index .site-footer { border-top: 1px solid var(--rule); padding-top: 20px; }
.footer-meta {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 20px; flex-wrap: wrap; margin-top: 0; padding-top: 0; border-top: 0;
}
.footer-links { gap: 20px; }

@media (max-width: 900px) {
  .page-index .a-evidence { grid-template-columns: 1fr; gap: 22px; }
  .page-index .a-evidence blockquote { max-width: 100%; }
}
@media (max-width: 640px) {
  .page-index .a-hero { padding: 0 16px; }
  .footer-meta { display: grid; justify-items: start; gap: 12px; }
}

/* ═══════════════════════════════════════════════════════════
   INDEX QUOTES — corners
   Opposite corners, quote TEXT tops aligned (the block was
   bottom-aligned before, so a two-line attribution pushed its
   quote text up and the pair never sat on one line).
   Measure is a share of the row, not ch: Geist's "0" is narrow,
   so 40ch resolved to 421px and held only ~20 characters.
   ═══════════════════════════════════════════════════════════ */
.page-index .a-hero { justify-content: space-between; padding-top: 108px; padding-bottom: 34px; }
.page-index .a-composition { flex: 0 0 auto; }
.page-index .a-evidence {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: clamp(40px, 7vw, 130px);
  margin: 0 0 clamp(26px, 5vh, 66px);
}
.page-index .a-evidence .quote { flex: 0 1 auto; width: auto; max-width: 43%; margin: 0; }
/* only the long quote gives — space-between was squeezing the short
   one until it broke at the hyphen in "world-class" */
.page-index .a-evidence .quote:last-child { flex-shrink: 0; max-width: 46%; }
.page-index .a-evidence p {
  font-size: clamp(19px, 2.05vw, 33px);
  line-height: 1.12; letter-spacing: -.032em; margin: 0 0 13px;
  hyphens: none; text-wrap: balance;
}
.page-index .a-evidence cite { font-size: 10px; line-height: 1.7; color: var(--oxide); }
.page-index .a-evidence cite span { display: block; color: #6c675d; }

@media (max-width: 900px) {
  .page-index .a-evidence { flex-direction: column; gap: 26px; }
  .page-index .a-evidence .quote,
  .page-index .a-evidence .quote:last-child { max-width: 100%; }
}

/* ── mobile nav ───────────────────────────────────────────
   The study hid nav items 1 and 2 under 640px to save room on a
   four-item bar. This nav has three (four on inner pages), so the
   same rule deleted About and Contact entirely and left only
   Client access — About and Contact were unreachable on a phone.
   Let the row wrap instead of dropping destinations.          */
@media (max-width: 640px) {
  .site-header { padding: 18px 16px 0; }
  .site-header nav { flex-wrap: wrap; justify-content: flex-end; gap: 10px 16px; }
  .a-header nav { font-size: 10px; }
  .a-header .client-link { padding: 8px 10px; }
}

/* ── home affordance ──────────────────────────────────────
   "Index" read as jargon. Inner pages carry no name anywhere
   once the wordmark went, so the name itself sits top-left and
   doubles as the link home. The index omits it — its name is
   already the hero and there is nowhere to go back to.        */
.site-header.has-name { justify-content: space-between; }
.a-header .site-name {
  font-family: "Geist Mono", ui-monospace, monospace;
  font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
  color: #6c675d; text-decoration: none; white-space: nowrap;
  transition: color .25s ease;
}
.a-header .site-name:hover { color: var(--ink); }
.a-header .site-name:focus-visible { outline: 2px solid var(--oxide); outline-offset: 4px; }
@media (max-width: 640px) {
  .a-header .site-name { font-size: 10px; letter-spacing: .1em; }
}

/* ═══════════════════════════════════════════════════════════
   CATEGORY RAIL — one string, four labels
   The index gives each category its own line; a page gives them
   one. Same behaviour: the line bends under the pointer and the
   label winds into a ring. Rows are stacked full-width, so the
   row takes no pointer events — only the label does — or the
   topmost row would swallow every hover.
   ═══════════════════════════════════════════════════════════ */
.rail-host { padding: 30px 30px 0; }
.railstring { position: relative; height: 76px; }
.rail-line { position: absolute; inset: 0; color: var(--ink); }
.rail-line svg { width: 100%; height: 100%; overflow: visible; }
.rail-line path {
  fill: none; stroke: currentColor; stroke-width: 1.25;
  vector-effect: non-scaling-stroke;
  transition: none;
}
html.rail-ready .rail-line path {
  transition: stroke-dasharray .5s var(--ease), stroke .25s ease;
}
.railstring:hover .rail-line { color: var(--oxide); }
.rail-item { position: absolute; inset: 0; pointer-events: none; min-height: 0; }
.rail-item .string-title { pointer-events: auto; font-size: clamp(14px, 1.15vw, 17px); }
.rail-item.is-current { pointer-events: none; }
.rail-item.is-current .string-title-text { color: var(--oxide); }

@media (max-width: 900px) { .rail-host { padding: 24px 16px 0; } .railstring { height: 64px; }
  .rail-item .string-title { font-size: 13px; } }
@media (max-width: 640px) {
  .railstring { height: auto; display: flex; flex-wrap: wrap; gap: 10px 20px; padding: 6px 0 0; }
  .rail-line { display: none; }
  .rail-item { position: static; inset: auto; pointer-events: auto; }
  .rail-item .string-title { position: static; transform: none; width: auto; height: auto;
    display: inline-block; font-size: 14px; }
  .rail-item .string-note { display: none; }
}

/* ═══ TOP NAV — same voice as the category names ═══════════
   It was Geist Mono, uppercase, +1.32px tracking while the
   categories were Geist sans, sentence case, negative tracking.
   The growing underscore also belonged to nothing else here.
   ═══════════════════════════════════════════════════════════ */
.a-header nav, .a-header nav a, .a-header .client-link, .a-header .site-name {
  font-family: "Geist", "Instrument Sans", sans-serif;
  text-transform: none; letter-spacing: -.015em;
}
.a-header nav a { font-size: 14px; font-weight: 300; color: rgba(20,19,23,.62); transition: color .25s ease; }
.a-header .site-name {
  font-size: 14px;
  font-weight: 300;
  letter-spacing: -.015em;
  color: rgba(20,19,23,.62);
}
.a-header .client-link { font-size: 14px; font-weight: 300; padding: 8px 13px; }
.a-header nav a:not(.client-link)::after { display: none; }
.a-header nav a:hover { color: var(--ink); }
.a-header nav a[aria-current="page"] { color: var(--oxide); }
@media (max-width: 640px) {
  .a-header nav a, .a-header .client-link, .a-header .site-name { font-size: 13px; }
}

/* ═══ INDEX — centre the composition, gap set explicitly ═══ */
.page-index .a-hero {
  justify-content: center; gap: clamp(52px, 10vh, 124px);
  padding-top: clamp(96px, 12vh, 150px); padding-bottom: clamp(28px, 5vh, 64px);
}
.page-index .a-evidence { margin-bottom: 0; }

/* ═══════════════════════════════════════════════════════════
   WORK CAPTIONS — "plate"
   Title and meta were both 19px, split left/right in a 332px
   column, across three greys — leaving the award note darker
   than the meta. Three columns give the caption 443px; one
   grey, one alignment, two sizes, award folded onto the meta.
   ═══════════════════════════════════════════════════════════ */
.a-work-grid { grid-template-columns: repeat(3, 1fr); gap: 34px 26px; }
.a-work { display: block; }
.work-title { display: block; margin-top: 4px;
  font-size: clamp(19px, 1.7vw, 24px); font-weight: 300; letter-spacing: -.022em; }
.work-meta, .work-note {
  display: inline; font-family: "Geist", "Instrument Sans", sans-serif;
  font-size: 14px; font-weight: 300; letter-spacing: -.01em;
  text-transform: none; text-align: left; color: rgba(20, 19, 23, .62);
}
.work-note { display: block; }
.work-note::before { content: none; }
@media (max-width: 900px) { .a-work-grid { grid-template-columns: repeat(2, 1fr); gap: 32px 18px; }
  .work-title { font-size: 18px; } }
@media (max-width: 560px) { .a-work-grid { grid-template-columns: 1fr; gap: 30px; }
  .work-title { font-size: 19px; } }

/* ═══════════════════════════════════════════════════════════
   ABOUT — the record
   One ruled spine, echoing the home page's four strings: the bio,
   each award, each notice and each photograph is a row on the same
   rule.

   The row is STACKED, not columnar. An earlier pass hung the mono
   key in a 150px left column, which pushed every piece of content
   — bio, headings, entries, photographs — to 210px, while the page
   title and every category page's grid sit at 30px. Measured, that
   put About 180px right of the whole rest of the site, and it could
   not be nudged back: content at 30px would need the key column to
   start at -180px. So the key moved above its entry instead, and
   everything on the page now shares the site's one left edge.
   ═══════════════════════════════════════════════════════════ */
/* Two columns: the record on the left, photographs on the right. The rules
   belong to the rows, which live in column 1, so they stop at the text and
   never run under a picture. Photos are assigned the same grid row as the
   block they belong to (set in build.py). */
.rec { display: grid; grid-template-columns: minmax(0, 58fr) minmax(0, 36fr);
  column-gap: 6%; align-items: start; padding: 0 30px 96px; }
.rec > .rec-row, .rec > .rec-sec { grid-column: 1; }
/* Each photo shares a grid row with the block it belongs to, so centring it
   in that row centres it against that block — the row's height is set by
   whichever of the two is taller. */
.rec > .rec-plate { grid-column: 2; align-self: center; }
.rec-row { padding: 20px 0; border-top: 1px solid var(--rule); }
.rec-key { display: block; margin-bottom: 7px;
  font-family: "Geist Mono", ui-monospace, monospace; font-size: 11px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--oxide);
  font-variant-numeric: tabular-nums; }
.rec-key:empty { display: none; }
.rec-main { display: block; font-size: clamp(16px, 1.5vw, 21px);
  letter-spacing: -.022em; }
/* the project, under its entry, in the same mono label voice */
.rec-note:empty { display: none; }
.rec-note:not(:empty) { display: block; margin-top: 6px;
  font-family: "Geist Mono", ui-monospace, monospace; font-size: 10px;
  letter-spacing: .14em; text-transform: uppercase; color: rgba(20, 19, 23, .42); }

/* the opening statement is a row like any other, only louder */
.rec-open { padding: 12px 0 42px; }
.rec > *:first-child { border-top: 0; }
.rec-open .rec-main p { margin: 0 0 18px; max-width: 62ch;
  font-size: clamp(15px, 1.2vw, 18px); line-height: 1.55; letter-spacing: -.01em; }
.rec-open .rec-main p:last-child { margin: 0; }
/* The lede was capped at 24ch — narrower than the 62ch body beneath it, which
   inverted the hierarchy and broke it into four lines with "Angeles." alone on
   the last. It leads now, and `balance` keeps the last line from orphaning. */
/* Two lines. The measure is in em, not ch: both scale with the font, so
   shrinking the type alone would have held the same characters per line and
   the same three lines. Empirically this face sets ~1.6 characters per em of
   measure, so 36em holds ~58 — enough for a 107-character sentence to break
   once. `balance` then evens the two lines rather than leaving a short tail. */
/* Two lines. The measure is in em, not ch: both scale with the font, so
   shrinking the type alone would hold the same characters per line. This face
   sets ~1.6 characters per em, so 34em holds ~54 — enough for the
   107-character sentence to break exactly once inside the narrower left
   column. `balance` then evens the pair rather than leaving a short tail. */
.rec-open .rec-lede { margin-bottom: 30px !important; max-width: 34em !important;
  font-size: clamp(19px, 1.62vw, 26px) !important; line-height: 1.16 !important;
  letter-spacing: -.028em !important; text-wrap: balance; }

/* A photograph is a row too. One fixed box for all of them, so three
   different source proportions read as one rhythm down the page. */
.rec-plate { padding: 0; }
.rec-plate img { display: block; width: 100%; aspect-ratio: 3 / 2;
  object-fit: cover;
  /* a trace of colour rather than the full frame */
  filter: grayscale(.52) saturate(1.12) contrast(1.02); }

.rec-h { margin: 0 0 6px; font: 300 clamp(24px, 2.6vw, 38px)/1
  "Geist", "Instrument Sans", sans-serif; letter-spacing: -.035em; }
.rec-sec { padding-top: 62px; }
.rec-sec:first-of-type { padding-top: 0; }

@media (max-width: 900px) {
  /* one column: the right-hand rail is too narrow to hold a readable photo,
     so pictures return to the flow between blocks */
  .rec { display: block; padding: 0 30px 70px; }
  .rec > .rec-plate { margin: 34px 0 0; }
  .rec-plate img { width: 62%; }
}
@media (max-width: 760px) {
  .rec { padding: 0 16px 60px; }
  .rec-plate img { width: 100%; }
  .rec-sec { padding-top: 40px; }
}

/* ═══════════════════════════════════════════════════════════
   ABOUT LISTS — Recognition / Press & media / Education
   Years and notes were mono caps, the same generic label voice
   the nav had. Sentence case, one family, plain dividers.
   ═══════════════════════════════════════════════════════════ */
.listing { padding: 0 30px 78px; }
.listing:first-of-type { padding-top: 8px; }
.listing h2 { margin: 0 0 6px;
  font: 300 clamp(24px, 2.6vw, 38px)/1 "Geist", "Instrument Sans", sans-serif; letter-spacing: -.035em; }
.lrows { display: block; }
.lrow { display: grid; grid-template-columns: 92px minmax(0, 1fr) auto; gap: 22px;
  align-items: baseline; padding: 19px 0; color: inherit; text-decoration: none;
  border-top: 1px solid var(--rule); }
.lrow:last-child { border-bottom: 1px solid var(--rule); }
.lr-key { font-size: 13.5px; font-weight: 300; letter-spacing: -.01em; text-transform: none;
  color: rgba(20, 19, 23, .42); font-variant-numeric: tabular-nums; }
.lr-main { font-size: clamp(16px, 1.5vw, 21px); font-weight: 300; letter-spacing: -.022em; }
.lr-note { font-size: 13.5px; font-weight: 300; letter-spacing: -.01em; text-transform: none;
  color: rgba(20, 19, 23, .42); text-align: right; white-space: nowrap; }
a.lrow:hover .lr-main { color: var(--oxide); }
a.lrow:focus-visible { outline: 2px solid var(--oxide); outline-offset: 4px; }
@media (max-width: 640px) {
  .listing { padding: 0 16px 56px; }
  .lrow { grid-template-columns: 62px minmax(0, 1fr); gap: 4px 14px; padding: 15px 0; }
  .lr-note { grid-column: 2; text-align: left; white-space: normal; }
}

/* ═══════════════════════════════════════════════════════════
   PHOTOS — mounted plate
   Source is 900x540 landscape; a 4/5 portrait crop kept only the
   middle 48% of its width and cut Dmitry (right of frame, with
   the score) out entirely. 5/4 keeps 75%, focal point at 94%.
   The soft edge-fade tried before read as an effect; a hairline
   rule with a paper mat is the device the page already uses.
   ═══════════════════════════════════════════════════════════ */
/* Source is 900x540 (1.667). 5/4 showed only 75% of the width, and
   pushing the focal point to 94% bought room on Dmitry's right by
   cutting the violinist off the left edge entirely.
   3/2 shows 90% of the width, and 42% shifts the window left: the
   violinist comes back, and the console dead space past Dmitry's
   right shoulder is what gets trimmed instead. */
.contact-figure img {
  width: 100%; aspect-ratio: 3/2; object-fit: cover;
  object-position: 42% center; filter: grayscale(1);
}


/* ═══════════════════════════════════════════════════════════
   INDEX HERO PHOTO — vertical split
   The composition already sits in a flex column with everything
   position:static (see "index: one centred composition"), so the
   photo is an absolutely positioned panel holding the right edge
   and the hero simply reserves that width in its own padding.
   Only engages when content.json sets hero_photo; without it the
   .has-hero-figure class is never emitted and the all-type hero
   is untouched.
   ═══════════════════════════════════════════════════════════ */
.page-index .a-hero.has-hero-figure { padding-right: calc(36% + 30px); }
.hero-figure {
  position: absolute; top: 0; right: 0; bottom: 0; width: 36%;
  margin: 0; overflow: hidden; background: #151310;
}
/* object-position is resolved BEFORE the transform, in the source
   image's own orientation — so 62% here is "62% into the unmirrored
   photo," then scaleX(-1) flips the already-cropped result. Verified
   against a PIL simulation at this box's real aspect ratio (crop-then-
   mirror, same order) before picking the number: 62% keeps the hand on
   the keyboard fully in frame and reads as balanced, where 50% cut the
   reaching arm at the edge. Mirrored so he faces left, into the name
   and quotes rather than off the right edge of the page. brightness(1.4)
   lifts the shadow-heavy original for legibility at hero size — the
   same file stays untouched (and unmirrored) everywhere else it's used
   on the About page. */
.hero-figure img { width: 100%; height: 100%; object-fit: cover;
  object-position: 62% 30%; filter: grayscale(1) brightness(1.4);
  transform: scaleX(-1); display: block; }
@media (max-width: 900px) {
  /* below this the split would leave the name too narrow to read as a
     masthead, so the photo returns to normal flow under the strings */
  .page-index .a-hero.has-hero-figure { padding-right: 30px; }
  .hero-figure { position: relative; width: auto; height: 42vh;
    margin: 34px -30px 0; }
}
@media (max-width: 640px) {
  /* the ≤900 rule above restores padding-right: 30px, and being later in
     the file it also beat the base ≤640 `padding: 0 16px` on that side
     alone — measured 16px left against 30px right. Restate it here. */
  .page-index .a-hero.has-hero-figure { padding-right: 16px; }
  .hero-figure { margin-left: -16px; margin-right: -16px; height: 36vh; }
}

/* ═══════════════════════════════════════════════════════════
   CONTACT
   The photo runs the full height of the form, but it starts on the
   site's own left edge rather than bleeding past it. It previously
   sat at left 0 against the page title's 30px — the same break the
   About spine had, where one element ignored the gutter every other
   page keeps.
   ═══════════════════════════════════════════════════════════ */
.contact-grid.contact-bleed {
  grid-template-columns: minmax(280px, .9fr) 1.1fr;
  gap: 5vw;
  /* matches .a-works' own padding-top, so the photo starts on the same line
     the category grids do */
  padding: 64px 30px 130px;
  align-items: start;
}
.contact-bleed .contact-figure { margin: 0; }
/* The photo keeps its own proportions — no crop. It was previously forced
   into a tall panel (min-height: 62vh + cover), which rendered a 1.50 source
   at 1.06 and discarded 29% of the width, cutting a hand off the frame. */
.contact-bleed .contact-figure img {
  width: 100%; height: auto; aspect-ratio: auto; min-height: 0;
  /* same trace of colour as the About plates — the base .contact-figure rule
     is a flat grayscale(1), which left the two pages disagreeing */
  filter: grayscale(.52) saturate(1.12) contrast(1.02);
}
.contact-bleed form { padding-top: 0; }
@media (max-width: 860px) {
  .contact-grid.contact-bleed { grid-template-columns: 1fr; gap: 34px;
    padding: 72px 16px 80px; }
  /* the base mobile rule caps .contact-figure at max-width: 62%, which
     measured 222px of a 390px viewport and shrank the photo out of the column */
  .contact-bleed .contact-figure { margin: 0; max-width: none; }
}

/* The utility nav is right-aligned, so with a hero photo holding the
   right edge every link lands on top of it — measured at rgba(20,19,23,.5)
   over a near-black photo, i.e. invisible. Lift it to paper there only. */
.page-index .a-hero.has-hero-figure ~ .site-header a,
body.page-index:has(.has-hero-figure) .site-header nav a { color: rgba(232, 232, 227, .82); }
body.page-index:has(.has-hero-figure) .site-header nav a:hover { color: #fff; }
body.page-index:has(.has-hero-figure) .client-link { border-color: rgba(232, 232, 227, .5); }
@media (max-width: 900px) {
  /* photo drops back into flow below the strings, so the nav is on paper again */
  body.page-index:has(.has-hero-figure) .site-header nav a { color: rgba(20, 19, 23, .62); }
  body.page-index:has(.has-hero-figure) .client-link { border-color: var(--rule); }
}

/* ═══════════════════════════════════════════════════════════
   FULL-POLISH STUDY
   The composition and quote type stay intact. This pass tightens
   the site's supporting register and teaches the string interaction
   on load, using the existing ring language rather than adding UI copy.
   ═══════════════════════════════════════════════════════════ */

/* Supporting text: human rather than technical, and readable at real size. */
.a-evidence cite,
.footer-meta,
.footer-meta span,
.footer-meta a {
  font-family: "Geist", "Instrument Sans", Arial, sans-serif;
  font-weight: 400;
  letter-spacing: -.005em;
  text-transform: none;
}
.page-index .a-evidence cite {
  font-size: 13.5px;
  line-height: 1.45;
}
.page-index .a-evidence cite span {
  margin-top: 2px;
  font-size: inherit;
  color: rgba(20, 19, 23, .62);
}
.footer-meta,
.footer-meta span,
.footer-meta a {
  font-size: 12.5px;
  line-height: 1.4;
  color: rgba(20, 19, 23, .66);
}

/* Utility navigation remains a separate register, but no longer whispers. */
.a-header nav a,
.a-header .client-link,
.a-header .site-name {
  font-size: 15px;
}
.a-header nav a:focus-visible,
.a-header .site-name:focus-visible,
.footer-meta a:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: 4px;
}

/* The secondary register is one system across every page and breakpoint.
   The circular notes keep Geist Mono because its fixed glyph widths are
   functional there; dates, descriptors, form labels, and status text do not. */
.rec-key,
.rec-note:not(:empty),
.page-count,
.page-intro,
.onward-label,
.form-field label,
.form-status,
.btn {
  font-family: "Geist", "Instrument Sans", Arial, sans-serif;
  font-weight: 400;
  letter-spacing: -.005em;
  text-transform: none;
}
.rec-key,
.rec-note:not(:empty) {
  font-size: 13.5px;
  line-height: 1.35;
}
.rec-key { color: var(--oxide); }
.rec-note:not(:empty) { color: rgba(20, 19, 23, .62); }
.page-count,
.page-intro,
.onward-label,
.form-field label,
.form-status { font-size: 13.5px; }
.btn { font-size: 14px; }

/* Inner pages leave 64px below the category rail before content begins.
   About previously began immediately, so a 90px note ring overlapped its photo. */
.page-about .rail-host + .rec { padding-top: 64px; }

/* Press rows are now genuine destinations, using the same quiet link behavior
   as project captions rather than introducing arrows or button chrome. */
.page-about a.rec-row {
  display: block;
  color: inherit;
  text-decoration: none;
}
.page-about a.rec-row:hover .rec-main { color: var(--oxide); }
.page-about a.rec-row:focus-visible {
  outline: 2px solid var(--oxide);
  outline-offset: 4px;
}

/* Four posters restore the index-like cadence at desktop sizes. Destination
   remains the color code: linked works are grey until interaction, while
   works without a destination stay fully colored. */
.a-work-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 30px 18px; }
.a-work.has-dest img { filter: grayscale(1) contrast(.96) brightness(.92); }
.js .a-work:not(.has-dest) img { filter: none; }
@media (max-width: 900px) {
  .a-work-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px 18px; }
}
@media (max-width: 560px) {
  .a-work-grid { grid-template-columns: 1fr; gap: 30px; }
}

/* Mask the line until final font metrics are measured without adding padding to
   the measured label itself. The mask matches the script's normal clearance. */
html.js:not(.strings-ready) .page-index .string-title::before,
html.js:not(.rail-ready) .rail-item .string-title::before {
  position: absolute;
  z-index: -1;
  top: 0;
  bottom: 0;
  background: var(--paper);
  content: "";
}
html.js:not(.strings-ready) .page-index .string-title::before {
  right: -26px;
  left: -26px;
}
html.js:not(.rail-ready) .rail-item .string-title::before {
  right: -28px;
  left: -28px;
}

/* The approved opening cue uses the existing note state in sequence. */
.string-row.is-hinting .string-title {
  color: var(--oxide);
}
.string-row.is-hinting .string-title-text {
  opacity: 0;
  transform: none;
  transition: opacity .1s linear;
}
.string-row.is-hinting .string-note {
  opacity: 1;
  transform: scale(1) rotate(0);
}
.string-row.is-hinting .string-line { color: var(--oxide); }

@media (max-width: 640px) {
  .a-header nav a,
  .a-header .client-link,
  .a-header .site-name { font-size: 13.5px; }
  .page-index .a-evidence cite { font-size: 12.5px; }
  .footer-meta,
  .footer-meta span,
  .footer-meta a { font-size: 12px; }
  .rec-key,
  .rec-note:not(:empty),
  .page-count,
  .page-intro,
  .onward-label,
  .form-field label,
  .form-status { font-size: 12.5px; }
  .page-about .rail-host + .rec { padding-top: 32px; }

  /* Preserve the single-line page title without allowing it to escape the
     narrowest supported phone viewport. */
  .page-arrangements .page-hero h1 {
    font-size: clamp(38px, 12vw, 52px);
  }

  /* Touch targets meet the 44px mobile minimum while the visible typography
     and spacing system remain unchanged. */
  .page-index .string-index .string-row,
  .rail-item,
  .rail-item .string-title,
  .dest,
  .footer-links a {
    min-height: 44px;
  }
  .rail-item,
  .dest,
  .footer-links a {
    min-width: 44px;
  }
  .rail-item,
  .rail-item .string-title,
  .dest,
  .footer-links a {
    display: inline-flex;
    align-items: center;
  }
}

/* Mobile homepage: retain the desktop composition and components, but give
   the narrow viewport two genuine full-width string tracks. Desktop remains
   governed by the original four-row layout above. */
@media (max-width: 640px) {
  body.page-index .site-header {
    justify-content: stretch;
    padding: 18px 20px 0;
  }

  body.page-index .site-header nav {
    display: grid;
    grid-template-columns: auto auto minmax(max-content, 1fr);
    width: 100%;
    gap: 12px;
    align-items: center;
    justify-content: initial;
  }

  body.page-index .site-header nav a,
  body.page-index .site-header nav a:not(.client-link) {
    min-width: 0;
    min-height: 44px;
    justify-content: flex-start;
  }

  body.page-index .site-header .client-link {
    justify-self: end;
    padding: 8px 11px;
  }

  .page-index .a-hero,
  .page-index .a-hero.has-hero-figure {
    justify-content: flex-start;
    gap: 0;
    padding: 112px 20px 58px;
  }

  .page-index .a-composition {
    order: 1;
    width: 100%;
  }

  .page-index .a-title-field h1 {
    font-size: clamp(54px, 15.8vw, 64px);
    line-height: .82;
  }

  .page-index .string-index {
    position: relative;
    top: auto;
    right: auto;
    left: auto;
    display: block;
    height: 112px;
    margin-top: 26px;
  }

  .page-index .string-index .string-row {
    --ring-size: 62px;
    position: absolute;
    right: 0;
    left: 0;
    height: 54px;
    min-height: 54px;
    pointer-events: none;
  }

  /* Keep the production DOM order for desktop. Only the mobile positions pair
     Screen with Records, and Stage with Arrangements. */
  .page-index .string-index .string-row:nth-child(1) {
    top: 0;
    --label-x: 18%;
    --label-w: 92px;
  }

  .page-index .string-index .string-row:nth-child(2) {
    top: 58px;
    --label-x: 28%;
    --label-w: 88px;
  }

  .page-index .string-index .string-row:nth-child(3) {
    top: 0;
    --label-x: 74%;
    --label-w: 96px;
  }

  .page-index .string-index .string-row:nth-child(4) {
    top: 58px;
    --label-x: 66%;
    --label-w: 128px;
  }

  .page-index .string-index .string-title {
    font-size: 16px;
    pointer-events: auto;
  }

  .page-index .string-index .string-line {
    height: 52px;
  }

  .page-index .string-index .string-row:nth-child(1) .string-line,
  .page-index .string-index .string-row:nth-child(2) .string-line {
    width: 100%;
  }

  .page-index .string-index .string-row:nth-child(3) .string-line,
  .page-index .string-index .string-row:nth-child(4) .string-line {
    display: none;
  }

  .page-index .string-index .string-title::before {
    position: absolute;
    z-index: -1;
    top: 0;
    right: -10px;
    bottom: 0;
    left: -10px;
    background: var(--paper);
    content: "";
  }

  .page-index .string-index:has(.string-row:nth-child(3).is-hinting)
    .string-row:nth-child(1) .string-line,
  .page-index .string-index:has(.string-row:nth-child(4).is-hinting)
    .string-row:nth-child(2) .string-line {
    color: var(--oxide);
  }

  .page-index .hero-figure {
    order: 2;
    position: relative;
    width: auto;
    height: auto;
    aspect-ratio: 6 / 5;
    margin: 36px -20px 0;
  }

  .page-index .hero-figure img {
    width: 100%;
    height: 100%;
    object-position: 50% 8%;
  }

  .page-index .a-evidence {
    order: 3;
    display: flex;
    flex-direction: column;
    gap: 44px;
    margin: 0;
    padding-top: 42px;
  }

  .page-index .a-evidence .quote,
  .page-index .a-evidence .quote:last-child {
    width: 100%;
    max-width: 100%;
  }

  .page-index .a-evidence .quote:first-child { order: 2; }
  .page-index .a-evidence .quote:last-child { order: 1; }

  .page-index .a-evidence p {
    font-size: 19px;
    line-height: 1.18;
  }

  .page-index .site-footer { padding-top: 22px; }

  /* Touch has no hover reveal. A single named destination therefore uses the
     entire poster as its hit area. Multi-destination covers keep their named
     choices visible over a restrained scrim. */
  .a-work.has-dest .dests {
    position: absolute;
    inset: 0;
    margin: 0;
    padding: 14px;
    align-items: center;
    justify-content: center;
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }

  .a-work.has-single-dest .dest:only-child {
    position: absolute;
    inset: 0;
    display: block;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
    color: transparent;
    font-size: 0;
    text-decoration: none;
    text-shadow: none;
  }

  .a-work.has-dest:not(.has-single-dest) figure::after {
    display: block;
    opacity: .42;
  }

  .a-work.has-dest:not(.has-single-dest) .dest {
    color: var(--paper);
    font-size: 17px;
    text-shadow: 0 1px 20px rgba(10, 11, 13, .6);
  }
}

/* iPad landscape keeps the desktop split, but the live photo starts at 64% of
   the viewport. Cap the masthead to the reserved text column so SELIPANOV does
   not run under the image edge. Large desktop and phone layouts stay on their
   existing rules. */
@media (min-width: 901px) and (max-width: 1366px) {
  .page-index .a-hero.has-hero-figure .a-title-field h1 {
    font-size: clamp(104px, 10.4vw, 142px);
  }
}
