/* home.css — what the merged product carries over from the original app,
 * ported under catalog-shelf.css's tokens. Loaded AFTER catalog-shelf.css and
 * never with styles.css.
 *
 * Step 1 (this file today): the top bar and the hero. Step 2 adds the record
 * panes inside the viewer; step 3 adds Manage.
 *
 * The hero keeps its own palette in both themes. It is a photographed door —
 * the portrait's backdrop is tuned into that beige and bleeds into the page —
 * so the theme toggle governs the catalogue below it, not the photo.
 */

/* ================= THE TOKENS — the design system, in one place =================
 * Every colour, type style, space, corner and control size the app draws with
 * (docs/03_DESIGN/DESIGN_SYSTEM.md is the written table). A rule points at a
 * token; it does not carry its own value.
 *
 * catalog-shelf.css is the approved /catalog-shelf.html specimen and is never
 * edited, so its tokens are re-declared here with the app's values; this
 * sheet loads after it and wins. Light first, dark second: the same
 * specificity, so the order is what makes dark win in dark.
 *
 * Aliases (var() of another token) resolve on the element that declares
 * them. Anything that re-defines --ink or --page on a subtree (.dialog-content
 * does) must declare the aliases that hang off them again there.
 */
:root{
  /* ---- colour: the ground, the type, the lines ----
     The ground, the ink, the second voice, the accent and warn are the Music
     Network's (network-tokens.css, loaded first; one black, one white, one
     yellow across the three apps). These names stay, pointing at them. */
  --page:var(--light-bg);
  --ink:var(--light-ink);
  --muted:var(--light-muted);
  --line:var(--light-line);
  --object-ground:#eff0f3;
  --header-bg:color-mix(in srgb,var(--light-bg) 88%,transparent);
  --leaf-1:#f0f2f5;
  --leaf-2:#e5e8ed;
  --leaf-3:#d9dde4;
  /* ---- colour: the one accent, and the three states ---- */
  --accent:var(--light-accent);     /* the network's one yellow, deepened for white; for state, never a button */
  --on-accent:var(--page);          /* text drawn on the accent, as the Manage count dot has always done */
  --ok:#1d7a3a;
  --warn:var(--light-warn);
  --no:#b3261e;
  --focus-ring:var(--accent);
  /* a person's face before there is a picture */
  --face-bg:color-mix(in srgb,var(--ink) 12%,transparent);
  --face-ink:var(--ink);
  /* the type on the record screen's veil: cool white in both themes, never cream */
  --on-veil:var(--white);

  /* ---- type: the two cuts, and six styles ----
     A style is adopted with two declarations:
       font:var(--t-title);letter-spacing:var(--tr-title)
     The shorthand resets line-height and font-variant, so anything like
     font-variant-numeric goes AFTER it. Three weights, each its own file:
     Inter 400 (the text cut), Inter Display 600 and 800 (the display cut). */
  --serif:var(--font-display);      /* the display cut, for headings and names */
  --sans:var(--font-sans);          /* the text cut, for anything read as a sentence */
  --display:var(--font-display);
  --t-display:800 48px/1 var(--serif);
  --t-title:800 24px/1.12 var(--serif);
  --t-name:800 13px/1.2 var(--serif);
  --t-body:400 15px/1.5 var(--sans);
  --t-small:600 12px/1.3 var(--serif);
  --t-label:600 11px/1.3 var(--serif);
  --tr-display:-.03em;
  --tr-title:-.015em;
  --tr-name:-.01em;
  --tr-body:0;
  --tr-small:0;
  --tr-label:.1em;

  /* ---- space, corners, sizes ----
     --space-1..7 and --radius-pill come from network-tokens.css. */
  --radius-cover:var(--cover-radius);   /* the old name stays: catalog-shelf-core.js reads --cover-radius */
  --radius-panel:14px;
  --control:32px;                   /* a header-sized button; its tap area stays 44px on touch */
  --face:28px;
}
[data-theme="dark"]{
  --page:var(--dark-bg);
  --ink:var(--dark-ink);
  --muted:var(--dark-muted);
  --line:var(--dark-line-strong);
  --object-ground:#141210;
  --header-bg:color-mix(in srgb,var(--dark-bg) 86%,transparent);
  --leaf-1:#1c1916;
  --leaf-2:#242019;
  --leaf-3:#2c2721;
  --accent:var(--dark-accent);      /* the network's one yellow on black (2026-10-18; it was blue) */
  --ok:#6fcf8a;
  --warn:var(--dark-warn);          /* the network's amber */
  --no:#ef7d72;                     /* a red lifted for dark grounds: 7.4:1 on the page, 5.2:1 or better on the record screen's veil */
  /* The specimen's last cream, cooled: the lines and the empty-cover type
     follow the ink. */
  --hairline:rgba(242,243,245,.12);
  --panel-line:rgba(242,243,245,.14);
  --placeholder-ink:var(--ink);
  --placeholder-dim:var(--muted);
}
@media (max-width:760px){
  :root{--t-display:800 30px/1 var(--serif);--t-title:800 21px/1.12 var(--serif);--control:30px}
}
@media (max-width:350px){
  :root{--control:28px}
}

:root{
  /* The profile's own palette. White and black now — the cream is gone, and
     the owner will set his own colours here once the scene is customisable.
     The portrait is still an opaque JPEG whose studio backdrop is baked in at
     roughly #E3DCD6, so a bloom in that colour sits behind him and carries the
     photograph into the ground instead of leaving a hard oval on white. When a
     cut-out portrait arrives the bloom can go. */
  /* The profile's ink and the catalogue's are the same colour, so crossing
     from one to the other changes nothing about the type. Aliases now: the
     profile's grey is the page's muted (6.45:1 on light, where its own
     .55 black was 3.98:1). */
  --hero-ink:var(--ink);
  --hero-dim:var(--muted);
  /* ONE GROUND. The profile's paper and the catalogue's page were two
     different whites — #ffffff and #f6f7f8 — so scrolling the dive stepped
     from one to the other: the owner, "when I scroll all the way down it
     changed from white to cream." They are the same colour now, and the only
     thing that changes on the way down is the record's own scene arriving. */
  --hero-paper:var(--page);
  --hero-bloom:rgba(234,227,221,.92);
}

/* ---------- the top bar: part of the hero now, not fixed ----------
   It sits on the light hero and scrolls away with it; the shelf header takes
   over below. Colours are the hero's, so it reads the same in both themes. */
/* The hero's own bar is gone — there is one header now. */
.who-col{position:relative}
.header-top>.nb-room{flex:none;margin-right:14px}
@media(max-width:560px){.header-top>.nb-room{letter-spacing:.14em;font-size:0;gap:0}.header-top>.nb-room .nb-mark{margin-right:0}}
.who-btn{display:inline-flex;align-items:center;gap:7px;padding:0;border:0;background:none;color:var(--hero-dim);font:inherit;letter-spacing:.14em;text-transform:uppercase;cursor:pointer}
.header-row .who-btn{line-height:1.25;white-space:nowrap;max-width:100%;overflow:hidden;text-overflow:ellipsis}
.who-btn .rl{font-style:normal}
.who-btn:hover{color:var(--hero-ink)}
.who-btn svg{width:9px;height:9px;fill:none;stroke:currentColor;stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round;transition:transform .22s ease}
.who-btn.open svg{transform:rotate(180deg)}
/* The menu is platform, not hero: it takes the page's tokens so it follows the theme. */
/* A hidden menu still contributes to the page's scroll width, and at 375px
   this one hung 23px past the right edge and gave the whole page a sideways
   scroll. Clamp it, and anchor it to the button's right on phones. */
/* Flat: a hairline and the page's ground, no shadow — covers are the only
   things with shadows. Each profile is a pill row: the name in the name
   style, the role beside it in small, in plain case. */
.who-menu{position:absolute;left:0;top:calc(100% + 10px);min-width:min(230px,calc(100vw - 24px));max-width:calc(100vw - 24px);max-height:320px;overflow:auto;padding:var(--space-1);border:1px solid var(--line);border-radius:var(--radius-panel);background:var(--page);color:var(--ink);opacity:0;visibility:hidden;transform:translateY(-6px);transition:opacity .2s ease,transform .2s ease;text-transform:none;letter-spacing:0}
.who-menu.on{opacity:1;visibility:visible;transform:translateY(0)}
.who-menu button{display:flex;align-items:center;gap:var(--space-2);width:100%;min-height:40px;padding:0 var(--space-3);border:0;border-radius:var(--radius-pill);background:none;text-align:left;color:var(--muted);font:inherit;cursor:pointer}
.who-menu button:hover{background:var(--object-ground);color:var(--ink)}
.who-menu button.on{background:var(--object-ground);color:var(--ink)}
.who-menu .nm{flex:1;min-width:0;font:var(--t-name);letter-spacing:var(--tr-name);color:var(--ink)}
.who-menu .rl{font:var(--t-small);letter-spacing:var(--tr-small);color:var(--muted)}
.who-menu button.on .rl{color:var(--ink)}

/* ---------- the hero, verbatim from the original ---------- */
/* ---------- the dive's runway (hero-dive.js) ----------
   The hero sticks to the top of this dock while the covers come in out of the
   air, and lets go once they are home. --dive-runway is the ONLY tempo knob:
   it is how far you swipe between seeing the face and owning the catalogue.
   Sticky keeps the hero in flow, so nothing below it moves. */
/* HOW LONG THE DIVE LASTS, in scroll. 62% of a screen is a deliberate swipe
   on a desktop trackpad. On a phone the same fraction is a much shorter
   distance and the whole flight of the catalogue has to happen inside a
   flick — the owner: "the animation feels rushed... that shit is all chopping
   and weird". A phone gets most of a screen, so one unhurried swipe carries
   the profile out and the records home. */
:root{--dive-runway:62svh}
html.dev-phone{--dive-runway:96svh}
.hero-dock{position:relative;height:calc(100svh + var(--dive-runway))}

/* LOCK TO THE SCENE, by leaving nowhere to drift to.

   When the dive finished there were still ~325px of scroll underneath it, so
   the page kept sliding after the records had landed — and a sideways swipe to
   browse then fought vertical momentum that had not stopped. That is the
   "stuck in the transition" the owner reported.

   scroll-snap was tried first and is the wrong tool: it hijacks the very scroll
   the dive is scrubbing, and a drift past the landing threw the page hundreds
   of pixels back mid-gesture. The fix is arithmetic instead. The catalogue's
   first screen is sized to the viewport MINUS the fixed header, so the document
   ends exactly where the dive does: maxScroll == catalogTop, and there is no
   leftover to carry momentum into.

   This also restores the repo's own "the catalogue is exactly one screen". */
.shelf-view,.grid-view{min-height:calc(100svh - var(--header-h))}
/* View all starts just under the header (the owner, 2026-10-02: "in all
   views make sure the balance is there"). The catalogue's top is already the
   header's foot (catalogTop in catalog-shelf-boot.js), so the specimen's
   (--header-h + 34px) counted the header twice: ~108px of nothing above the
   count line. */
.grid-view{padding-top:34px}
@media (max-width:760px){.grid-view{padding-top:22px}}
/* With the songs under a cover sized to fit (balanceBand in
   catalog-shelf-core.js), the year/kind line is set as the design system's
   label, 11px, so it stays on one line over the narrower cover. */
.shelf-view.is-balanced .record-kicker{font-size:11px;letter-spacing:.1em}
/* No motion, no runway: the covers are simply home, so a pinned hero with
   nothing happening would just be a long scroll through a still picture. */
@media (prefers-reduced-motion:reduce){:root{--dive-runway:0px}}
/* Black in dark, and the profile's ink flips with it — the ground is one field
   across the whole page now, so the profile cannot keep a light-only palette. */
:root[data-theme="dark"]{--hero-paper:var(--page);--hero-bloom:rgba(46,42,52,.92)}
/* The portrait and the ground recede as the covers take over — opacity and a
   touch of scale only, both compositor-cheap. No blur: this is a 620px-wide
   photograph on a sticky layer and blurring it per frame drops frames.
   Deliberately GENTLE and late: the scene's own blocks below carry the exit,
   and a strong blanket fade on top of them would just make everything vanish
   at once, which is the flat thing this replaced. */
.hero{opacity:1;transform:scale(calc(1 - var(--hero-fade,0) * .045))}   /* the hero's ground stays until the records come; the figure fades on its own (below) */

/* The scene blocks compose the dive's drift with whatever transform they
   already needed. --dive-shift is identity until hero-dive.js says otherwise,
   so nothing moves before the swipe and nothing breaks without the script. */
[data-dive-depth]{--dive-shift:translate3d(0,0,0) scale(1);transform:var(--dive-shift)}
/* Only while it is actually moving. A permanent will-change on five blocks plus
   twenty-nine covers is five-and-twenty-nine compositor layers held for a page
   that spends almost all its time at rest. */
html.is-diving [data-dive-depth]{will-change:transform,opacity}
.hero-kicker[data-dive-depth],.dive[data-dive-depth]{transform:translateX(-50%) var(--dive-shift)}

/* ---------- THE WORLD: one ground for the whole page ----------
   Fixed to the viewport and behind everything, so the profile and the
   catalogue stand on the same floor and there is never an edge between two
   grounds. `body` carries the catalogue's paper; this sits on top of it and
   fades away as the records arrive, which is why the change reads as the world
   receding rather than as the colour swapping.

   Deliberately NOT in catalog-shelf.css: that is the approved specimen's sheet
   and /catalog-shelf.html must keep the page it was approved with.

   The colours are the photograph's. The portrait is a JPEG with no alpha and
   its studio backdrop is baked in, sampling #D8D1CB-#EAE3DD, which is why
   --hero-paper was tuned to #e6e0da in the first place: the two match, so the
   join is invisible. Give the world a different hue and a pale box appears
   around him. A coloured world needs a cut-out portrait first. */
/* body must NOT paint, or the world is invisible. catalog-shelf.css sets a
   background on BOTH html and body. A z-index:-1 child of body paints at step 2
   of the painting order — after the canvas, but BEFORE the block backgrounds of
   in-flow descendants at step 3. So body's own background covered the world
   completely, and the page went on looking exactly as it had: the profile stood
   on the catalogue's cool paper, and because the portrait is an opaque JPEG with
   a feathered mask rather than a cut-out, its baked beige backdrop showed as a
   pale oval around his head. The first version of this shipped that way; it was
   caught by reading the painting order, and confirmed by toggling this one
   declaration in a browser.

   html keeps --page, so the canvas is still the catalogue's paper and the world
   sits on top of it. */
body{background:transparent}
/* The loading veil (home.html): the page's own ground, a ring, a line. Gone
   the moment the shelf is drawn. */
.boot-veil{position:fixed;inset:0;z-index:80;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-4);
  background:var(--page);color:var(--muted);font:var(--t-small);letter-spacing:var(--tr-small);transition:opacity .38s var(--ease)}
.boot-veil.is-gone{opacity:0;pointer-events:none}
.boot-ring{width:26px;height:26px;border-radius:50%;border:2px solid var(--line);border-top-color:var(--ink);animation:bootSpin .9s linear infinite}
@keyframes bootSpin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.boot-ring{animation:none;border-top-color:var(--line)}}

.world{position:fixed;inset:0;z-index:-1;pointer-events:none;
  background:var(--hero-paper);
  opacity:calc(1 - var(--world-fade,0))}
/* Only while it is actually moving, like the covers and the scene blocks. */
html.is-diving .world{will-change:opacity}
/* The aura behind the portrait, and the soft field around it. Fixed with the
   world: the hero is pinned for the whole dive, so it stays registered with
   the face, and by the time the hero unpins the world has gone. */
/* Nothing but the ground. The bloom that carries the photograph into it moved
   onto .figure, because a gradient on a fixed full-viewport layer cannot track
   a portrait whose size is 86vw on a phone and 44vw on a desktop. */
.world-aura{display:none}
.world-grid{display:none;position:absolute;inset:-8%;width:116%;height:116%;transform:scale(1.08);
  background:linear-gradient(90deg,transparent 49.9%,rgba(23,19,28,.05) 50%,transparent 50.1%),linear-gradient(0deg,transparent 49.9%,rgba(23,19,28,.035) 50%,transparent 50.1%),radial-gradient(circle at 21% 82%,rgba(168,132,196,.18),transparent 34%)}
@media (prefers-reduced-motion:reduce){.world{will-change:auto}}
/* No background of its own any more — the world behind it is the ground. A
   hero that paints its own rectangle IS the second page. */
/* NO FLOOR. `min-height:620px` was the single worst line in this file on a
   phone held sideways: at 390px tall it made the hero 1.6x the screen, so the
   name, socials, place, bio, counter and Highlights all sat below the fold in
   a box with overflow:hidden, unreachable.

   It also broke the dive twice over. The dock is 100svh + --dive-runway, so
   the sticky travel is dock - hero: with a 620px floor that collapsed to 12px
   at 844x390 (the hero let go almost immediately and slid the whole profile
   up through the transparent header — which is the owner's screenshot), and
   went NEGATIVE at 667x375, where hero-dive.js's own guard switches the dive
   off entirely. With the floor gone the hero is exactly 100svh and the travel
   is exactly --dive-runway, at every height. */
.hero{--word-x:0px;--word-y:0px;position:sticky;top:0;height:100svh;overflow:hidden;isolation:isolate;user-select:none;color:var(--hero-ink);background:transparent;perspective:1700px}
.hero-scene{position:absolute;inset:0;z-index:2;perspective:1500px;perspective-origin:50% 46%;transform-style:preserve-3d}
/* THE SCENE, behind everything in the hero and in front of nothing. It fills
   the whole top of the page — "fill up that whole top area with that picture"
   — and fades out on the world's own clock, so diving into the catalogue
   leaves the artist's universe behind at the same moment his ground does.
   With no scene set it is simply not painted. */
.hero-backdrop{position:absolute;inset:0;z-index:0;pointer-events:none;
  background:var(--scene,none) center/cover no-repeat;
  opacity:calc(1 - var(--world-fade,0))}
.hero-backdrop::after{content:"";position:absolute;inset:0;background:var(--scene-veil)}
/* A veil, or the name and the bio are text on a photograph. Light enough that
   the picture is still the thing you see. */
:root{--scene-veil:linear-gradient(to bottom,color-mix(in srgb,var(--page) 34%,transparent),color-mix(in srgb,var(--page) 74%,transparent))}
:root[data-theme="dark"]{--scene-veil:linear-gradient(to bottom,color-mix(in srgb,var(--page) 30%,transparent),color-mix(in srgb,var(--page) 72%,transparent))}
html:not(.has-scene) .hero-backdrop{display:none}
.hero-word{position:absolute;left:50%;top:46%;z-index:1;transform:translate3d(calc(-50% + var(--word-x)),calc(-50% + var(--word-y)),-110px);font-family:var(--serif);font-size:clamp(120px,19.1vw,364px);font-weight:900;line-height:.75;letter-spacing:-.105em;white-space:nowrap;color:var(--hero-ink);pointer-events:none;will-change:transform}
.portrait-rock{position:absolute;inset:0;z-index:3;transform-style:preserve-3d;will-change:transform;animation:portraitRock 8.8s cubic-bezier(.45,.05,.55,.95) infinite}
.portrait-rig{position:absolute;inset:0;transform-style:preserve-3d;will-change:transform;transition:transform .18s linear}
.figure{position:absolute;inset:0;z-index:2;overflow:visible;transform:translateZ(54px);pointer-events:none;opacity:calc(1 - var(--hero-fade,0));-webkit-mask-image:linear-gradient(#000 72%,transparent 100%);mask-image:linear-gradient(#000 72%,transparent 100%)}   /* the portrait fades all the way, no square (the owner, 2026-10-18) */
.figure[hidden]{display:none}
/* NO CIRCLE, NO BLOOM. Both were workarounds for one asset: the portrait was
   an opaque JPEG with a studio backdrop baked in, so it had to be hidden
   inside a shape that was meant to be there, and bloomed into the page so its
   edge did not read as a badly cut photograph. The portrait is a real cut-out
   now — lifted with Vision's foreground mask, alpha and all — so he simply
   stands on whatever is behind him. The shadow is a drop-shadow rather than a
   box-shadow, because a box-shadow follows the element's rectangle and would
   draw a hard square behind a transparent PNG. */
.figure .portrait-main{position:absolute;left:50%;top:50%;z-index:2;
  width:min(68svh,82vw,500px);aspect-ratio:1;height:auto;object-fit:contain;
  translate:-50% -50%;
  filter:drop-shadow(0 26px 44px rgba(23,19,28,.38));
  transition:transform .18s linear;will-change:transform}
/* THE PICTURE: a small circle right above the name, its left edge on the
   name's (the owner's mockup, 2026-10-02: about 22% of a phone's width, a
   small gap over the name). The count beside the name moves down by the
   same amount, so it stays level with the name, not the circle. */
.about-row{--avatar:clamp(72px,22vw,96px);--avatar-gap:12px}
.hero-avatar{width:var(--avatar);aspect-ratio:1;border-radius:50%;margin:0 0 var(--avatar-gap);
  background:#17131c center/cover no-repeat;display:grid;place-items:center;
  font-family:var(--serif);font-weight:900;font-size:calc(var(--avatar) * .36);color:#efedf1;
  box-shadow:0 10px 24px -12px rgba(23,19,28,.45)}
.hero-avatar[hidden]{display:none}
.about-row:has(.hero-avatar:not([hidden])) .releases{margin-top:calc(var(--avatar) + var(--avatar-gap))}
/* One column, in the sketched order: portrait, then name / roles / socials /
   where / bio, then the count, then Highlights. Absolute placement is gone —
   it is what put the bio across his face on a phone and made the block fight
   the portrait for space at every width.
   ONE LEFT EDGE: the page's own gutter (--pad-l / --pad-r, catalog-shelf.css),
   the same one the header's name stands on, so the profile's name starts on
   the line the header's does. */
.hero-stack{position:absolute;inset:0;display:flex;flex-direction:column;
  padding:calc(var(--header-h) + 8px) var(--pad-r) var(--space-5) var(--pad-l);gap:var(--space-4)}
.hero-scene{position:relative;flex:1 1 auto;min-height:0}
/* The count sits beside the about block, not under it, and level with the
   name: both are the title style, top to top. */
.about-row{flex:0 0 auto;display:flex;align-items:flex-start;justify-content:space-between;gap:clamp(18px,4vw,48px);
  /* the row the links' line runs (100cqw, below) */
  container-type:inline-size}
.about{flex:1 1 auto;min-width:0;max-width:46ch}
/* The profile's words are the design system's six styles (the tokens at the
   top of this file): his name and the count in title, the roles, the place
   and the confirmed line in small, "Releases" in label, the bio in body. */
.ident-name{margin:0;font:var(--t-title);letter-spacing:var(--tr-title)}
.ident-role{margin:var(--space-1) 0 0;font:var(--t-small);letter-spacing:var(--tr-small);color:var(--hero-dim)}
/* Socials sit directly under the role: name, what he does, where to find him.
   THE LINKS' LINE runs the whole row, not the about block's measure, so its
   far end — the share button — is under the count at every width (the
   owner, 2026-10-02: "all the way to the right"); the links keep the
   measure. Top-aligned, so links that wrap leave the button on their first
   line. A browser without container units ends it at the about block. */
.socials-line{display:flex;align-items:flex-start;gap:var(--space-2);margin:var(--space-3) 0 0;width:100%;width:100cqw}
.about .socials{flex:0 1 auto;min-width:0;max-width:46ch;justify-content:flex-start;margin:0}
.socials-end{flex:0 0 auto;margin-left:auto;display:flex;align-items:center;gap:var(--space-3)}
/* SHARE: one glyph, the header's round frosted button (QUIET PILL, FLOATING
   and ROUND, at the end of this file). */
.share-btn{display:grid;place-items:center;padding:0;cursor:pointer;transition:color .2s var(--ease)}
.share-btn svg{display:block}
.share-btn:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}
.hero-place{margin:var(--space-3) 0 0;font:var(--t-small);letter-spacing:var(--tr-small);color:var(--hero-dim)}
.hero-place[hidden]{display:none}
.releases{flex:0 0 auto;display:flex;flex-direction:column;align-items:flex-end;text-align:right}
.releases .num{font:var(--t-title);font-family:var(--font-num);letter-spacing:var(--tr-title)}   /* the count in Doto, the network's number face */
.releases .num-label{margin:var(--space-1) 0 0;font:var(--t-label);letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--hero-dim)}
/* The confirmed line: beside the share button, under the count. */
.hero-confirmed{font:var(--t-small);letter-spacing:var(--tr-small);color:var(--hero-dim);white-space:nowrap}

/* THE BIO, in the text cut at regular weight, in the ink: it is read, so it
   is not dimmed. */
#heroBio{margin:var(--space-2) 0 0;font:var(--t-body);letter-spacing:var(--tr-body);color:var(--hero-ink)}
/* The social links are the header's quiet pills (QUIET PILL and FLOATING, at
   the end of this file): the page's muted on a frosted ground in both themes. */
.socials{display:flex;flex-wrap:wrap;gap:var(--space-2)}
.socials a{display:inline-flex;align-items:center;white-space:nowrap;text-decoration:none;transition:color .2s var(--ease)}
@keyframes heroEnter{from{translate:0 12px;filter:blur(3px)}to{translate:0 0;filter:none}}
@keyframes portraitRock{0%,100%{transform:translate3d(-.38vw,.08vh,-8px) rotateY(-1deg)}50%{transform:translate3d(.38vw,-.16vh,10px) rotateY(1deg)}}

/* ---------- the shelf header: in flow after the hero, sticky once reached ----------
   catalog-shelf.css fixes it to the viewport top and pads the shelf under it;
   here it follows the hero and then sticks, so the shelf loses that padding. */
/* ONE header, fixed, above everything, and it never moves. catalog-shelf.css
   already fixes it to the viewport top and pads the shelf under it by
   --header-h; the merged product used to override that to sticky so it could
   follow a hero that owned its own bar. There is no second bar now, so the
   override goes and the specimen's own behaviour is the right one again.

   Taller than the specimen's, because it carries two rows: the name and the
   theme control, which never change, and beneath them a row that cross-fades
   from the profile's controls to the catalogue's. Declared here and not in
   catalog-shelf.css — that file is the approved specimen and /catalog-shelf.html
   must keep the header it was approved with. */
:root{--header-h:74px}
@media (max-width:760px){:root{--header-h:66px}}
@media (max-width:420px){:root{--header-h:62px}}

/* One row again: the name, and the two controls. The view switcher moved
   out to a floating pill, so the second row is gone and the header can be a
   header. */
.site-header{display:flex;align-items:center;padding-top:0;padding-bottom:0;z-index:60}
/* The name is the fixed point of the whole page, set in the title style
   (24px, 21px on a phone, extra-bold) rather than the specimen's black: the
   record's own title leads in the catalogue, and this sits above it. */
.site-header .wordmark{font:var(--t-title);letter-spacing:var(--tr-title)}
/* Over the records, not under them: they fly past it on the way down. */
.header-top{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%}
.header-right{display:flex;align-items:center;gap:8px}
/* The name is the switcher: one control, in the same title style. Upright:
   the shorthand sets the style back to normal, and the specimen's italic
   read as a logotype rather than as the owner's name. */
.who-btn.wordmark{display:inline-flex;align-items:center;gap:8px;padding:0;border:0;background:none;cursor:pointer;
  font:var(--t-title);letter-spacing:var(--tr-title);
  color:inherit;text-transform:none}
.who-btn.wordmark .nm{font:inherit;color:inherit}
/* The chevron in the page's muted, rather than the name's ink at half. */
.who-btn.wordmark svg{width:13px;height:13px;flex:0 0 auto;color:var(--muted)}
/* Fixed, not absolute. Anchored to the header rather than to the button, so it
   cannot be clipped by the header's own box or pushed off the left edge — which
   is what happened on the owner's phone. It stands on the page's left edge,
   under the name. */
.who-menu{position:fixed;left:var(--pad-l);right:auto;top:calc(var(--header-h) - 10px);
  width:min(280px,calc(100vw - 24px));max-height:min(60svh,420px)}
/* The view switcher is a floating control now, bottom right, where a thumb is —
   not a row under the name. Sketched by the owner. Fixed to the viewport so it
   stays put while the catalogue scrolls, and it arrives with --dive-ui like the
   rest of the catalogue's chrome. */
.header-row.is-catalog{position:fixed;left:auto;right:clamp(14px,4vw,28px);bottom:clamp(16px,4svh,30px);top:auto;
  width:auto;justify-content:flex-end;z-index:45}
/* One segmented pill, the network's filter control (Design_Cohesion step 4): the word, then the view's picture. */
.mode-switch{display:inline-flex;width:auto;height:auto;gap:0;padding:0;border:1px solid var(--line);border-radius:var(--radius-pill);background:var(--header-bg);overflow:hidden;
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);box-shadow:0 10px 24px -14px rgba(0,0,0,.45)}
.mode-button{display:inline-flex;align-items:center;gap:7px;height:36px;min-width:0;padding:0 13px;border:0;border-radius:0;background:transparent;color:var(--muted);
  font:600 12px/1 var(--sans);letter-spacing:.01em;
  transition:color .2s var(--ease),background .2s var(--ease)}
.mode-button+.mode-button{border-left:1px solid var(--line)}
.mode-button svg{width:15px;height:15px;fill:currentColor}
.mode-button:hover{color:var(--ink)}
.mode-button.is-active{background:var(--ink);color:var(--page)}
/* The sliding rule belonged to a text row; the pill highlights instead. */
.mode-pill{display:none}
/* Manage and the theme control keep the header to themselves. */
.header-stats{display:none}
/* Stacked, so the header's height never changes as they swap and nothing
   below it shifts by a pixel mid-dive. */
.header-row{position:absolute;inset:0;display:flex;align-items:center;gap:12px;
  transition:opacity .28s var(--ease);will-change:opacity}
.header-row.is-catalog{opacity:var(--dive-ui,0);justify-content:space-between}
/* Only the row that is actually showing can be clicked. */
.header-row{pointer-events:none}
html.is-in-catalog .header-row.is-catalog{pointer-events:auto}
/* The header is the hero's own colour while the profile is up, and the page's
   once you are in the catalogue — one bar, two grounds, no seam. */
/* NO BAR. The owner: "there's a header at the top of the screen where my name
   is, and Manage, and... I don't like that, it doesn't feel like the
   background is [continuous] — just remove that shit, make it blend.
   swajbeats is supposed to blend into the background. All of that's just
   supposed to be sitting on top."

   So the header has no surface of its own in either state: the name, Manage
   and the theme toggle sit directly on whatever the page's background is, and
   the record's colour runs behind them unbroken. It was the blurred bar that
   made the catalogue read as a separate sheet from the profile. */
.site-header{background:transparent;backdrop-filter:none;-webkit-backdrop-filter:none;
  transition:color .3s var(--ease)}
html:not(.is-in-catalog) .site-header{color:var(--hero-ink)}
/* The name only: the header's buttons are all the page's muted, the theme
   control with them. */
html:not(.is-in-catalog) .wordmark{color:var(--hero-ink)}
/* The reference fixes its header over a 100svh shelf, so the catalogue is
   exactly one screen. Here the header is in flow above it, so the section
   gives that height back and the composition is the same screenful. */
/* No padding override: with the header fixed again, catalog-shelf.css's own
   calc(var(--header-h) + N) is correct and the catalogue is one screen. */
main{scroll-margin-top:var(--header-h)}

/* ---------- the dive (hero-dive.js) ----------
   The band clips its covers so a dragged rail cannot spill past the edges.
   While they are still in the air they have to be ABOVE the band, over the
   portrait, so the clip comes off for exactly as long as the dive lasts and
   goes straight back on. `clip` rather than `hidden` on the page: hidden would
   make body a scroll container and break the sticky header. */
/* The covers have to escape the band UPWARD during the dive — that is the
   whole flight — but never sideways. They scatter to within 46% of the
   viewport either side of centre, and with the band unclipped that reached
   past the edge and made the document wider than the screen: measured on a
   390px phone, the page could be dragged 84px sideways mid-dive. Clipping one
   axis and not the other is exactly what overflow-x/y are for. */
html.is-diving .record-stage{overflow-x:clip;overflow-y:visible}
/* ALWAYS, not only while diving. Nothing on this page is meant to be reached
   by panning sideways, and several things are positioned from the selected
   record rather than from the page — so any of them drifting past an edge
   turned into a document wider than the screen and a phone that could be
   dragged off its own layout. `clip` rather than `hidden`, or body becomes a
   scroll container and the sticky header stops sticking. */
html,body{overflow-x:clip}
/* In the air they are moving every frame; at rest this must not be left on.
   NOT ON A PHONE. will-change promotes every one of the twenty-nine sleeves
   to its own compositor layer, and a phone GPU asked for twenty-nine layers
   it did not need spends longer managing them than it saves — and only two of
   them are on screen. The flight is smoother without it there. */
html.is-diving:not(.dev-phone) .record-sleeve{will-change:transform,opacity}

/* The stack shows artwork, dimmed and set back, so a multi-track record reads
   as a collection at a glance rather than as a cover with paper behind it. */
.leaf{overflow:hidden}
.leaf img{display:block;width:100%;height:100%;object-fit:cover;
  opacity:.5;filter:saturate(.72) brightness(1.06)}
.record-sleeve.is-selected .leaf img{opacity:.62}
/* THE STACK FLATTENS as its sheets leave. --badge-open is the flight, written
   on the band once a frame by catalog-shelf.js; the leaves are gone by the
   time it reaches a seventh, which is while the sheets are still over the
   cover. No transition: the number is scrubbed, and a transition on top of a
   scrub is two clocks fighting. */
.record-sleeve.is-open .leaf{opacity:calc(1 - var(--badge-open,0) * 7)}

/* ---------- the badge ----------
   His drawing, and the motion is the point: the sheets stacked behind the
   cover COME OUT — they slide right and spread into a column — and slide back
   in when the selection moves on. Not a menu appearing beside the cover. So
   the badges start stacked, at the cover's own position, and travel out; they
   are kept in the DOM while collapsing so the return is animated too, and the
   stack itself leaves with them (see .record-sleeve.is-open .leaf above).

   ONE ROW PER SONG, as his first app had it (the Year Wheel's track menu,
   .amRow — the owner, 2026-10-01: "make it like this, the OG from my
   drawing"): on the left who it is by, the title large, "Track: N"; on the
   right the face and the name over the role. No card, no thumbnail.

   Declared here, not in catalog-shelf.css: /catalog-shelf.html is the approved
   specimen and its shelf stays as approved. */
.tracklist{position:absolute;left:0;bottom:var(--shelf-baseline);z-index:6;
  display:flex;flex-direction:column;justify-content:flex-end;gap:0;
  width:min(440px,40vw);padding-left:16px;pointer-events:none;
  --am:clamp(12px,1vw,15px)}
/* UNDER THE COVER. Two cases end up here. A single has one credit and nowhere
   to fan, so its badge belongs under the artwork — "title card, cover art,
   credit badge under the cover art". And on a phone a whole album's badges go
   under it too: "on a mobile phone the side menus are supposed to populate
   under the actual cover art, just because the screen has more space to
   actually seat those in that location." Beside the cover on a 390px screen
   there is no beside.

   Placed from the top, with catalog-shelf.js writing both coordinates rather
   than only the sideways one. */
.tracklist.is-under{top:0;bottom:auto;justify-content:flex-start;
  width:var(--sleeve-w);max-width:calc(100% - 16px);padding-left:0}
/* ONE SIZE DRIVES THE ROW. Every part is in em off --am, set on the column
   (and smaller on a phone, a short screen and the gallery), so the row keeps
   its proportions at any size: who it is by 1, the title 1.8, "Track: N"
   .72, the face 1.8, the name .85, the role .72 — the drawing's, with the credit's words held
   to a size that can be read (11px and 10px at least). The grey lines are
   90% ink, not the OG's half-tones: without a card under them those read
   at about 3.4:1 on a dimmed cover (the owner, 2026-10-01: "on the desktop
   view the text is hard to see").

   No surface of its own and no shadow under the words (the owner,
   2026-10-01: "take out the shadow"). They float, as on the record screen,
   and are read off the artwork behind them the OG's way: the covers the list
   sits over recede toward the ground (catalog-shelf-render.js beside the
   cover; the other tiles in the gallery), as in his drawing. A veil drawn
   behind the column was tried and read as a pale box — a card again. */
.track-row{position:relative;z-index:1;display:flex;align-items:center;justify-content:space-between;
  gap:1.2em;padding:.5em 0;font-size:var(--am)}
/* ...except where the list has had to rise over its OWN cover (a short
   phone, Safari's bars showing). There the cover's foot fades into the
   ground under the rows — only the part they cover, from the cover's own
   width and corners, and only by as much as they cover it (--over, written
   by catalog-shelf-render.js). */
.tracklist::before{content:"";position:absolute;z-index:0;left:0;right:0;top:calc(-1 * var(--over-fade,40px));
  height:calc(var(--over,0px) + var(--over-fade,40px));border-radius:0 0 var(--cover-radius) var(--cover-radius);
  background:color-mix(in srgb,var(--page) 84%,transparent);pointer-events:none;
  opacity:calc(var(--over-k,0) * (var(--badge-open,0) - .35) * 1.6);
  -webkit-mask-image:linear-gradient(to bottom,transparent,#000 var(--over-fade,40px));
  mask-image:linear-gradient(to bottom,transparent,#000 var(--over-fade,40px))}
.tracklist:not(.is-under)::before,.tracklist:empty::before{display:none}
/* The words arrive last — "stacked opens up WITH the title name". Until then
   all you see is sheets moving. */
.track-work,.track-credit{opacity:calc((var(--badge-open,0) - .58) * 2.4)}
.track-work{display:flex;flex-direction:column;min-width:0}
.track-artist{font-family:var(--sans);font-size:max(10.5px,1em);font-weight:600;line-height:1.15;
  color:color-mix(in srgb,var(--ink) 90%,transparent);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* ONE VOICE. The title is Inter's DISPLAY cut, heavy and tightly tracked, set
   as the title card is: a song's name is the same kind of name. */
.track-title{font-family:var(--serif);font-size:1.8em;font-weight:800;letter-spacing:-.015em;line-height:1.12;
  color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* A title too long for its row even after the credit has given way goes
   onto a second line, balanced, rather than being cut ("fix the title cut
   off"). Only that title — catalog-shelf-core.js marks it when the column
   is measured — so the others keep their one line. A third line is cut. */
.track-title.is-long{white-space:normal;text-wrap:balance;overflow-wrap:anywhere;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}
/* "Track: N" under the title, the OG's proportions (.amTr): .72 of the
   row's size with a 9px floor. N is the song's place on the whole record
   (catalog-shelf-core.js workOf); a single has none. Quiet by its SIZE, not
   its colour: it takes the row's 90% ink like the role beside it, because
   --muted read at about 3:1 on a dimmed cover — the half-tone the owner
   already found hard to read on the desktop (2026-10-01, above). */
.track-no{font-family:var(--sans);font-size:max(9px,.72em);font-weight:600;line-height:1.2;
  color:color-mix(in srgb,var(--ink) 90%,transparent);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* ON A PHONE the number goes on the artist line, after the name, so it adds
   no height: a phone has no room to make for a third line. Held sideways,
   four songs beside the cover already fill the space down to the view
   buttons; upright on a small phone, a taller list rises further over its
   own cover. The title spans both columns, and the second is 1fr, so the
   title's width lands there and never pushes the number away from the name
   (nor widens the row: an intrinsic second column took the whole title,
   and the credit's role wrapped). A long artist line gives way first, to its
   ellipsis; the number keeps its whole width (min-width), or a 1fr column
   would give it none. A song with no artist line: the number alone heads
   it. Desktop and tablet keep the number under the title. */
html.dev-phone .tracklist .track-work{display:grid;grid-template-columns:minmax(0,auto) 1fr;
  column-gap:.6em;align-items:baseline}
html.dev-phone .tracklist .track-artist{grid-row:1;grid-column:1;min-width:0}
html.dev-phone .tracklist .track-no{grid-row:1;grid-column:2;min-width:max-content}
html.dev-phone .tracklist .track-title:first-child + .track-no{grid-column:1}
html.dev-phone .tracklist .track-title{grid-row:2;grid-column:1 / -1;min-width:0}
/* Under a cover the HEIGHT sizes (balanceBand, a short window), the rows
   sit closer, so the number lines cost the cover a few pixels rather than a
   whole size: the title card above stays the cover's width and its
   year/kind line stays on one line (.is-balanced .record-kicker).
   balanceBand sets the class and counts this padding. */
.shelf-view.is-balanced.rows-close .track-row{padding:.2em 0}
/* A column narrower than a row can hold (a single under a small cover on a
   phone held sideways): the credit goes under the title, so the title has the
   whole width and no word is split. */
.tracklist.is-narrow .track-row{flex-wrap:wrap;row-gap:.25em}
.tracklist.is-narrow .track-work{flex:1 1 100%}
/* The credit: the face, then the name over the role(s). When a row is
   tight the CREDIT gives way first — its role wraps onto a second line
   ("Producer ·" / "Composer") — and the title only after that, down to the
   name's own width (the owner, 2026-10-02: "fix the title cut off", after
   "Vintage Garme…" beside "Producer · Composer" on a phone). The role is
   never cut ("full role text"). The shrink weight is huge on purpose: flex
   shares shrinking by weight × size, and at 100 the title still gave up a
   fraction of a pixel — enough for "Vintage Garmen…" next to a wrapped role. */
.track-credit{display:flex;align-items:center;gap:.55em;flex:0 1000000 auto;max-width:16em}
/* Sized off --am, not em: the initials set their own font-size. */
.credit-face{flex:0 0 auto;width:calc(var(--am,12px) * 1.8);height:calc(var(--am,12px) * 1.8);border-radius:50%;overflow:hidden;
  background:var(--object-ground);display:grid;place-items:center;
  font-family:var(--sans);font-size:calc(var(--am,12px) * .75);font-weight:800;letter-spacing:.01em;color:var(--muted)}
/* Cropped to the face, the same 18%-from-the-top the hero uses on the portrait. */
.credit-face img{display:block;width:100%;height:100%;object-fit:cover;object-position:50% 14%}
.track-who-stack{display:flex;flex-direction:column;min-width:0;line-height:1.15}
.track-who{font-family:var(--sans);font-size:max(11px,.85em);font-weight:800;letter-spacing:-.01em;line-height:1.15;
  color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.track-role{font-family:var(--sans);font-style:normal;font-size:max(10px,.72em);font-weight:600;line-height:1.2;
  color:color-mix(in srgb,var(--ink) 90%,transparent);min-width:0}

/* ---------- the sheets ----------
   One per song. It starts as the cover — same artwork, same size, same place
   — and travels to its row, shrinking to the row's height at the row's left
   end, and dissolves as the words arrive (catalog-shelf-render.js). Positioned
   from the top left because that is the corner the flight is written
   against. */
.flight-sheet{position:absolute;left:0;top:0;z-index:2;width:var(--sleeve-w);aspect-ratio:1;
  transform-origin:top left;overflow:hidden;background:var(--object-ground);
  box-shadow:var(--record-shadow);pointer-events:none}
.flight-sheet img{display:block;width:100%;height:100%;object-fit:cover}
.record-stage.badges-landed .flight-sheet{display:none}
/* A SINGLE does not fly: the owner, "why is it taking the album and making
   that a card? That doesn't make sense for a single. The credit badge should
   just appear at the bottom for that scenario." There is no stack to open,
   so there is nothing to animate opening; it arrives with the rest of the
   catalogue. */
.tracklist.is-single .track-row{transform:translateY(calc((1 - var(--badge-open,0)) * 12px))}
@media (prefers-reduced-motion:reduce){.tracklist.is-single .track-row{transform:none}}
.record-artist,.record-kicker{font-family:var(--sans);font-weight:700;letter-spacing:.1em}
/* The gallery's own card is set in full further down, beside the list. */

/* ---------- the same list, in the gallery ----------
   "For the view all, when I hover over it, I wanted that to have the same
   effect where the list comes down. You can see the list." The same badges,
   dropped under the artwork.

   An OVERLAY, and only where there is a pointer to hover with. The gallery's
   row spans are computed from the artwork and the caption, so a list in flow
   would re-measure every tile; and on a phone there is no hover at all, so
   showing it there would only be a list nobody asked for over the next row.
   The card is lifted out of the flow's paint order while it is hovered, or a
   later tile's own artwork covers the list that dropped over it. */
/* The tile's stack is a <span> and was left inline. An absolutely positioned
   child of an INLINE containing block is laid out against its line boxes, not
   against the artwork, so the dropped list resolved to zero width and every
   badge came out as a bare thumbnail with its text squeezed to nothing. Its
   content is already block-level, so this changes nothing that was drawn. */
.grid-stack{display:block}
@media (hover:hover){
  /* Hidden, the dropped list takes no pointer: otherwise a pointer arriving
     on the tile below lands on this tile's invisible list and hovers the
     wrong tile. The rows take it back while their own tile is hovered. */
  .grid-tracks{position:absolute;left:10px;right:0;top:calc(100% + 8px);z-index:3;
    display:flex;flex-direction:column;gap:0;--am:10.5px;pointer-events:none}
  /* The rows drop across the next row of tiles, so while one tile is
     hovered the others recede (as the shelf's do beside an open album, and
     as they already do while a record is held), and the rows read over them. */
  .record-grid:has(.grid-card:hover) .grid-card:not(:hover){opacity:.15}
  /* ...and their captions go entirely, or a title under the rows still reads
     through them, word over word. */
  .record-grid:has(.grid-card:hover) .grid-card:not(:hover) .grid-caption{opacity:0}
  .grid-card:hover,.grid-card:focus-visible,.grid-card:focus-within{position:relative;z-index:30}
  .grid-track{padding:.45em 0;opacity:0;transform:translateY(-12px) scale(.95);
    transition:opacity .24s var(--ease),transform .36s cubic-bezier(.22,.82,.18,1);
    transition-delay:calc(var(--i) * 44ms);pointer-events:none}
  .grid-card:hover .grid-track,.grid-card:focus-visible .grid-track{opacity:1;transform:none;pointer-events:auto}
  /* THE LIST IS PART OF THE TILE. It used to ignore the pointer entirely, so
     the tile lost :hover the moment you moved off the artwork and the list
     vanished under you — the owner: "My Kollection is only letting me hover
     over Beijeng and not the rest of the tracks." Taking the pointer keeps
     the tile hovered while you read down it, and a click anywhere on a row
     still reaches the tile's own button and opens the record. */
  .grid-track{cursor:pointer;transition:opacity .24s var(--ease),
    transform .36s cubic-bezier(.22,.82,.18,1)}
  /* The OG's "on" row: the one under the pointer reads brighter. */
  .grid-track .track-title{color:color-mix(in srgb,var(--ink) 88%,transparent)}
  .grid-track:hover .track-title{color:var(--ink)}
  /* These rows answer to the pointer, not to the shelf's flight, so they opt
     out of --badge-open — which is written on the band and is absent here. */
  .grid-track .track-work,.grid-track .track-credit{opacity:1}
  /* The hover list is an overlay (its height moves no tile), so its titles
     simply wrap to two balanced lines when they must, instead of being cut. */
  .grid-track .track-title{white-space:normal;text-wrap:balance;
    display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}
}
@media (hover:hover) and (prefers-reduced-motion:reduce){
  .grid-track{transition:none;transform:none}
}
@media not all and (hover:hover){ .grid-tracks{display:none} }

/* ---------- the gallery's own title card ----------
   "For the title card on the View all page, it should display as the same
   font as on the bookshelf and wave views, at the top." Same three lines, same
   order, same cuts as the card on the band — and above the artwork, where
   that card is. */
/* "The title should fit more compact with the cover, so it can look cohesive,
   like they belong together, and the spacing should be fairly similar to
   everything." So the same rhythm as the card on the band: the last line
   lands just above the artwork. */
/* "Just make it look like how it looks, but a mini version — bring the title
   close to the cover art." The stack keeps 10px of padding above the artwork
   for the leaves to lean into, so the caption is pulled back through it: what
   matters is the gap to the ARTWORK, not to the box around it. */
.grid-caption{display:block;padding:0 2px 0;margin-bottom:-4px}
.grid-card-artist{display:block;margin:0 0 2px;font-family:var(--sans);font-size:.6875rem;
  line-height:1.3;letter-spacing:.1em;text-transform:uppercase;font-weight:700;color:var(--muted)}
.grid-card-title{display:block;font-family:var(--serif);font-size:clamp(15px,1.35vw,19px);
  font-weight:800;letter-spacing:-.026em;line-height:1.12;color:var(--ink)}
.grid-card-year{display:block;margin-top:2px;font-family:var(--sans);font-size:.625rem;
  line-height:1.3;letter-spacing:.1em;text-transform:uppercase;font-weight:700;color:var(--muted)}

/* ---------- which one you are on ----------
   A wash of the record's own colour, sampled from the artwork in
   catalog-shelf.js. It is THE BACKGROUND, not a glow around one cover: a
   fixed full-screen field behind the header, the card, the covers and the
   badges alike, so the page is one continuous ground. A version of this was
   clipped to the band, which is what left the header sitting on a different
   colour from everything under it.

   Its opacity rides --world-fade: the artist's paper leaves as the records
   arrive, and the record's own colour is what they arrive into. */
.tint{position:fixed;inset:0;z-index:-1;pointer-events:none;overflow:hidden;
  background-color:rgb(var(--record-tint,0 0 0) / .30);
  opacity:calc(var(--catalog-in,1) * var(--tint-on,0));
  transition:opacity .5s var(--ease),background-color .6s var(--ease)}
/* Each layer is the cover itself, blown past the edges and blurred. The inset
   and the scale exist because a blur this wide pulls the transparent outside
   of the box inward: without them the scene has four pale borders. */
.tint i{position:absolute;inset:-16%;display:block;background:center 42%/cover no-repeat;
  filter:blur(64px) saturate(1.5);transform:scale(1.1);
  opacity:0;transition:opacity .75s var(--ease);will-change:opacity}
.tint i.on{opacity:1}
/* And a veil, or the page is text on a photograph. It is the page's own
   colour, so the scene reads as the ground tinted rather than as wallpaper. */
.tint::after{content:"";position:absolute;inset:0;background:var(--tint-veil)}
:root{--tint-veil:color-mix(in srgb,var(--page) 74%,transparent)}
:root[data-theme="dark"]{--tint-veil:color-mix(in srgb,var(--page) 58%,transparent)}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){--tint-veil:color-mix(in srgb,var(--page) 58%,transparent)}}
html.has-tint{--tint-on:1}
@media (prefers-reduced-motion:reduce){
  .tint{transition:none}
}
@media (max-width:760px){
  /* The row's one size on a phone: a title of about 21px, and four songs
     still fit between the cover and the view buttons on a 390x844 screen. */
  .tracklist{width:min(240px,50vw);padding-left:11px;--am:11.5px}
}

/* ---------- the shelf's geometry, in ONE place ----------
   Every one of these resolves against the others, so they are all declared on
   the same element. A custom property is substituted where it is DECLARED,
   not where it is used: --sleeve-w declared on :root and --band-h overridden
   on .shelf-view meant the sleeve was sized against the band height :root
   still had, and the covers came out a third smaller than the band they sat
   in. That mismatch is what every "there's a gap" note has been about.

   --card-reserve is the room kept above the covers for the title card;
   --badge-reserve the room kept BELOW them for a single's credit badge. The
   badge only exists on a single, but the room is kept on every record, or the
   artwork would jump each time you swiped past one.

   The floor under the third term matters: on a short window the reserves can
   add up to more than the band, and without it the covers collapse to
   nothing rather than simply crowding the card. */
:root{
  /* --shelf-slack is not a taste value: it is the section's own padding, and
     the band is the screen minus it. .shelf-view pads (--header-h + 18) above
     and 30 below, so anything other than 48 leaves the page longer or shorter
     than one screen. It was 46, and that 2px is why every desktop size had
     scroll left over after the dive had landed — room for a vertical drag to
     steal a sideways swipe on the covers. */
  --shelf-slack:48px;
  --card-reserve:172px;
  --badge-reserve:80px;
  --band-h:max(300px,calc(100svh - var(--header-h) - var(--shelf-slack)));
  --sleeve-max:min(74vw,460px);
  --sleeve-floor:180px;
  --sleeve-w:min(var(--sleeve-max),calc(var(--band-h) * .82),
    max(var(--sleeve-floor),calc(var(--band-h) - var(--card-reserve) - var(--badge-reserve) - 12px)));
  /* THE CARD HUGS THE COVER. "I need the title a lot closer to the cover art,
     to make it look a lot more compact and fit the screen better — I don't
     want the title card moving away from the cover too much and distorting
     the way the space looks." So the artwork sits exactly --card-gap under
     the card's room and ALL the leftover height goes below it, rather than
     being split above and below. Floored at the badge's own room, so a
     single's credit always fits underneath. */
  --card-gap:8px;
  --shelf-baseline:max(var(--badge-reserve),
    calc(var(--band-h) - var(--card-reserve) - var(--card-gap) - var(--sleeve-w)));
}
@media (max-width:760px){
  :root{
    /* The phone pads (--header-h + 10) above and 22 below. */
    --shelf-slack:32px;
    --card-reserve:122px;
    --badge-reserve:70px;
    /* With the card overlaid rather than stacked above, the phone has room
       the covers were not using. */
    --sleeve-max:min(80vw,380px);
  }
}

/* ---------- the title card, ON the scene ----------
   His Freeform mock moves it up and his note puts it on top: "it's supposed
   to sit on top and look fluid with the fade... the title card should be
   centered with the actual project cover".

   So it is an OVERLAY on the band, not a block above it. Three things follow,
   and all three were complaints:
     - it starts at the top of the catalogue, so there is nothing between it
       and his name in the header. Reserving flow space for it was what put
       "a fat ass space" there, because the reserve had to hold the tallest
       card any record could produce.
     - nothing it contains can move the covers. That is what the reserve was
       FOR, and an overlay gets it for free — a two-line title, a version
       switcher, a single's credit badge underneath, none of them shift the
       artwork by a pixel.
     - it rides sideways with the record it belongs to. --card-x is written
       once a frame by catalog-shelf.js from the same numbers the badges use.
   Its own box is the width of a cover, so the words start on the cover's left
   edge rather than floating over the middle of the band. */
.shelf-view{position:relative;padding-bottom:30px}
/* `top` is the SAME expression as the section's own padding-top, not 0: an
   absolutely positioned child is placed against the padding box, so top:0 put
   the card behind the fixed header with the artist's name under it. It has to
   start exactly where the band starts, because a single's badge is placed by
   measuring down from the card and the two must share a frame. */
/* The card's box has to be the BAND's box, because --card-x is written as an
   offset from the band's centre. An absolutely positioned child is placed
   against the padding box, which is already the full-bleed width — so it
   takes no negative margins, and it must drop the width:100% and auto
   margins it inherits from the flowed readout, or it is over-constrained and
   lands a page gutter to the left of where the covers are. */
/* ITS BOX IS THE RESERVE, AND THE WORDS SIT AT THE BOTTOM OF IT. His
   reference: the year/type/credits line lands right on the artwork's top
   edge, whatever the title did above it. Pinning the card's TOP could not do
   that — a one-line title left half the reserve as a hole between the words
   and the cover, and every record has a different title. Bottom-aligned, the
   last line is always --card-gap above the cover and the title grows upward
   into the room under the header instead. */
.shelf-view .record-readout{position:absolute;z-index:7;top:calc(var(--header-h) + 18px);
  left:0;right:0;width:auto;margin:0;max-width:none;
  height:var(--card-reserve);min-height:0;padding:0;pointer-events:none;
  display:flex;align-items:flex-end}
/* THE CHIP SHARES THE KICKER'S LINE. Two of twenty-nine records carry a
   version switcher, and giving it a line of its own meant the card's reserved
   room had to be tall enough for a record that almost never comes up — which
   pushed the artwork down on every other one. Side by side, the card is one
   line shorter and the covers move up to meet it. */
.shelf-view .record-identity{width:var(--sleeve-w);max-width:calc(100% - 28px);
  /* THE CARD IS NOT A LID. It is an overlay at z-index 7 sitting over the top
     of the artwork, and it used to take the pointer for its whole box — so on
     a short screen, where the card and the cover overlap, elementFromPoint a
     quarter of the way down the cover returned the card and a swipe there
     never reached the shelf at all. Only the version switcher inside it is
     something you click; the words are words. */
  margin-inline:auto;transform:translateX(var(--card-x,0px));pointer-events:none;
  display:flex;flex-wrap:wrap;align-items:center;column-gap:14px}
.shelf-view .record-artist,.shelf-view .record-identity h2{flex:0 0 100%}
.shelf-view .record-kicker,.shelf-view .version-switch{margin-top:10px}
.shelf-view .version-switch{pointer-events:auto}
/* IT ARRIVES WITH THE COLOUR. "I see the title card come up from the bottom
   and that looks cool, but it comes in a little bit too early — it should
   come in as the background colour is changing." --catalog-in is that clock,
   written by hero-dive.js: the same window the record's scene fades up in. */
.shelf-view .record-readout{opacity:var(--catalog-in,1)}
/* BIGGER. "You've got to make that title card a lot bigger, it looks too
   small" — on the Wave and on the Bookshelf both. Sized off his reference,
   where the title is roughly a seventh of the cover's width. */
.shelf-view .record-identity h2{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;
  overflow:hidden;font-size:clamp(34px,4.6vw,58px);line-height:1;letter-spacing:-.034em}
.shelf-view .record-artist{margin-bottom:8px;font-size:.8125rem;letter-spacing:.14em}
.shelf-view .record-kicker{font-size:.8125rem;letter-spacing:.13em}
@media (max-width:760px){
  .shelf-view{padding-bottom:22px}
  .shelf-view .record-readout{top:calc(var(--header-h) + 10px)}
}

/* ---------- Highlights ---------- */
.highlights{flex:0 0 auto;z-index:9;color:var(--hero-ink)}
.highlights-head{display:flex;align-items:center;justify-content:space-between;width:100%;padding:var(--space-4) 0 0;
  border:0;border-top:1px solid color-mix(in srgb,var(--hero-ink) 14%,transparent);background:none;color:inherit;cursor:pointer;font:inherit}
.highlights-head .label{font:var(--t-name);letter-spacing:var(--tr-name)}
.highlights-sign{font-size:18px;line-height:1;color:var(--hero-dim)}
.highlights-head[aria-expanded="true"] .highlights-sign{transform:rotate(45deg)}
.highlights-body{padding:var(--space-2) 0 0}
.highlights-empty{margin:0;font:var(--t-small);letter-spacing:var(--tr-small);color:var(--hero-dim)}
/* The records he picked, in the order he picked them: the name style over a
   small line, beside the cover's own corner. */
.highlight-list{list-style:none;display:flex;flex-wrap:wrap;gap:var(--space-2) var(--space-4);margin:0;padding:0}
.highlight{display:flex;align-items:center;gap:var(--space-2);min-width:0}
.highlight-art{flex:0 0 auto;width:40px;height:40px;border-radius:var(--radius-cover);overflow:hidden;
  background:color-mix(in srgb,var(--hero-ink) 10%,transparent)}
.highlight-art img{display:block;width:100%;height:100%;object-fit:cover}
.highlight-text{display:flex;flex-direction:column;min-width:0}
.highlight-text b{font:var(--t-name);letter-spacing:var(--tr-name);
  color:var(--hero-ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.highlight-text i{font:var(--t-small);letter-spacing:var(--tr-small);color:var(--hero-dim)}

/* ---------- the profile editor (profile-edit.js) ----------
   His workspace for the front door: picture, name, roles, based in, bio,
   social accounts, highlights. It lives in Manage because that is where the
   owner already works, and it borrows Manage's own controls (.fix-btn, the
   pane tokens) rather than inventing a second set. */
.pe-head{margin:0 0 22px}
.pe-title{margin:0;font-family:var(--serif);font-size:clamp(22px,2.4vw,30px);font-weight:900;
  letter-spacing:-.04em;line-height:1.05;color:var(--ink)}
.pe-sub{margin:6px 0 0;font-size:13px;color:var(--muted)}
.pe-block{margin:0 0 26px;padding:0 0 22px;border-bottom:1px solid var(--line)}
.pe-block:last-of-type{border-bottom:0}
.pe-h{margin:0 0 12px;font-family:var(--sans);font-size:.6875rem;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.pe-note{margin:8px 0 0;font-size:12px;line-height:1.5;color:var(--muted)}
.pe-field{display:block;margin:0 0 14px;max-width:560px}
.pe-label{display:block;font-size:12.5px;font-weight:600;color:var(--ink)}
.pe-hint{display:block;margin-top:2px;font-size:11.5px;color:var(--muted)}
.pe-input{width:100%;margin-top:6px;padding:9px 12px;border:1px solid var(--line);border-radius:10px;
  background:var(--pane-field);color:var(--ink);font:inherit;font-size:14px}
.pe-input:focus{outline:2px solid var(--pane-accent);outline-offset:1px;border-color:transparent}
.pe-area{resize:vertical;line-height:1.5}
.pe-rows{display:flex;flex-direction:column;gap:8px;margin-top:6px}
.pe-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center}
.pe-row-2{grid-template-columns:minmax(0,.8fr) minmax(0,1.4fr) auto}
.pe-row .pe-input{margin-top:0}
.pe-x{width:34px;height:34px;flex:0 0 auto;border:1px solid var(--line);border-radius:9px;
  background:transparent;color:var(--muted);font-size:17px;line-height:1;cursor:pointer;
  transition:color .18s var(--ease),border-color .18s var(--ease)}
.pe-x:hover{color:var(--ink);border-color:var(--muted)}
.pe-rows + .fix-btn{margin-top:10px}
.pe-picture{display:flex;align-items:center;gap:16px;flex-wrap:wrap}
.pe-disc{width:76px;height:76px;flex:0 0 auto;border-radius:50%;overflow:hidden;
  background:var(--pane-field) center/cover no-repeat;border:1px solid var(--line);
  display:grid;place-items:center;font-family:var(--sans);font-size:11px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted);text-align:center}
.pe-disc.is-off{border-style:dashed;font-size:9px;line-height:1.2;padding:0 8px}
.pe-picture-acts{display:flex;gap:8px;flex-wrap:wrap}
/* THE PICKER. Small cards, one per release — and a release with more than one
   track drops its tracks on hover, the same gesture the gallery's View all
   uses. The two choices are independent: picking the album does not pick its
   tracks, and picking a track does not pick the album.

   The list takes the pointer, or the card loses :hover the moment you move
   onto it and the list vanishes under you. Same fix, same reason, as the
   gallery's. */
.pe-picks{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:8px;margin-top:4px}
.pe-pick-wrap{position:relative;min-width:0}
.pe-pick-wrap.has-tracks:hover,.pe-pick-wrap:focus-within{z-index:20}
.pe-pick{display:flex;align-items:center;gap:9px;padding:6px 10px 6px 6px;text-align:left;width:100%;
  border:1px solid var(--line);border-radius:12px;background:transparent;color:var(--muted);
  font:inherit;cursor:pointer;min-width:0;
  transition:color .18s var(--ease),border-color .18s var(--ease),background .18s var(--ease)}
.pe-pick:hover{color:var(--ink);border-color:var(--muted)}
.pe-pick.on{color:var(--ink);border-color:transparent;background:var(--pane-field)}
.pe-pick-art{flex:0 0 auto;width:32px;height:32px;border-radius:6px;overflow:hidden;background:var(--pane-field)}
.pe-pick-art img{display:block;width:100%;height:100%;object-fit:cover}
.pe-pick.on .pe-pick-art{box-shadow:0 0 0 2px var(--pane-accent)}
.pe-pick-name{font-size:12.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* A multi-track release says so without a word: the card sits on a stack. */
.pe-pick-wrap.has-tracks .pe-pick{box-shadow:3px -3px 0 -1px var(--pane-field),3px -3px 0 0 var(--line)}
.pe-tracks{position:absolute;left:0;right:0;top:calc(100% + 6px);z-index:1;
  display:flex;flex-direction:column;gap:4px;padding:6px;
  border:1px solid var(--line);border-radius:12px;background:var(--pane-bg,var(--page));
  box-shadow:0 18px 40px -16px rgba(0,0,0,.5);
  opacity:0;transform:translateY(-8px);pointer-events:none;
  transition:opacity .18s var(--ease),transform .24s var(--ease)}
.pe-pick-wrap:hover .pe-tracks,.pe-pick-wrap:focus-within .pe-tracks{opacity:1;transform:none;pointer-events:auto}
.pe-track{display:flex;align-items:baseline;gap:8px;padding:5px 9px;text-align:left;min-width:0;
  border:1px solid transparent;border-radius:8px;background:transparent;color:var(--muted);
  font:inherit;cursor:pointer;
  transition:color .18s var(--ease),border-color .18s var(--ease),background .18s var(--ease)}
.pe-track:hover{color:var(--ink);border-color:var(--line)}
.pe-track.on{color:var(--ink);border-color:transparent;background:var(--pane-field)}
.pe-track-name{font-size:12px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pe-track-role{margin-left:auto;font-size:9.5px;font-weight:700;letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted);white-space:nowrap}
/* the background plate, beside the picture's disc */
.pe-plate{width:132px;height:76px;flex:0 0 auto;border-radius:10px;overflow:hidden;
  background:var(--pane-field) center/cover no-repeat;border:1px solid var(--line);
  display:grid;place-items:center;font-family:var(--sans);font-size:10.5px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted);text-align:center}
.pe-acts{display:flex;gap:10px;flex-wrap:wrap;padding-top:4px}
@media (max-width:760px){
  .pe-row-2{grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"a x" "b b"}
  .pe-row-2 .pe-input:first-child{grid-area:a}
  .pe-row-2 .pe-input:nth-child(2){grid-area:b}
  .pe-row-2 .pe-x{grid-area:x}
  .pe-picks{grid-template-columns:repeat(auto-fill,minmax(138px,1fr))}
}

/* Read by screen readers, not shown. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}

/* ---------- a finger is not a mouse ----------
   Measured on a 390x844 phone before this block: the social links were 24px
   tall, Manage 26x26, the theme toggle 28x28 and the profile switcher 29px.
   A fingertip is about 44px, and every one of those is something the owner
   reaches for constantly — Manage most of all, because it is the way into his
   own catalogue.

   The HIT AREA grows, not the ink. A ::after box centred on the control
   takes the touch, so the chrome keeps the size it was drawn at and the
   layout does not move by a pixel. Only on a coarse pointer, because a mouse
   does not need it and growing the boxes on a desktop would space the header
   out for no reason. */
@media (pointer:coarse){
  .socials a,.share-btn,.manage-toggle,.theme-toggle,.who-btn,.highlights-head,.mode-button{position:relative}
  .socials a::after,.share-btn::after,.manage-toggle::after,.theme-toggle::after,.who-btn::after,
  .highlights-head::after,.mode-button::after{
    content:"";position:absolute;left:50%;top:50%;translate:-50% -50%;
    width:max(100%,44px);height:max(100%,44px)}
}

/* ---------- the toast (record.js's say()), on the page's tokens ---------- */
.toast{position:fixed;z-index:40;left:50%;bottom:28px;transform:translate(-50%,10px);padding:10px 16px;border:1px solid var(--line);border-radius:999px;background:var(--ink);color:var(--page);font-size:12px;opacity:0;transition:.3s;pointer-events:none}
.toast.on{opacity:1;transform:translate(-50%,0)}

/* ---------- a phone on its side, and any short window ----------
   THE ONLY RULE IN THIS APP THAT EVER KEYED ON HEIGHT WAS DEAD. It lived in
   catalog-shelf.css, and home.css is the second stylesheet on home.html —
   equal specificity, later sheet wins — so its landscape --header-h and
   --band-h never applied to a single pixel. Measured: --header-h resolved to
   74px at 844x390, not the 60px it asked for. Everything short-screen
   therefore lives HERE, in the sheet that wins.

   And it keys on HEIGHT, not width. Every other breakpoint in this file
   assumes a small screen is a narrow one; a phone held sideways is 844 wide
   and 390 tall, so it passed every "desktop" test while being the most
   cramped screen anyone owns. */
@media (max-height:560px) and (orientation:landscape){
  :root{
    --header-h:56px;
    /* The section pads (--header-h + 14) above and 12 below here. */
    --shelf-slack:26px;
    --card-reserve:92px;
    --badge-reserve:54px;
    --card-gap:6px;
    --sleeve-floor:120px;
    /* No 300px floor: on a 390px screen a floor IS the overflow. The band is
       simply what is left, and the covers take what the reserves leave. */
    --band-h:max(200px,calc(100svh - var(--header-h) - var(--shelf-slack)));
    --sleeve-max:min(46vw,460px);
  }
  /* TWO COLUMNS. Stacked, the portrait and the about column cannot both fit a
     390px screen at any size worth looking at; side by side they both can,
     and the composition stays the one the owner approved rather than a
     squashed version of it. */
  .hero-stack{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);
    grid-template-rows:1fr auto;align-items:center;
    padding:calc(var(--header-h) + 6px) clamp(16px,3.4vw,40px) 12px;
    column-gap:clamp(18px,3vw,44px);row-gap:4px}
  /* Stretched, not centred: centred, the scene has no content of its own to
     size it and came out 0px tall, so the picture's max-height (the phone
     block, below) worked from 0 and the picture vanished on phones 720px
     wide or less; on wider ones the disc ran off the bottom of the screen. */
  .hero-scene{grid-column:1;grid-row:1 / span 2;min-height:0;align-self:stretch}
  .about-row{grid-column:2;grid-row:1}
  .about-row{--avatar:min(64px,15svh);--avatar-gap:6px}
  .highlights{grid-column:2;grid-row:2}
  /* svh, not vh: on a phone vh is the TALL state, so the portrait was being
     sized for a screen the URL bar was still covering. */
  .figure .portrait-main{width:min(74svh,40vw,320px)}
  /* The same six styles as anywhere else; only the bio is held to three
     lines, because the column is one short screen tall (the clamp is said
     again after the phone block, whose five lines would otherwise win on
     phones 720px wide or less). The confirmed line goes, as it does on an
     upright phone: beside the count it took the about column's width, and
     the bio showed less of itself in its three lines. */
  #heroBio{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}
  .hero-confirmed{display:none}
  .highlights-head{padding-top:8px}
  .shelf-view{padding-top:calc(var(--header-h) + 14px);padding-bottom:12px}
  /* The title card has to be a card, not a headline, when there are 92px for
     it. Its box is --card-reserve; the type has to agree with the box. */
  .shelf-view .record-identity h2{font-size:clamp(22px,3vw,30px);-webkit-line-clamp:1}
  .shelf-view .record-artist{margin-bottom:4px;font-size:.625rem}
  .shelf-view .record-kicker{font-size:.625rem}
  /* The card is normally the cover's width, and on a short screen the cover
     gets small enough that "2026 · SINGLE · 1 CREDIT" wraps. It keeps a floor
     of its own here and stays centred on the artwork. */
  .shelf-view .record-identity{column-gap:10px;width:max(var(--sleeve-w),clamp(200px,34vw,300px))}
  .shelf-view .record-kicker,.shelf-view .version-switch{margin-top:5px}
  /* The rows a size down, so the column keeps its feet inside the band. */
  .tracklist{--am:9.5px}
  .track-row{padding:.35em 0}
}
/* The smallest phones held sideways: the rows closer still, so four songs fit
   between the title card and the view buttons. */
@media (max-height:400px) and (orientation:landscape){
  .track-row{padding:.2em 0}
}

/* ---------- phones ---------- */
@media (max-width:760px){

}
@media (max-width:720px){
  .hero-word{top:44%;font-size:clamp(88px,28vw,138px)}
  .portrait-rock{inset:0 -5%}
  /* NEVER UNDER THE HEADER. The picture is centred in what the about block
     leaves it, and on a short phone (390x664, 320x568) the whole bio and the
     full-size links leave less than the picture is tall — centred, it rose
     behind the name and the buttons. So it is held to the room it has: the
     same size wherever it already fits, smaller only where it did not. The
     cut-out by its box (object-fit keeps the figure whole and centred), the
     disc by its height, so it stays round, in a row as tall as the room so
     the percentage has something to read. 16px short of the room, because
     the figure stands forward in the scene's perspective and draws a few
     percent larger than its box. */
  .figure .portrait-main{width:min(52svh,78vw,380px);max-height:calc(100% - var(--space-4))}
  /* Both columns sit at the bottom, under the portrait, with Highlights below
     them. The bio used to be pinned to top:104px, across the face. */
  /* The column does the work now; phones only need tighter numbers. */
  .hero-stack{padding:calc(var(--header-h) + 4px) var(--pad-r) var(--space-4) var(--pad-l);gap:var(--space-3)}
  /* On a phone the count rides up beside the NAME rather than taking a column
     of its own, so the bio gets the full width underneath. Only the name and
     role clear it; everything below runs edge to edge. Top to top with the
     name: the two are the same style. */
  .about-row{display:block;position:relative}
  .releases{position:absolute;top:0;right:0;align-items:flex-end}
  /* The confirmed line is real but secondary; at the top of a phone row it
     crowds the name. It stays on wider screens. */
  .hero-confirmed{display:none}
  .about{max-width:none}
  .ident-name,.ident-role{padding-right:92px}
  /* The links at full size, a thumb's worth each, wrapping to a second line
     rather than shrinking to fit one. */
  .about .socials{flex-wrap:wrap;gap:var(--space-2)}
  /* The whole bio on a tall phone (up to nine lines, below); five lines on
     a shorter one, so the portrait keeps its room. */
  #heroBio{display:-webkit-box;overflow:hidden;-webkit-box-orient:vertical;-webkit-line-clamp:5}
}
/* Nine lines on a tall phone, not none: 410 to 500 characters from 360 to
   430 wide, more than twice the example bio, so a normal bio shows whole. With no cap at all a
   long bio (the profile editor takes any length) squeezed the picture to
   nothing and pushed Highlights off the bottom of the screen. */
@media (max-width:720px) and (min-height:780px){
  #heroBio{-webkit-line-clamp:9}
}
/* A PHONE ON ITS SIDE, AGAIN. A phone 720px wide or less held sideways gets
   both the landscape block and the phone block above, and the phone block
   comes later with the same weight, so its five-line bio, its 12px row gap
   and its 16px foot won and Highlights ran off the bottom of the screen
   (568x320, 640x304, 667x331). The landscape numbers are said again here. */
@media (max-height:560px) and (orientation:landscape){
  #heroBio{-webkit-line-clamp:3}
  .hero-stack{row-gap:4px;padding-bottom:12px}
}
/* 360px tall or less, the links keep their full size on ONE row that slides
   sideways: wrapped, the second row of pills cost 38px of a 320px screen.
   The 7px above and below keep the 44px touch area (the finger block)
   inside the row, which would otherwise clip it; the margins give the same
   space back, so nothing moves. */
@media (max-height:360px) and (orientation:landscape){
  .about .socials{flex-wrap:nowrap;overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none;
    padding:7px 4px;margin:-7px -4px}
  .about .socials::-webkit-scrollbar{display:none}
}
/* 320px tall or less, the bio gives up its third line while Highlights is
   open, so the picks fit under it. Closed, the three lines stay. */
@media (max-height:320px) and (orientation:landscape){
  .hero-stack:has(#highlightsToggle[aria-expanded="true"]) #heroBio{-webkit-line-clamp:2}
}
@media (prefers-reduced-motion:reduce){
  .portrait-rock,.about,.releases,.highlights{animation:none}
}

/* ================= step 2: the record's five panes =================
 * Ported from the original app's record view (styles.css, dark) onto the
 * shelf's tokens, and scoped under .pane-body so generic names like .row and
 * .note cannot reach the rest of the page. The viewer's own card is the
 * container; these panes just flow inside its scroll.
 */
:root{
  /* The old names follow the tokens at the top of this file. */
  --pane-accent:var(--accent);      /* the one accent: blue */
  --pane-ok:var(--ok);
  --pane-no:var(--no);
  --pane-warn:var(--warn);
  --pane-on-ok:#fff;                /* a tick or number drawn on --pane-ok */
  --pane-field:rgba(20,25,35,.035);
  --pane-field-line:rgba(20,25,35,.10);
}
[data-theme="dark"]{
  --pane-on-ok:#0a0908;             /* white on the light green was 1.9:1 */
  /* cool, not cream: the ink at a whisper */
  --pane-field:rgba(242,243,245,.045);
  --pane-field-line:rgba(242,243,245,.12);
}

/* ---- the tab row, inside the viewer's content column ---- */
.pane-tabs{display:flex;gap:18px;margin:26px 0 0;border-bottom:1px solid var(--line);overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch}
.pane-tabs::-webkit-scrollbar{display:none}
.pane-tabs button{padding:8px 0 10px;border:0;background:none;color:var(--muted);font:inherit;font-size:13px;
  border-bottom:1.5px solid transparent;margin-bottom:-1px;white-space:nowrap;cursor:pointer}
.pane-tabs button:hover{color:var(--ink)}
.pane-tabs button.on{color:var(--ink);border-color:var(--pane-accent)}
.pane-body{font-size:14px;padding-top:4px}

/* ---- a person / credit row ---- */
.pane-body .row{display:grid;grid-template-columns:36px minmax(0,1fr) auto;align-items:center;gap:12px;padding:11px 0;border-top:1px solid var(--line)}
.pane-body .row:first-child{border-top:0}
.pane-body .avatar{width:34px;height:34px;object-fit:cover;border-radius:50%;background:var(--object-ground);border:1px solid var(--line)}
.pane-body .avatar.init{display:grid;place-items:center;font-family:var(--display);font-weight:800;font-size:15px;color:var(--pane-accent)}
.pane-body .row .who{font-size:14px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pane-body .row .who em{font-style:normal;margin-left:6px;font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--pane-accent)}
.pane-body .row .sub{margin-top:2px;color:var(--muted);font-size:12px}
.pane-body .row .right{text-align:right;min-width:92px}
.pane-body .row .right strong{display:block;font-size:12px}
.pane-body .row .right span{display:block;margin-top:3px;font-size:11px;color:var(--pane-accent)}
.pane-body .row .right span.dim{color:var(--muted)}
.pane-body .row .right span.ok{color:var(--pane-ok)}
.pane-body .row .right span.warn{color:var(--pane-warn)}
.pane-body .row .right span.no{color:var(--pane-no);font-style:italic}
.pane-body .row.person.me{background:var(--pane-field)}
.pane-body .row.person.tappable{cursor:pointer}
.pane-body .row.person.tappable:hover .who{color:var(--pane-accent)}

/* ---- your own claim actions ---- */
.pane-body .claim-act{display:flex;flex-wrap:wrap;gap:8px;padding:2px 0 10px}
.pane-body .claim-act button{padding:9px 14px;border:1px solid var(--line);border-radius:999px;background:none;
  color:var(--muted);font:inherit;font-size:12px;cursor:pointer;transition:color .2s ease,border-color .2s ease}
.pane-body .claim-act button:hover{color:var(--ink);border-color:var(--muted)}
.pane-body .claim-act button.primary{background:var(--ink);border-color:var(--ink);color:var(--page);font-weight:600}
.pane-body .claim-act .note{margin-top:0}

/* ---- Identity ---- */
.pane-body .kv{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin-top:8px}
.pane-body .kv div{padding:10px 12px;border:1px solid var(--pane-field-line);border-radius:10px;background:var(--pane-field);min-width:0}
.pane-body .kv small{display:block;margin-bottom:4px;color:var(--muted);font-size:10px;text-transform:uppercase;letter-spacing:.08em}
.pane-body .kv strong{display:block;overflow:hidden;text-overflow:ellipsis;font-size:12.5px;font-weight:500;white-space:nowrap}
.pane-body .kv strong.no{color:var(--muted);font-style:italic;font-weight:400}

/* ---- Rights ---- */
.pane-body .empty{margin-top:10px;padding:17px;border:1px solid var(--pane-field-line);border-radius:14px;background:var(--pane-field)}
.pane-body .empty>span{color:var(--pane-accent);font-size:10px;letter-spacing:.12em;text-transform:uppercase}
.pane-body .empty h4{margin:10px 0 7px;font-family:var(--display);font-weight:800;font-size:25px;letter-spacing:-.02em}
.pane-body .empty p{margin:0;color:var(--muted);font-size:12.5px;line-height:1.5}
.pane-body .actions{display:flex;gap:8px;margin-top:16px;flex-wrap:wrap}
.pane-body .actions button{min-height:38px;padding:0 14px;border:1px solid var(--line);border-radius:999px;
  background:none;color:var(--ink);font:inherit;font-size:12px;cursor:pointer}
.pane-body .actions button:hover{border-color:var(--muted)}
.pane-body .actions .primary{background:var(--ink);border-color:var(--ink);color:var(--page)}
.pane-body .invite-form{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.pane-body .invite-email{flex:1 1 200px;min-height:38px;padding:10px 12px;border:1px solid var(--pane-field-line);
  border-radius:999px;background:var(--page);color:var(--ink);font:inherit;font-size:13px}
.pane-body .invite-link{width:100%;margin:10px 0 4px;padding:10px 12px;border:1px solid var(--pane-field-line);
  border-radius:10px;background:var(--page);color:var(--ink);font:inherit;font-size:12px}
.pane-body .invite-email:focus,.pane-body .invite-link:focus{outline:2px solid var(--focus-ring);outline-offset:1px}

/* ---- splits overview (Rights tab). Prefixed so- throughout so it never
   collides with the row/who/actions/empty classes above, which the rest of
   the pane still uses. A BMI-repertoire layout: the record on top, then one
   Master box next to one Composition box per song. ---- */
:is(.pane-body,.mg-body) .so-flag{display:block;color:var(--pane-warn, #8a5a00);font-size:11px;line-height:1.3}
:is(.pane-body,.mg-body) .so-wrap{margin-top:6px}
:is(.pane-body,.mg-body) .so-loading,:is(.pane-body,.mg-body) .so-error{margin:0;padding:16px;border:1px solid var(--pane-field-line);border-radius:14px;background:var(--pane-field);color:var(--muted);font-size:12.5px}
:is(.pane-body,.mg-body) .so-error{color:var(--pane-no)}

:is(.pane-body,.mg-body) .so-album{display:flex;gap:13px;align-items:center;margin:2px 0 14px;min-width:0}
:is(.pane-body,.mg-body) .so-cover{width:60px;height:60px;border-radius:10px;flex:none;object-fit:cover;background:var(--pane-field);border:1px solid var(--pane-field-line)}
:is(.pane-body,.mg-body) .so-cover-ph{display:grid;place-items:center;font-family:var(--display);font-weight:800;font-size:14px;letter-spacing:.03em;color:var(--pane-accent)}
:is(.pane-body,.mg-body) .so-album h3{margin:0 0 2px;font-family:var(--display);font-weight:800;font-size:18px;letter-spacing:-.02em;color:var(--ink)}
:is(.pane-body,.mg-body) .so-sub{margin:0;font-size:12px;color:var(--muted)}
:is(.pane-body,.mg-body) .so-count{margin:4px 0 0;font-size:12px;color:var(--muted)}
:is(.pane-body,.mg-body) .so-legend-row{display:block;margin-top:6px;line-height:1.7}
:is(.pane-body,.mg-body) .so-legend{display:inline-flex;align-items:center;gap:4px;margin-right:10px;font-size:10.5px;color:var(--muted)}
:is(.pane-body,.mg-body) .so-legend .so-mk{position:static;border:0;width:10px;height:10px}
:is(.pane-body,.mg-body) .so-legend .so-mk-wait{border:1.5px solid var(--pane-field-line)}
:is(.pane-body,.mg-body) .so-legend .so-mk-inv{border:1.5px dashed var(--pane-warn)}

:is(.pane-body,.mg-body) .so-song{border-top:1px solid var(--line);padding:14px 0 4px}
:is(.pane-body,.mg-body) .so-song-head{display:flex;align-items:center;gap:8px;margin:0 0 10px}
:is(.pane-body,.mg-body) .so-tn{color:var(--muted);font-size:12px;width:16px;flex:none;font-variant-numeric:tabular-nums}
:is(.pane-body,.mg-body) .so-t{font-size:14.5px;font-weight:700;letter-spacing:-.01em;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
:is(.pane-body,.mg-body) .so-chip{margin-left:auto;flex:none;font-size:10.5px;font-weight:600;padding:3px 9px;border-radius:999px;border:1px solid var(--line);white-space:nowrap;color:var(--muted)}
:is(.pane-body,.mg-body) .so-chip-ok{color:var(--pane-ok);border-color:var(--pane-ok)}
:is(.pane-body,.mg-body) .so-chip-warn{color:var(--pane-warn);border-color:var(--pane-warn)}
:is(.pane-body,.mg-body) .so-chip-no{color:var(--pane-no);border-color:var(--pane-no)}

:is(.pane-body,.mg-body) .so-boxes{display:grid;grid-template-columns:1fr 1fr;gap:8px;min-width:0}
:is(.pane-body,.mg-body) .so-box{border:1px solid var(--pane-field-line);border-radius:12px;padding:10px 8px;display:flex;flex-direction:column;min-width:0}
:is(.pane-body,.mg-body) .so-box-h{margin:0;font-size:10px;font-weight:700;letter-spacing:.11em;text-transform:uppercase;color:var(--ink)}
:is(.pane-body,.mg-body) .so-box-s{margin:0 0 6px;font-size:10.5px;color:var(--muted)}
:is(.pane-body,.mg-body) .so-empty{border-style:dashed;justify-content:center;align-items:center;text-align:center;color:var(--muted);min-height:76px;gap:3px}
:is(.pane-body,.mg-body) .so-empty-msg{margin:0;font-size:11.5px}
:is(.pane-body,.mg-body) .so-empty-note{margin:2px 0 0;font-size:10.5px;color:var(--muted)}

/* ---- the record's one screen: per song, the people and their roles (as a
   film's credits roll), then that song's splits. rc- so it never collides
   with the so- overview it borrows the song heading and the boxes from. ---- */
.pane-body .rc-song:first-child{border-top:0;padding-top:6px}
/* A credit line is the picture, the name, the role(s) — the owner's reference
   is the shelf's badge: name bold, role under it in the muted weight. */
/* Sized like the splits rows (the owner: "small just like how you had it on
   the splits page"): a 24px picture, a 12.5px name. */
.pane-body .rc-people .row{grid-template-columns:24px minmax(0,1fr);gap:8px;padding:7px 0;border-top:1px solid var(--line)}
.pane-body .rc-people .row:first-child{border-top:0}
.pane-body .rc-people .avatar{width:24px;height:24px;font-size:9.5px;border:0}
/* Just the picture, no ring round it (the owner, 2026-10-01). Initials keep
   their soft fill so the letters have something to sit on. */
.pane-body .rc-people img.avatar{background:none}
/* A name is a link to that person's page; the anchor takes no box of its own
   so the picture and the name stay in the row's two columns. */
.pane-body .rc-who{display:contents;color:inherit;text-decoration:none}
.pane-body .rc-who .who{text-decoration:underline;text-decoration-color:transparent;text-underline-offset:3px;transition:text-decoration-color .15s}
@media (hover:hover){.pane-body .rc-who:hover .who{text-decoration-color:currentColor}}
.pane-body .rc-people .row .who{font-size:12.5px;font-weight:700;letter-spacing:0;line-height:1.2}
.pane-body .rc-people .row .sub{margin-top:1px;font-size:12px;font-weight:600;color:var(--muted);line-height:1.3}
.pane-body .rc-people .row .flag{margin-top:2px;font-size:11px;line-height:1.3}
.pane-body .rc-people .row .flag.warn{color:var(--pane-warn)}
.pane-body .rc-people .row .flag.no{color:var(--pane-no);font-style:italic}
.pane-body .rc-song .so-chip:empty{display:none}
.pane-body .rc-splits{margin:10px 0 8px}
.pane-body .rc-record .so-song-head{margin-bottom:2px}
.pane-body .credit-note{margin-top:22px}
/* LISTEN / BUY, above the Credits heading (record-panes.js linksRow): small
   pills that float on the scene like the rest of this screen — the veil's
   own ink and hairline, no card. Drawn only when the record has links, so a
   record without them looks exactly as it did. */
.pane-body .rc-links{display:flex;flex-wrap:wrap;gap:6px;margin:18px 0 0}
.pane-body .rc-link{display:inline-flex;align-items:center;padding:6px 11px;border:1px solid var(--line);border-radius:999px;
  background:var(--pane-field);color:var(--ink);font-size:11.5px;font-weight:600;line-height:1.1;text-decoration:none;white-space:nowrap;
  transition:border-color .2s var(--ease),background .2s var(--ease)}
.pane-body .rc-link:hover,.pane-body .rc-link:focus-visible{border-color:var(--muted)}
.pane-body .rc-link:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}
.pane-body .rc-links+.credit-heading{margin-top:16px}
/* A fingertip, not a cursor: taller pills, same row. */
@media (pointer:coarse){.pane-body .rc-link{padding:9px 13px}}

/* ---- the record's text floats on the scene: no card (the owner, 2026-10-01:
   "take out the menu box, the text should be floating"). The specimen page
   keeps its card — this file loads for the product only. The scroll region
   stays, fading at both ends so text slides out rather than cutting off. ---- */
/* With no card, the scene behind has to carry the type: a deeper, blurrier
   veil than the specimen's (JS reads these two), the same in both themes. */
:root,[data-theme="dark"]{--viewer-veil:.9;--viewer-blur:26}
.dialog-content{background:transparent;border:0;box-shadow:none;border-radius:0;
  padding-left:0;padding-right:0;padding-top:22px;padding-bottom:22px;
  -webkit-mask-image:linear-gradient(to bottom,transparent,#000 22px,#000 calc(100% - 22px),transparent);
  mask-image:linear-gradient(to bottom,transparent,#000 22px,#000 calc(100% - 22px),transparent);
  /* light on the veil, whichever theme the page is in: the type, the lines,
     the boxes and the buttons all read these */
  color:var(--on-veil);
  --ink:var(--on-veil);--muted:color-mix(in srgb,var(--on-veil) 55%,transparent);
  --line:color-mix(in srgb,var(--on-veil) 14%,transparent);--page:rgb(var(--veil-rgb));
  --pane-field:color-mix(in srgb,var(--on-veil) 6%,transparent);--pane-field-line:color-mix(in srgb,var(--on-veil) 16%,transparent);
  /* the dark theme's accent and states, since the veil is dark in both themes;
     a problem is red here too (5.2:1 or better on the veil over a white cover) */
  --accent:var(--dark-accent);--ok:#6fcf8a;--warn:var(--dark-warn);--no:#ef7d72;
  /* the aliases, again: they resolve where they are declared, and this
     subtree has its own --ink and --page */
  --pane-accent:var(--accent);--pane-ok:var(--ok);--pane-on-ok:var(--black);--pane-warn:var(--warn);--pane-no:var(--no);
  --on-accent:var(--page);--face-bg:color-mix(in srgb,var(--ink) 12%,transparent);--face-ink:var(--ink)}
/* The focus ring on the veil: the light theme's deep accent is too dark there,
   so the record screen (Close included) takes the dark accent in both themes. */
.record-dialog{--focus-ring:var(--dark-accent)}
.dialog-content .credit-heading{margin-top:22px}
/* On a phone the text column, the counter and Close line up with the cover's
   own edges (the owner: "make it line up with the cover"). The viewer writes
   --art-left / --art-width on the dialog each time it aims the cover. */
@media (max-width:760px){
  .dialog-content{left:var(--art-left,16px);width:var(--art-width,calc(100% - 32px));right:auto;max-height:44dvh}
  .dialog-close{right:calc(100% - var(--art-left,16px) - var(--art-width,calc(100% - 32px)))}
}
/* the counter, pinned to the top-left of the screen, level with Close */
.dialog-index.pinned{left:max(24px,env(safe-area-inset-left));top:calc(max(18px,env(safe-area-inset-top)) + 16px);z-index:8;font-size:.8125rem}
@media (max-width:760px){
  .dialog-index.pinned{left:var(--art-left,16px);top:calc(max(10px,env(safe-area-inset-top)) + 15px)}
}

:is(.pane-body,.mg-body) .so-ppl{list-style:none;margin:0;padding:0}
:is(.pane-body,.mg-body) .so-ppl li{display:flex;align-items:center;gap:6px;padding:5px 0;border-top:1px solid var(--line);min-width:0}
:is(.pane-body,.mg-body) .so-ppl li:first-child{border-top:0}
:is(.pane-body,.mg-body) .so-p.so-me{background:var(--pane-field);border-radius:8px;margin:0 -4px;padding:5px 4px;border-top-color:transparent}
:is(.pane-body,.mg-body) .so-p.so-me+li{border-top-color:transparent}

:is(.pane-body,.mg-body) .so-avw{position:relative;flex:none;display:inline-flex}
:is(.pane-body,.mg-body) .so-av{width:23px;height:23px;border-radius:50%;flex:none;display:grid;place-items:center;font-size:9.5px;font-weight:700;color:#fff;object-fit:cover}
:is(.pane-body,.mg-body) .so-mk{position:absolute;right:-3px;bottom:-2px;width:13px;height:13px;border-radius:50%;border:2px solid var(--page);display:grid;place-items:center;font-size:8px;font-weight:800;color:#fff;line-height:1}
:is(.pane-body,.mg-body) .so-mk-ok{background:var(--pane-ok);color:var(--pane-on-ok)}
/* the ! in the tick's ink: dark on the dark theme's light red (7.4:1), white
   on the light theme's deep red (6.5:1); white on #ef7d72 was 2.7:1 */
:is(.pane-body,.mg-body) .so-mk-no{background:var(--pane-no);color:var(--pane-on-ok)}
:is(.pane-body,.mg-body) .so-mk-wait{background:var(--page);border:2px solid var(--pane-field-line);width:12px;height:12px}
:is(.pane-body,.mg-body) .so-mk-inv{background:var(--page);border:2px dashed var(--pane-warn);width:12px;height:12px}

:is(.pane-body,.mg-body) .so-who{flex:1;min-width:0;line-height:1.2}
:is(.pane-body,.mg-body) .so-who b{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12px;font-weight:600;overflow:hidden;overflow-wrap:break-word;color:var(--ink)}
:is(.pane-body,.mg-body) .so-who small{display:block;font-size:10px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
:is(.pane-body,.mg-body) .so-pct{font-weight:700;font-size:12px;font-variant-numeric:tabular-nums;color:var(--ink);flex:none}

:is(.pane-body,.mg-body) .so-tot{display:flex;justify-content:space-between;border-top:1px solid var(--ink);padding-top:6px;margin-top:4px;font-weight:700;font-size:12px;color:var(--ink)}
:is(.pane-body,.mg-body) .so-meta{margin:5px 0 0;font-size:10px;color:var(--muted)}

:is(.pane-body,.mg-body) .so-act{margin-top:auto;padding-top:9px;display:flex;flex-direction:column;gap:6px}
:is(.pane-body,.mg-body) .so-say{margin:0;font-size:11px;font-weight:600}
:is(.pane-body,.mg-body) .so-say-ok{color:var(--pane-ok)}
:is(.pane-body,.mg-body) .so-say-dim{color:var(--muted);font-weight:500}
:is(.pane-body,.mg-body) .so-btn2{padding:8px 8px;font-size:11.5px;width:100%;border:1px solid var(--line);border-radius:999px;background:none;color:var(--ink);font:inherit;cursor:pointer}
:is(.pane-body,.mg-body) .so-btn2:hover{border-color:var(--muted)}

:is(.pane-body,.mg-body) .so-notepanel{margin-top:2px;padding:9px 10px;border:1px solid var(--pane-field-line);border-radius:12px;background:var(--pane-field)}

:is(.pane-body,.mg-body) .so-invite{display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap;margin:10px 0 0;padding:9px 11px;border-radius:12px;background:var(--pane-field);font-size:12px;color:var(--pane-warn);font-weight:600}
:is(.pane-body,.mg-body) .so-invite button{padding:7px 11px;font-size:11px;flex:none;border:1px solid var(--pane-warn);border-radius:999px;background:none;color:var(--pane-warn);font:inherit;cursor:pointer}
:is(.pane-body,.mg-body) .so-invite-email-input{flex:1 1 160px;min-width:0;min-height:34px;padding:7px 10px;border:1px solid var(--pane-field-line);border-radius:999px;background:var(--page);color:var(--ink);font:inherit;font-size:13px}
:is(.pane-body,.mg-body) .so-invite-link{display:flex;gap:8px;align-items:center;margin:6px 0 0}
:is(.pane-body,.mg-body) .so-invite-link-input{flex:1;min-width:0;padding:8px 10px;border:1px solid var(--pane-field-line);border-radius:10px;background:var(--page);color:var(--ink);font:inherit;font-size:11px}
:is(.pane-body,.mg-body) .so-err{margin:6px 0 0;font-size:11px;color:var(--pane-no)}

:is(.pane-body,.mg-body) .so-panel{margin-top:12px;border:1.5px solid var(--ink);border-radius:14px;padding:13px 13px 11px}
:is(.pane-body,.mg-body) .so-panel h4{margin:0 0 4px;font-size:14px;color:var(--ink)}
:is(.pane-body,.mg-body) .so-faint{margin:0 0 8px;font-size:11.5px;color:var(--muted)}
:is(.pane-body,.mg-body) .so-quote{margin:8px 0;padding:8px 11px;border-left:3px solid var(--line);color:var(--ink);font-size:13px}

:is(.pane-body,.mg-body) .so-slide{padding:9px 0 5px;border-top:1px solid var(--line)}
:is(.pane-body,.mg-body) .so-slide:first-of-type{border-top:0}
:is(.pane-body,.mg-body) .so-slide-top{display:flex;align-items:center;gap:9px}
:is(.pane-body,.mg-body) .so-slide input[type=range]{width:100%;margin:7px 0 0;accent-color:var(--ink)}
:is(.pane-body,.mg-body) .so-num{display:flex;align-items:center;gap:2px;font-weight:700;color:var(--ink);flex:none}
:is(.pane-body,.mg-body) .so-num input{width:64px;padding:7px 7px;text-align:right;font-weight:700;border-radius:10px;border:1px solid var(--pane-field-line);background:var(--page);color:var(--ink);font:inherit;font-size:12.5px}

:is(.pane-body,.mg-body) .so-sumbar{display:flex;justify-content:space-between;align-items:center;margin:8px 0 4px;padding:9px 11px;border-radius:10px;font-weight:700;font-size:13px}
:is(.pane-body,.mg-body) .so-sumbar-ok{background:rgba(29,122,58,.08);color:var(--pane-ok)}
:is(.pane-body,.mg-body) .so-sumbar-bad{background:rgba(179,38,30,.07);color:var(--pane-no)}

:is(.pane-body,.mg-body) .so-cmp{width:100%;border-collapse:collapse;font-size:12px;margin:9px 0}
:is(.pane-body,.mg-body) .so-cmp th{font-size:9px;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);text-align:right;font-weight:700;padding:0 0 5px}
:is(.pane-body,.mg-body) .so-cmp th:first-child,:is(.pane-body,.mg-body) .so-cmp td:first-child{text-align:left}
:is(.pane-body,.mg-body) .so-cmp td{padding:6px 0;border-top:1px solid var(--line);text-align:right;font-variant-numeric:tabular-nums;color:var(--ink)}
:is(.pane-body,.mg-body) .so-cmp td .so-who{display:flex;align-items:center;gap:7px}
:is(.pane-body,.mg-body) .so-up{color:var(--pane-ok);font-weight:700}
/* a smaller share is not a problem: muted, not the colour that means one */
:is(.pane-body,.mg-body) .so-down{color:var(--muted);font-weight:700}
:is(.pane-body,.mg-body) .so-same{color:var(--muted)}

:is(.pane-body,.mg-body) .so-btns{display:flex;flex-direction:column;gap:6px;margin-top:6px}
:is(.pane-body,.mg-body) .so-btns button{padding:9px 10px;font-size:12.5px;width:100%;border:1px solid var(--line);border-radius:999px;background:none;color:var(--ink);font:inherit;cursor:pointer}
:is(.pane-body,.mg-body) .so-btns button.primary{background:var(--ink);border-color:var(--ink);color:var(--page);font-weight:600}
:is(.pane-body,.mg-body) .so-btns button.so-quiet{color:var(--muted)}
:is(.pane-body,.mg-body) .so-btns button:disabled{opacity:.5;cursor:default}

:is(.pane-body,.mg-body) .so-note{margin:8px 0 0;font-size:10.5px;color:var(--muted);line-height:1.4}

/* ---- Evidence ---- */
.pane-body .checks div{display:flex;gap:12px;align-items:center;padding:9px 0;border-top:1px solid var(--line);font-size:13.5px}
.pane-body .checks div:first-child{border-top:0}
.pane-body .checks i{width:18px;height:18px;border-radius:50%;border:1px solid var(--line);display:grid;place-items:center;
  font-style:normal;font-size:11px;color:var(--pane-ok);flex:none}
.pane-body .checks i.no{color:var(--muted)}
.pane-body .checks span{flex:1}
.pane-body .checks small{color:var(--muted);font-size:11px}

.pane-body .note{margin-top:14px;font-size:12.5px;color:var(--muted);line-height:1.5}
.pane-body .note a{color:var(--ink)}

@media (max-width:760px){
  .pane-tabs{margin-top:18px;gap:14px}
  .pane-body .kv{grid-template-columns:1fr}
  .pane-body .row{grid-template-columns:32px minmax(0,1fr) auto;gap:10px}
  .pane-body .invite-email{font-size:16px}   /* under 16px iOS zooms the page on focus */
  :is(.pane-body,.mg-body) .so-invite-email-input,:is(.pane-body,.mg-body) .so-num input{font-size:16px}
}

/* Two boxes fit side by side down to 351px; below that they stack, so a
   split never gets cut off on the narrowest phones the owner reads on. */
@media (max-width:350px){
  :is(.pane-body,.mg-body) .so-boxes{grid-template-columns:1fr}
}

/* ================= step 3: Manage, the owner's workspace =================
 * The original app's Manage screen ported onto the shelf's tokens. It is not
 * a catalogue view: while it is open the shelf and the gallery are put away
 * and the mode switch goes with them, because there is nothing to switch
 * between. The wordmark, the theme control and the Manage action stay, so the
 * shell never changes under the owner.
 */
.manage-toggle{position:relative;cursor:pointer;white-space:nowrap;
  transition:color .2s var(--ease),border-color .2s var(--ease)}
/* its size, hairline, ground and type: QUIET PILL, FLOATING and ROUND, at
   the end of this file */
.manage-icon{display:none}
/* How many requests wait on the owner, from anywhere on the shelf. Drawn only
   while there is one; the number is also in the button's label, for a screen
   reader. The ring keeps it apart from whatever the header sits over. */
.manage-dot{position:absolute;top:-6px;right:-6px;box-sizing:border-box;min-width:17px;height:17px;padding:0 4px;
  border-radius:999px;box-shadow:0 0 0 2px var(--page);
  font-size:10px;font-weight:700;line-height:17px;letter-spacing:0;text-align:center;pointer-events:none}
/* its fill and its number: the PRIMARY recipe, at the end of this file */
/* Browsing modes mean nothing in a workspace. */
body.is-managing .mode-switch{display:none}
/* In Manage the list scrolls under the fixed header, and the wordmark sat on
   top of record rows (owner's phone, 2026-09-30). Here — a workspace, with no
   dive to keep light — the header gets a ground. */
body.is-managing .site-header{background:color-mix(in srgb, var(--page) 86%, transparent);
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}

.manage-workspace{padding:22px var(--pad-r) 64px var(--pad-l);min-height:100svh}
.manage-workspace[hidden]{display:none}
.manage-head{display:flex;align-items:center;gap:14px;margin-bottom:18px;flex-wrap:wrap}
.manage-head input{flex:1;min-width:0;padding:12px 16px;border:1px solid var(--line);border-radius:999px;
  background:var(--pane-field);color:var(--ink);font:inherit;font-size:16px}
.manage-head input::placeholder{color:var(--muted)}
.manage-head input:focus{outline:2px solid var(--focus-ring);outline-offset:1px;border-color:transparent}
.manage-count{flex:none;font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.fix-btn{flex:none;padding:11px 15px;border:1px solid var(--line);border-radius:999px;background:none;
  color:var(--muted);font:inherit;font-size:12px;cursor:pointer;white-space:nowrap}
.fix-btn:hover{color:var(--ink);border-color:var(--muted)}
/* Adding a record is the one action in Manage that creates something rather
   than correcting something, so it is the one that leads. */
.fix-btn.primary{background:var(--ink);border-color:var(--ink);color:var(--page);font-weight:600}
.fix-btn.primary:hover{color:var(--page);border-color:var(--ink);opacity:.88}
.mg-views{flex:none;display:inline-flex;border:1px solid var(--line);border-radius:999px;overflow:hidden}
.mg-views button{padding:10px 15px;border:0;background:none;color:var(--muted);font:inherit;font-size:12px;cursor:pointer}
.mg-views button.on{background:var(--ink);color:var(--page);font-weight:600}

/* ---- the list ---- */
.mg-year{margin:26px 0 10px;font-family:var(--display);font-weight:800;font-size:26px;letter-spacing:-.02em;color:var(--muted)}
.mg-year:first-child{margin-top:0}
.mg-row{display:flex;align-items:center;gap:14px;padding:11px 14px;margin-bottom:8px;border:1px solid var(--line);
  border-radius:16px;background:var(--pane-field);transition:background .2s var(--ease),border-color .2s var(--ease)}
.mg-row:hover{border-color:var(--muted)}
/* A record opens in place: its row, then its songs' splits under it, as
   one card. The row itself is the switch; the arrow says which way. */
.mg-listbar{display:flex;justify-content:flex-end;margin:-6px 0 8px}
.mg-foldall{padding:7px 13px;border:1px solid var(--line);border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:12px;cursor:pointer}
.mg-foldall:hover{color:var(--ink);border-color:var(--muted)}
.mg-row.is-foldable{cursor:pointer}
.mg-fold{flex:none;display:grid;place-items:center;width:32px;height:32px;padding:0;border:0;border-radius:50%;background:none;cursor:pointer}
.mg-fold:hover{background:var(--pane-field)}
.mg-fold .etrack-chev{margin-top:-3px}
.mg-rec.open .mg-fold .etrack-chev{transform:rotate(-135deg);margin-top:3px}
.mg-rec.open .mg-row{margin-bottom:0;border-radius:16px 16px 0 0;border-bottom-color:transparent}
.mg-body{margin-bottom:8px;padding:4px 14px 14px;border:1px solid var(--line);border-top:0;border-radius:0 0 16px 16px;background:var(--pane-field)}
.mg-body .so-song:first-child{margin-top:0}
.mg-row.is-hidden{opacity:.5}
.mg-cover{flex:none;width:52px;height:52px;border-radius:9px;overflow:hidden;background:var(--object-ground);display:grid;place-items:center}
.mg-cover img{width:100%;height:100%;object-fit:cover;display:block}
.mg-cover span{font-size:8px;line-height:1.15;text-align:center;letter-spacing:.06em;color:var(--muted)}
.mg-main{flex:1;min-width:0}
.mg-title{font-family:var(--display);font-weight:800;font-size:18px;line-height:1.15;letter-spacing:-.02em;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mg-sub{margin-top:3px;font-size:11.5px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mg-badge{flex:none;padding:4px 9px;border-radius:999px;font-size:9px;font-weight:700;letter-spacing:.12em;text-transform:uppercase}
.mg-badge.added{color:var(--page);background:var(--pane-accent)}
.mg-badge.edited{color:var(--pane-accent);border:1px solid var(--pane-accent)}
.mg-badge.hidden{color:var(--muted);border:1px solid var(--line)}
.mg-badge.confirmed{color:var(--page);background:var(--pane-ok)}
.mg-badge.dismissed{color:var(--muted);border:1px solid var(--line)}
.mg-acts{flex:none;display:flex;gap:7px}
.mg-acts button{padding:7px 13px;border:1px solid var(--line);border-radius:999px;background:none;color:var(--muted);
  font:inherit;font-size:11.5px;cursor:pointer;transition:color .2s var(--ease),border-color .2s var(--ease)}
.mg-acts button:hover{color:var(--ink);border-color:var(--muted)}
.mg-acts button.danger:hover{color:var(--pane-no);border-color:var(--pane-no)}
.mg-readonly{flex:none;font-size:11px;color:var(--muted)}
.mg-empty{padding:40px 4px;color:var(--muted);font-size:13px}

/* ---- alerts: requests to change a credit, waiting on answers ---- */
.al-sec{margin-bottom:26px}
.al-h{margin:0 0 10px;font-size:10px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:var(--muted)}
.al-h span{margin-left:4px;color:var(--ink)}
.al-list{list-style:none;margin:0;padding:0}
.al-card{margin-bottom:8px;padding:13px 14px 12px;border:1px solid var(--line);border-radius:16px;background:var(--pane-field)}
.al-card.is-closed{opacity:.8}
.al-top{display:flex;align-items:flex-start;gap:14px}
.al-main{flex:1;min-width:0}
.al-what{margin:0;font-size:13.5px;line-height:1.4;color:var(--muted);overflow-wrap:anywhere}
.al-what b{font-weight:700;color:var(--ink)}
.al-roles{margin:6px 0 0;font-size:13px;line-height:1.4;color:var(--muted);overflow-wrap:anywhere}
.al-roles i{font-style:normal;margin:0 2px}
.al-roles .al-to{font-weight:600;color:var(--ink)}
.al-note{margin:7px 0 0;font-size:12.5px;line-height:1.4;color:var(--ink);overflow-wrap:anywhere}
.al-meta{margin:6px 0 0;font-size:11px;color:var(--muted)}
.al-appr{list-style:none;display:flex;flex-wrap:wrap;gap:6px 18px;margin:11px 0 0;padding:10px 0 0;border-top:1px solid var(--line)}
.al-a{display:flex;flex-wrap:wrap;align-items:center;gap:6px;min-width:0;font-size:12px;color:var(--ink)}
.al-a-wait .al-who{color:var(--muted)}
.al-mk{flex:none;display:inline-grid;place-items:center;box-sizing:border-box;width:15px;height:15px;border-radius:50%;
  font-style:normal;font-size:9px;font-weight:800;line-height:1;color:var(--page)}
.al-mk-ok{background:var(--pane-ok)}
.al-mk-no{background:var(--pane-no)}
.al-mk-wait{border:1.5px solid var(--muted);background:none}
.al-say{flex-basis:100%;padding-left:21px;font-size:11.5px;line-height:1.35;color:var(--muted);overflow-wrap:anywhere}
.al-wait{margin:8px 0 0;font-size:11.5px;color:var(--pane-warn)}
.al-acts{display:flex;gap:8px;margin-top:12px}
.al-acts .fix-btn{flex:1 1 0;max-width:180px}
.al-decline{margin-top:12px}
.al-decline input{display:block;width:100%;box-sizing:border-box;padding:11px 14px;border:1px solid var(--line);border-radius:12px;
  background:var(--page);color:var(--ink);font:inherit;font-size:16px}
.al-decline input::placeholder{color:var(--muted)}
.al-decline input:focus{outline:2px solid var(--focus-ring);outline-offset:1px;border-color:transparent}
.al-decline .al-acts{margin-top:8px}
.al-end{margin:12px 0 0;font-size:12px;font-weight:600;color:var(--muted)}
.al-end small{margin-left:6px;font-size:11px;font-weight:400}
.al-end-applied{color:var(--pane-ok)}
.al-empty{max-width:46ch;padding:40px 4px;font-size:13px;line-height:1.5;color:var(--muted)}
.al-clear{margin:0 0 24px;padding:2px 4px;font-size:13px;color:var(--muted)}
.al-stale{margin:0;font-size:11.5px;color:var(--pane-warn)}

/* ---- the spreadsheet. The ONE place a sideways scroll is deliberate: the
   columns carry real widths and squeezing them would make the grid unusable. */
/* svh, not vh, everywhere a box has to FIT the screen. Bare vh is the
   viewport at its TALLEST — the state a phone is in only once the URL bar
   has retracted — so a sheet sized in vh is taller than the screen it is
   sitting on for as long as that bar is showing, and its bottom edge (which
   is where the Save button lives) is off the bottom. */
.tbl-wrap{overflow:auto;max-height:66svh;border:1px solid var(--line);border-radius:14px;-webkit-overflow-scrolling:touch}
/* The spreadsheet already has its own scroller, .tbl-wrap, and one is enough:
   measured on a 390px phone it scrolls to 356 of 720 and every column from
   Record to Date is reachable. A second scroller on #manageTable around it
   would only give the same gesture two things to fight over. */
table.grid{border-collapse:separate;border-spacing:0;width:100%;font-size:12.5px}
table.grid th{position:sticky;top:0;z-index:2;padding:10px 9px;text-align:left;white-space:nowrap;background:var(--page);
  border-bottom:1px solid var(--line);font-size:9.5px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
table.grid td{padding:0;border-bottom:1px solid var(--line);vertical-align:middle}
table.grid tr:last-child td{border-bottom:0}
table.grid tr.newrec td{border-top:1px solid var(--muted)}
table.grid td.n{padding:0 9px;color:var(--muted);font-size:10.5px;text-align:right;width:34px}
table.grid td.ro{padding:0 9px;color:var(--muted);font-size:10.5px;white-space:nowrap}
table.grid input,table.grid select{width:100%;padding:9px;border:0;background:none;color:var(--ink);font:inherit;font-size:12.5px;min-width:0}
table.grid input:focus,table.grid select:focus{outline:2px solid var(--focus-ring);outline-offset:-2px;background:var(--pane-field)}
table.grid select option{background:var(--page);color:var(--ink)}
table.grid td.dirty input,table.grid td.dirty select{background:var(--pane-field);color:var(--ink);box-shadow:inset 2px 0 0 var(--pane-accent)}
table.grid tr.is-hidden{opacity:.45}
.tbl-bar{position:sticky;bottom:0;display:flex;align-items:center;gap:10px;margin-top:14px;padding:12px 4px;background:var(--page)}
.tbl-bar span{flex:1;font-size:12px;color:var(--pane-accent)}
.tbl-bar button{padding:10px 17px;border:1px solid var(--line);border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:12.5px;cursor:pointer}
.tbl-bar button:hover{color:var(--ink);border-color:var(--muted)}
.tbl-bar button.primary{background:var(--ink);border-color:var(--ink);color:var(--page);font-weight:600}
.tbl-bar button[disabled]{opacity:.4;cursor:default}

/* ---- fix everywhere ---- */
.fx-group{margin-bottom:22px}
.fx-group h4{margin:0 0 9px;font-size:10px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:var(--muted)}
.fx-row{display:flex;align-items:center;gap:12px;padding:10px 13px;margin-bottom:7px;border:1px solid var(--line);border-radius:13px;flex-wrap:wrap}
.fx-name{flex:1;min-width:0;font-family:var(--display);font-weight:800;font-size:17px;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fx-n{flex:none;font-size:11px;color:var(--muted)}
.fx-row button{flex:none;padding:7px 13px;border:1px solid var(--line);border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:11.5px;cursor:pointer}
.fx-row button:hover{color:var(--ink);border-color:var(--muted)}
.fx-row button.primary{background:var(--ink);border-color:var(--ink);color:var(--page);font-weight:600}
.fx-edit{display:flex;gap:8px;width:100%;flex-wrap:wrap;align-items:center}
.fx-edit input{flex:1;min-width:150px;padding:9px 12px;border:1px solid var(--line);border-radius:10px;background:var(--pane-field);color:var(--ink);font:inherit;font-size:16px}
.fx-edit input:focus{outline:2px solid var(--focus-ring);outline-offset:1px}
.fx-impact{width:100%;font-size:11.5px;color:var(--pane-accent)}

/* ---- the record editor and Fix-everywhere sheets ---- */
.edit-veil{position:fixed;inset:0;z-index:80;background:rgba(var(--veil-rgb),.62);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.edit-veil[hidden],.edit-sheet[hidden]{display:none}
.edit-sheet{position:fixed;z-index:81;left:50%;top:50%;transform:translate(-50%,-50%);width:min(680px,92vw);max-height:88svh;
  overflow:auto;padding:24px;border:1px solid var(--panel-line);border-radius:22px;background:var(--panel-bg);
  color:var(--ink);box-shadow:var(--panel-shadow)}
.edit-sheet h3{margin:0 0 3px;font-family:var(--display);font-weight:800;font-size:26px;letter-spacing:-.02em;color:var(--ink)}
.edit-sheet .eid{margin:0 0 18px;font-size:11px;color:var(--muted);word-break:break-all}
.ef{display:flex;flex-direction:column;gap:6px;min-width:0}
.ef.wide{grid-column:1/-1}
.ef label{font-size:10px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:var(--muted)}
.ef input,.ef select{padding:10px 12px;border:1px solid var(--line);border-radius:10px;background:var(--pane-field);color:var(--ink);font:inherit;font-size:16px;min-width:0}
.ef input:focus,.ef select:focus{outline:2px solid var(--focus-ring);outline-offset:1px;border-color:transparent}
.ef select option{background:var(--page);color:var(--ink)}
.edit-foot{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.edit-foot .grow{flex:1}
.edit-foot button{padding:11px 18px;border:1px solid var(--line);border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:13px;cursor:pointer}
.edit-foot button:hover{color:var(--ink);border-color:var(--muted)}
.edit-foot button.primary{background:var(--ink);border-color:var(--ink);color:var(--page);font-weight:600}
.edit-note{margin:14px 0 0;font-size:11.5px;line-height:1.5;color:var(--muted)}

/* ---- phones: a full-width workspace. Forms must not scroll sideways; the
   spreadsheet is the deliberate exception and keeps its real column widths. */
@media (max-width:760px){
  /* At phone widths the approved header is already full: wordmark, the
     three-view switch and the theme control fill the row exactly. A fourth
     labelled control does not fit — it overflowed the page by 41px — so
     Manage takes the theme control's shape and gives the switch its position
     back, which is the part of the composition that matters. */
  .manage-toggle{display:grid;place-items:center}
  /* Out of the layout, not squeezed to a 1px box that still clips its text. */
  .manage-word{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
  /* The pencil: a 16px line drawing in the button's own colour (home.html),
     so it is as crisp as the theme control's glyph and follows the pressed
     state's colour by itself. */
  .manage-icon{display:block;width:16px;height:16px}
  .manage-icon svg{display:block;width:16px;height:16px}
  .manage-workspace{padding-top:14px}
  .manage-head{gap:9px}
  .fix-btn,.mg-views{width:100%}
  /* Five tabs since Alerts, and "Alerts · 2" is the widest: less padding each
     so they still fit a 375px screen edge to edge. */
  .mg-views button{flex:1;padding:10px 6px}
  .manage-dot{top:-5px;right:-5px;min-width:15px;height:15px;font-size:10px;line-height:15px}
  /* While the dot shows, the pencil steps 2px away from it (down and left),
     so the dot's ring does not cut off its tip; whole pixels keep it crisp.
     With nothing waiting it stays centred. */
  .manage-toggle[data-waiting] .manage-icon svg{translate:-2px 2px}
  .al-card{padding:11px 11px 10px}
  .al-top{gap:10px}
  .al-acts .fix-btn{max-width:none}
  .mg-row{gap:10px;padding:9px 11px;flex-wrap:wrap}
  .mg-cover{width:44px;height:44px}
  .mg-title{font-size:16px}
  .mg-acts{width:100%;justify-content:flex-end}
  .mg-body{padding:4px 11px 12px}
  .tbl-wrap{max-height:60svh}
  table.grid{min-width:760px}
  .edit-sheet{width:96vw;max-height:92svh;padding:16px;border-radius:18px}
  .fx-row{gap:8px}
}

/* ================= the version switcher =================
 * Ported from the original app's pill under the carousel. It sits in the
 * record's identity block, under the facts line, and only two of the 29
 * records have anything to show — the container collapses for the rest, so
 * the approved readout is unchanged everywhere else.
 *
 * The original centred its menu above the pill because the pill sat at the
 * bottom of the page. Here the identity block is left-aligned with the
 * readout below it, so the menu hangs from the pill instead.
 */
.version-switch{margin-top:12px}
.version-switch:empty{display:none}
.version-pill-wrap{position:relative;display:inline-block}
.pill{display:inline-flex;align-items:center;gap:7px;padding:8px 13px;border:1px solid var(--line);border-radius:999px;
  background:var(--pane-field);color:var(--muted);font:inherit;font-size:11px;font-weight:600;letter-spacing:.07em;
  text-transform:uppercase;white-space:nowrap;cursor:pointer;
  transition:color .2s var(--ease),border-color .2s var(--ease),background .2s var(--ease)}
.pill:hover,.pill.open{color:var(--ink);border-color:var(--muted)}
.pill b{font-weight:600;color:var(--ink)}
.pill i{width:3px;height:3px;border-radius:50%;background:var(--pane-accent);flex:none}
.pill svg{width:11px;height:11px;fill:none;stroke:currentColor;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round;transition:transform .22s var(--ease)}
.pill.open svg{transform:rotate(180deg)}
.menu{position:absolute;left:0;top:calc(100% + 9px);z-index:20;width:min(300px,calc(100vw - 40px));max-height:280px;
  overflow:auto;padding:6px;border:1px solid var(--panel-line);border-radius:16px;background:var(--panel-bg);
  box-shadow:var(--panel-shadow);opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity .2s var(--ease),transform .2s var(--ease)}
.menu.on{opacity:1;visibility:visible;transform:translateY(0)}
.menu-head{padding:8px 11px 7px;font-size:9.5px;font-weight:700;letter-spacing:.15em;text-transform:uppercase;color:var(--muted)}
.menu-row{display:flex;align-items:baseline;gap:10px;width:100%;padding:9px 11px;border:0;border-radius:11px;
  background:none;text-align:left;color:var(--muted);font:inherit;cursor:pointer;
  transition:background .18s var(--ease),color .18s var(--ease)}
.menu-row:hover{background:var(--object-ground);color:var(--ink)}
.menu-row.on{background:var(--object-ground);color:var(--ink)}
.menu-row .ml{flex:1;min-width:0}
.menu-row .mt{display:block;font-family:var(--display);font-weight:800;font-size:17px;line-height:1.15;letter-spacing:-.02em;
  color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.menu-row .ms{display:block;margin-top:3px;font-size:10px;font-weight:600;letter-spacing:.07em;text-transform:uppercase;color:var(--muted)}
.menu-row .mr{flex:none;font-size:10px;font-weight:600;letter-spacing:.08em;color:var(--muted)}
.menu-row.on .mr{color:var(--pane-accent)}
@media (max-width:760px){
  .version-switch{margin-top:10px}
  .menu{width:min(300px,calc(100vw - 24px))}
}


table.grid td.credited{font-size:12px;line-height:1.4;white-space:normal;min-width:130px}
table.grid td.credited i{font-style:normal;color:var(--muted)}


/* ---- the record wizard: Project (cover, title, date, type; the songs as
   cards, each with its credits and splits), Documents, Review — record
   editor v2, owner-approved 2026-09-25 ------------------------------------ */
.wiz-rail{display:flex;gap:4px;margin:0 0 20px;padding-bottom:12px;overflow-x:auto;border-bottom:1px solid var(--line);scrollbar-width:none}
.wiz-rail::-webkit-scrollbar{display:none}
.wiz-step{display:flex;align-items:center;gap:7px;flex:none;padding:7px 12px 7px 7px;border:1px solid transparent;border-radius:999px;
  background:none;color:var(--muted);font:inherit;font-size:12px;cursor:pointer;white-space:nowrap}
.wiz-step i{display:grid;place-items:center;width:20px;height:20px;border-radius:50%;border:1px solid var(--line);
  font-style:normal;font-size:10.5px;font-weight:700;font-variant-numeric:tabular-nums}
.wiz-step:hover{color:var(--ink)}
.wiz-step.done i{background:var(--pane-ok);border-color:var(--pane-ok);color:var(--pane-on-ok)}
.wiz-step.on{background:var(--pane-field);border-color:var(--line);color:var(--ink);font-weight:600}
.wiz-step.on i{background:var(--ink);border-color:var(--ink);color:var(--page)}
.wiz-body{min-height:220px}
.wiz-head{margin:0 0 18px}
.wiz-head h4{margin:0 0 3px;font-family:var(--display);font-weight:800;font-size:19px;letter-spacing:-.015em;color:var(--ink)}
.wiz-head p{margin:0;font-size:12.5px;line-height:1.5;color:var(--muted)}
/* The nested "Credits & splits" heading, inside the Project step: one size
   down from wiz-head, so the page still reads as one step with sections in
   it, not several stacked steps. */
.wiz-subhead{margin:22px 0 14px;padding-top:18px;border-top:1px solid var(--line)}
.wiz-subhead h4{font-size:15px}

/* The top of Project, as the owner's mockup lays it out (2026-09-25): the
   cover large on the left, the record's facts beside it. The preview shows
   the whole cover in its own shape — contain, never a crop. */
.eproj{display:grid;grid-template-columns:minmax(150px,230px) minmax(0,1fr);gap:20px;align-items:start}
.eproj-art{display:flex;flex-direction:column;gap:10px;min-width:0}
.eproj-prev{aspect-ratio:1/1;width:100%;border:1px solid var(--line);border-radius:16px;overflow:hidden;
  background:var(--object-ground);display:grid;place-items:center}
.eproj-prev img{width:100%;height:100%;object-fit:contain}
.eproj-prev span{font-size:11px;font-weight:700;letter-spacing:.12em;color:var(--muted);text-align:center;line-height:1.4}
.eproj-artbtns{display:flex;flex-wrap:wrap;justify-content:center;gap:8px}
.eproj-artbtns button{padding:8px 14px;border:1px solid var(--line);border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:12px;cursor:pointer}
.eproj-artbtns button:hover{color:var(--ink);border-color:var(--muted)}
.eproj-artbtns button:disabled{cursor:default;opacity:.6}
.eproj-art .ehint{margin:0;text-align:center}
.eproj-fields{display:flex;flex-direction:column;gap:16px;min-width:0}
.eproj-fields .etype{margin-bottom:0}
/* A phone stacks the two; the cover stays centred with its buttons under
   it, at a size that does not push the fields a screen down. */
@media (max-width:560px){
  .eproj{grid-template-columns:1fr;gap:16px}
  .eproj-art{align-items:center}
  .eproj-prev{width:180px}
}
/* A date is picked, not typed: the native field lies invisibly over the box,
   so a tap anywhere opens the picker, and the date shows in words. */
.edate{position:relative;display:flex;align-items:center;gap:10px;min-height:44px;padding:10px 12px;border:1px solid var(--line);
  border-radius:10px;background:var(--pane-field);color:var(--ink);font-size:16px;cursor:pointer}
.edate.is-empty .edate-text{color:var(--muted)}
.edate-text{flex:1;min-width:0}
.edate-cal{flex:none;width:16px;height:15px;border:1.5px solid var(--muted);border-top-width:4px;border-radius:3px}
.edate input[type="date"]{position:absolute;inset:0;width:100%;height:100%;margin:0;padding:0;border:0;opacity:0;cursor:pointer;min-width:0}
.edate:focus-within{outline:2px solid var(--focus-ring);outline-offset:1px;border-color:transparent}

/* record type: live cards for a new record, a settled .as-field row with
   Change for an existing one (reuses .ecredit-top.as-field, below) */
.wiz-type{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.wiz-type button{display:flex;flex-direction:column;gap:3px;padding:14px;border:1px solid var(--line);border-radius:14px;
  background:none;color:var(--muted);font:inherit;text-align:left;cursor:pointer}
.wiz-type button b{font-size:13.5px;color:var(--ink);font-weight:650}
.wiz-type button small{font-size:11.5px}
.wiz-type button.on{border-color:var(--ink);background:var(--pane-field)}
.wiz-type button.on b{font-weight:750}
.etype-kind{margin-top:10px}
.etype-done{margin-top:10px;align-self:flex-start}
/* Change and Done open and close a choice; they are not a removal, so they
   do not turn the removal red. */
.etype .edrop:hover{color:var(--ink);border-color:var(--muted)}
.ehint{margin:8px 0 0;font-size:11.5px;line-height:1.45;color:var(--muted)}

/* THE SONGS. Every song is a card, a Single's too, and every card starts
   closed: its head is the number (on a multi-track project), the title and
   a round button that opens it; below the head a closed card says in one
   line per side who is on it and whether it adds up. Open, it holds the
   song's Master and Composition side by side, then its samples and studio
   credits. */
/* The number column is a fixed width, so the closed card's summary below
   (.esong-sum) can start exactly under the title. */
.etrack-n{flex:none;width:14px;font-size:10px;font-weight:700;color:var(--muted);font-variant-numeric:tabular-nums}
.etrack-chev{flex:none;width:7px;height:7px;border-right:1.5px solid var(--muted);border-bottom:1.5px solid var(--muted);
  transform:rotate(45deg);margin-top:-3px;transition:transform .15s}
.esong{margin-bottom:9px;border:1px solid var(--line);border-radius:14px;overflow:hidden}
.esong-head{display:flex;align-items:center;gap:10px;padding:10px 12px}
.esong.open .esong-head{border-bottom:1px solid var(--line)}
.esong-t{flex:1;min-width:0;display:flex;flex-direction:column}
.esong-t b{font-size:14px;font-weight:650;color:var(--ink);overflow-wrap:anywhere}
.esong-tin{width:100%;min-width:0;padding:6px 9px;border:1px solid var(--line);border-radius:8px;background:var(--pane-field);
  color:var(--ink);font:inherit;font-weight:650;font-size:16px}
.esong-tin:focus{outline:2px solid var(--focus-ring);outline-offset:1px;border-color:transparent}
.esong-tog{flex:none;display:grid;place-items:center;width:32px;height:32px;padding:0;border:1px solid var(--line);border-radius:50%;
  background:none;cursor:pointer}
.esong-tog:hover{border-color:var(--muted)}
.esong.open .esong-tog .etrack-chev{transform:rotate(-135deg);margin-top:3px}
/* The card clips its corners (overflow:hidden), so the keyboard ring is drawn
   inside what it rings, where it cannot be cut off. */
.esong-tog:focus-visible{outline:2px solid var(--focus-ring);outline-offset:-2px}
/* The open card is the container its two boxes measure: the sheet is
   narrower than the screen on a computer and nearly all of it on a phone,
   so the screen's width cannot say whether two boxes fit side by side. */
.esong-body{padding:12px;container-type:inline-size}
.esong-body .drop{margin:14px 0 0;padding:0;border:0;background:none;font:inherit;font-size:11px;color:var(--muted);cursor:pointer}
.esong-body .drop:hover{color:var(--pane-no)}
.esong-body .drop:disabled{cursor:default;opacity:.5}
.esong-day{margin-top:14px;max-width:320px}
.esong-day label{color:var(--pane-warn)}
.esongs-status{margin:-4px 0 12px}

/* a closed card: a line per side — its label, the credit badges, the total */
.esong-sum{display:flex;flex-direction:column;gap:6px;padding:0 12px 11px 36px;cursor:pointer}
/* a Single's head has no number: its title, and so its summary, start at the edge */
.esong.is-single .esong-sum{padding-left:12px}
.esum-row{display:flex;align-items:center;gap:8px;min-width:0}
.esum-l{flex:none;width:86px;font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.esum-t{flex:none;font-size:11.5px;font-weight:700;font-variant-numeric:tabular-nums}
.esum-t.ok{color:var(--pane-ok)}
.esum-t.bad{color:var(--pane-no)}
.esum-t.is-empty{color:var(--muted);font-weight:500}
/* A phone has no room for the label, the badges and the total on one line:
   the label and the total share the first, the badges take the width below,
   so a name wraps between its words rather than letter by letter. */
@media (max-width:560px){
  .esong-sum{padding-left:12px;gap:10px}
  .esum-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:5px 8px}
  .esum-l{width:auto}
  .esum-t{grid-column:2;grid-row:1}
  .esum-row .ebadges{grid-column:1/-1}
}

/* THE CREDIT BADGE: picture or initials, name, role, and the share in bold
   when there is one; faded when the person owns no share of that side. */
.ebadges{flex:1;min-width:0;display:flex;flex-wrap:wrap;gap:4px}
.ebadge{display:inline-flex;align-items:center;gap:5px;max-width:100%;min-width:0;padding:2px 8px 2px 2px;
  border:1px solid var(--line);border-radius:999px;background:var(--pane-field);font-size:11.5px;color:var(--ink)}
.ebadge .eavatar{width:18px;height:18px;font-size:8px}
.ebadge-n{font-weight:600;min-width:0;overflow-wrap:break-word}
.ebadge-r{color:var(--muted);font-size:10.5px;min-width:0;overflow-wrap:break-word}
.ebadge b{font-weight:700;font-variant-numeric:tabular-nums}
.ebadge.is-dim{background:none;color:var(--muted)}
.ebadge.is-dim .ebadge-n{color:var(--muted);font-weight:500}
.ebadge.is-dim .eavatar{opacity:.55}
.ebadge.is-sample{padding-left:8px}
.ebadge-x{flex:none;padding:0 2px;border:0;background:none;color:var(--muted);font:inherit;font-size:13px;line-height:1;cursor:pointer}
.ebadge-x:hover{color:var(--pane-no)}
.eavatar.is-face{overflow:hidden}
.eavatar.is-face img{width:100%;height:100%;object-fit:cover;display:block}

/* THE TWO SIDES of an open song, side by side, stacked on a narrow screen */
.esides{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px}
.esides-note{margin:10px 0 0}
.eside{display:flex;flex-direction:column;min-width:0;padding:12px 10px;border:1px solid var(--line);border-radius:14px}
.eside-h{margin:0 0 8px;font-size:10.5px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--ink)}
.eside-none{margin:2px 0 8px;font-size:12px;color:var(--muted)}
.eside .eside-add{align-self:flex-start;margin-top:8px;padding:6px 11px;font-size:11.5px}
.eside .epicker{margin-top:8px}
.eside-foot{display:flex;align-items:center;flex-wrap:wrap;gap:4px;margin-top:8px;font-size:11px;color:var(--muted)}
/* The day a split takes effect, picked in the footer line, in its words. */
.edate.is-inline{display:inline-flex;min-height:0;padding:2px 8px;gap:6px;border-radius:999px;font-size:11px;color:var(--ink)}
.edate.is-inline .edate-cal{width:11px;height:10px;border-width:1.2px;border-top-width:3px}
/* Side by side only while each box leaves a person's name room to read:
   below this the name column fell to a few pixels and names broke one
   letter per line (430px phones and up to ~580px). */
@container (max-width:560px){.esides{grid-template-columns:1fr}}

/* one person on a side: picture, name, role chips and "+ role", share, × */
.esrow{display:grid;grid-template-columns:26px minmax(0,1fr) auto auto;align-items:center;gap:7px;padding:7px 0;border-top:1px solid var(--line)}
.eside-h+.esrow,.eside-h+.rs-onfile+.esrow,.estudio .ehint+.esrow{border-top:0}
.esrow .eavatar{width:26px;height:26px;font-size:10px}
.esrow.is-dim .eavatar{opacity:.55}
.esrow-who{min-width:0;display:flex;flex-direction:column;gap:3px;line-height:1.2}
.esrow-who b{font-size:13px;font-weight:600;color:var(--ink);overflow-wrap:anywhere}
.esrow.is-dim .esrow-who b{color:var(--muted);font-weight:500}
.esrow-who b i{font-style:normal;font-size:9.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.esrow-roles{display:flex;flex-wrap:wrap;align-items:center;gap:4px}
.esrow-roles small{font-size:10.5px;color:var(--muted)}
.esrow-roles small.is-new{color:var(--pane-warn)}
.echip{display:inline-flex;align-items:center;gap:4px;max-width:100%;padding:2px 3px 2px 8px;border:1px solid var(--line);border-radius:999px;
  background:var(--pane-field);font-size:10.5px;color:var(--ink)}
.echip button{width:16px;height:16px;padding:0;border:0;border-radius:50%;background:none;color:var(--muted);font:inherit;font-size:12px;line-height:1;cursor:pointer}
/* The role itself is the picker: reads as the chip's word, opens the side's roles. */
.echip-pick{appearance:none;-webkit-appearance:none;max-width:140px;padding:0 14px 0 0;border:0;background:transparent url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5'%3E%3Cpath d='M0 0h8L4 5z' fill='%23888'/%3E%3C/svg%3E") no-repeat right center;color:var(--ink);font:inherit;font-size:10.5px;cursor:pointer;text-overflow:ellipsis}
.echip-pick:focus-visible{outline:2px solid var(--focus-ring);outline-offset:1px;border-radius:999px}
.echip button:hover{background:var(--pane-no);color:var(--pane-on-ok)}
.echip .eother{width:120px;max-width:100%;min-width:0;padding:1px 6px;border:1px solid var(--line);border-radius:999px;
  background:var(--pane-field);color:var(--ink);font:inherit;font-size:16px}
.esrow .esrow-add{max-width:96px;padding:1px 6px;font-size:10.5px}
.esrow-share{display:inline-flex;align-items:center;gap:2px;font-size:12px;font-weight:700;color:var(--muted)}
/* Wide enough for a three-way split's 33.33 whole: at 56px its last digit
   was cut off. */
.esrow-share input{width:68px;padding:6px 7px;border:1px solid var(--line);border-radius:8px;background:var(--pane-field);color:var(--ink);
  font:inherit;font-size:16px;font-weight:700;text-align:right;font-variant-numeric:tabular-nums}
.esrow.is-dim .esrow-share input{background:transparent}
.esrow-share input:focus{outline:2px solid var(--focus-ring);outline-offset:1px;border-color:transparent}
.esrow-x{width:24px;height:24px;padding:0;border:0;border-radius:50%;background:none;color:var(--muted);font:inherit;font-size:15px;line-height:1;cursor:pointer}
.esrow-x:hover{color:var(--pane-no);background:var(--pane-field)}
.esrow-x:focus-visible,.echip button:focus-visible,.ebadge-x:focus-visible{outline:2px solid var(--focus-ring);outline-offset:1px}
/* a studio row has no share: the × takes the share's column */
.estudio .esrow{grid-template-columns:26px minmax(0,1fr) auto}

/* SAMPLES & STUDIO CREDITS, under the two sides */
.estudio{margin-top:16px;padding-top:12px;border-top:1px dashed var(--line)}
.estudio-h{margin:0;font-size:10px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:var(--muted)}
.estudio .ehint{margin:4px 0 8px}
.estudio-samples{margin:8px 0 0}
.estudio-acts{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.estudio-acts .eaddperson{padding:6px 11px;font-size:11.5px}
.estudio .epicker{margin-top:8px}
.esample-form{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:8px;margin-top:10px;padding:10px;
  border:1px solid var(--line);border-radius:12px;background:var(--pane-field)}
.esample-go{grid-column:1/-1;display:flex;gap:8px;align-items:center}
@media (max-width:420px){.esample-form{grid-template-columns:1fr}}

/* THE RECORD'S OWN CREDITS, folded under the songs */
.erecfold{margin:16px 0 4px;border:1px solid var(--line);border-radius:12px}
.erecfold-head{display:flex;align-items:center;flex-wrap:wrap;gap:4px 10px;width:100%;padding:10px 12px;border:0;border-radius:12px;
  background:none;color:var(--ink);font:inherit;text-align:left;cursor:pointer}
.erecfold-head:focus-visible{outline:2px solid var(--focus-ring);outline-offset:-2px}
.erecfold-t{font-size:12.5px;font-weight:600}
.erecfold-hint{flex:1;min-width:0;font-size:11.5px;color:var(--muted)}
.erecfold.open .etrack-chev{transform:rotate(-135deg);margin-top:3px}
.erecfold-sum{padding:0 12px 11px;cursor:pointer}
.erecfold-none{font-size:12px;color:var(--muted)}
.erecfold-body{padding:0 12px 12px}
.erecfold-body .ecredits{margin:0}

#addTrack,.eaddperson{padding:10px 15px;border:1px dashed var(--line);border-radius:999px;background:none;
  color:var(--muted);font:inherit;font-size:12.5px;cursor:pointer}
.eaddperson:hover,#addTrack:hover{color:var(--ink);border-color:var(--muted);border-style:solid}
#addTrack{margin-top:2px}

/* people & credits — inside Project's Tracks & Credits, and reused by Rights */
.ecredits{margin:0 0 22px}
.ecredits h4{margin:0 0 4px;font-size:10px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:var(--muted)}
.ecredits .ehint{margin:0 0 10px}
.ecredits .pempty{margin:0 0 10px;font-size:12px;color:var(--muted)}
.ecredit{padding:12px;margin-bottom:9px;border:1px solid var(--line);border-radius:14px}
.ecredit-top{display:flex;align-items:center;gap:10px}
.ecredit-top.as-field{padding:10px;border:1px solid var(--line);border-radius:12px}
.eavatar{flex:none;display:grid;place-items:center;width:30px;height:30px;border-radius:50%;
  background:var(--object-ground);color:var(--muted);font-size:11px;font-weight:700;letter-spacing:.02em}
.ecredit-who{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.ecredit-who b{font-size:13.5px;font-weight:650;color:var(--ink)}
.ecredit-who b i{font-style:normal;font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.ecredit-who small{font-size:11px;color:var(--muted)}
.ecredit-who small.is-new{color:var(--pane-warn)}
.ecredit-who small.is-claimed{color:var(--pane-ok)}
.edrop{flex:none;padding:6px 11px;border:1px solid var(--line);border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:11.5px;cursor:pointer}
.edrop:hover{color:var(--pane-no);border-color:var(--pane-no)}
.eroles{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin-top:10px}
.erole{display:inline-flex;align-items:center;gap:5px;padding:5px 6px 5px 11px;border:1px solid var(--line);border-radius:999px;font-size:12px;color:var(--ink)}
.erole button{width:17px;height:17px;padding:0;border:0;border-radius:50%;background:var(--pane-field);color:var(--muted);font:inherit;font-size:12px;line-height:1;cursor:pointer}
.erole button:hover{background:var(--pane-no);color:var(--pane-on-ok)}
.erole.is-none{color:var(--muted);border-style:dashed}
.erole.is-other{padding-left:6px}
/* The role itself is the control. It reads as the chip's own label until you
   touch it, which is what keeps a list of credits looking like a list of
   credits rather than a row of form fields. */
.erole-pick{max-width:170px;padding:2px 4px 2px 5px;border:0;border-radius:999px;background:transparent;
  color:inherit;font:inherit;font-size:12px;cursor:pointer;appearance:none;-webkit-appearance:none;
  text-overflow:ellipsis}
.erole-pick:hover{color:var(--pane-accent)}
.erole-pick:focus-visible{outline:2px solid var(--pane-accent);outline-offset:1px}
.erole:has(.erole-pick){padding-left:7px}

/* the two actions on a collaborator card */
.dir-acts{display:flex;gap:6px;width:100%;margin-top:8px}
.dir-acts .fix-btn{flex:1;min-width:0;margin-top:0}
.dir-remove:hover{color:var(--pane-no,#c4403a);border-color:currentColor}
.erole .eother{width:150px;padding:3px 8px;border:1px solid var(--line);border-radius:999px;background:var(--pane-field);color:var(--ink);font:inherit;font-size:12px}
.eaddrole{padding:5px 10px;border:1px dashed var(--line);border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:12px;cursor:pointer}
.eaddrole:hover{border-style:solid;color:var(--ink)}
.ecredit-foot{display:flex;align-items:center;gap:8px;margin-top:11px;padding-top:10px;border-top:1px solid var(--line)}
.ecredit-foot .grow{flex:1}
.estate{font-size:11px;color:var(--muted)}
.estate.ok{color:var(--pane-ok)}.estate.no{color:var(--pane-no)}.estate.warn{color:var(--pane-warn)}
.emove,.eaddrole{max-width:100%;min-width:0;text-overflow:ellipsis}
.emove{padding:5px 9px;border:1px solid var(--line);border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:11.5px;cursor:pointer}

/* the ADD PERSON panel — search what exists before creating anyone new */
.epicker{padding:12px;border:1px solid var(--ink);border-radius:14px;background:var(--pane-field)}
.epicker>label{display:block;font-size:10px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:var(--muted);margin-bottom:8px}
.epick-q{width:100%;padding:10px 12px;border:1px solid var(--line);border-radius:10px;background:var(--panel-bg);color:var(--ink);font:inherit;font-size:16px}
.epick-q:focus{outline:2px solid var(--focus-ring);outline-offset:1px;border-color:transparent}
.epick-list{margin:8px 0;max-height:210px;overflow:auto}
.epick-hit{display:flex;align-items:center;gap:10px;width:100%;padding:8px;border:0;border-radius:10px;background:none;font:inherit;text-align:left;cursor:pointer}
.epick-hit:hover:not(:disabled){background:var(--panel-bg)}
.epick-hit:disabled{opacity:.5;cursor:default}
.epick-who{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.epick-who b{font-size:13px;font-weight:650;color:var(--ink)}
.epick-who small{font-size:11px;color:var(--muted)}
.epick-act{flex:none;font-size:11.5px;color:var(--pane-accent);font-weight:600}
.epick-hit:disabled .epick-act{color:var(--muted);font-weight:400}
.epick-empty{margin:10px 8px;font-size:12px;color:var(--muted)}
/* The typed name is already someone's: said, not asked — a new person of that name is allowed */
.epick-twin{margin:2px 8px 10px;font-size:12px;line-height:1.45;color:var(--ink)}
.epick-foot{display:flex;gap:8px;align-items:center;padding-top:9px;border-top:1px solid var(--line)}
.epick-new{flex:1;padding:9px 12px;border:1px solid var(--line);border-radius:999px;background:var(--panel-bg);color:var(--ink);font:inherit;font-size:12.5px;cursor:pointer;text-align:left}
.epick-new:disabled{color:var(--muted);cursor:default}
.epick-cancel{padding:9px 14px;border:1px solid transparent;border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:12.5px;cursor:pointer}
/* "Owns a share, no credit": a person on a split with no credit, never a credit */
.epick-foot{flex-wrap:wrap}
.epick-mode{padding:9px 12px;border:1px dashed var(--line);border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:12px;cursor:pointer}
.epick-mode:hover{color:var(--ink);border-style:solid}
.epick-mode[aria-pressed="true"]{border-style:solid;color:var(--ink)}

/* The splits, inside each side's box: what is on file, the running total,
   what filing said, and the actions after a save. Scoped to .eside, so no
   other step moves. */
.eside .rs-onfile{margin:0 0 8px}
.eside .rs-total{margin:8px 0 0;padding-top:7px;border-top:1px solid var(--ink);font-size:12.5px;font-weight:700;
  color:var(--muted);font-variant-numeric:tabular-nums}
.eside .rs-state{margin:6px 0 0;font-size:12px;line-height:1.45;color:var(--muted)}
.eside .ok{color:var(--pane-ok)}
.eside .warn{color:var(--pane-warn)}
.eside .rs-why{margin:5px 0 0;padding:0 0 0 16px;font-size:12px;line-height:1.45;color:var(--pane-warn)}
.eside .rs-acts{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.eside .rs-acts .eaddperson{padding:7px 12px;font-size:12px}
.eside .eaddperson:disabled{opacity:.45;cursor:default;border-style:dashed;color:var(--muted)}

/* Documents — present in the flow, honest about not being built */
.wiz-later{padding:16px;border:1px dashed var(--line);border-radius:14px}
.wiz-later p{margin:0 0 10px;font-size:12.5px;line-height:1.55;color:var(--muted)}
.wiz-later p:last-child{margin:0}
.wiz-later b{color:var(--ink)}

/* Review, and the screen after creation */
.wiz-review .rev-top{display:flex;align-items:center;gap:14px;margin-bottom:16px}
.rev-art{flex:none;width:66px;height:66px;border-radius:12px;overflow:hidden;background:var(--object-ground);display:grid;place-items:center}
.rev-art img{width:100%;height:100%;object-fit:cover}
.rev-art span{font-size:8px;color:var(--muted);text-align:center}
.rev-id h5{margin:0 0 3px;font-family:var(--display);font-weight:800;font-size:21px;letter-spacing:-.02em;color:var(--ink)}
.rev-id p{margin:0;font-size:12.5px;color:var(--muted)}
.rev-counts{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin:0 0 14px;padding:0;list-style:none}
.rev-counts li{padding:12px;border:1px solid var(--line);border-radius:12px;text-align:center}
.rev-counts b{display:block;font-family:var(--font-num);font-size:24px;font-weight:800;color:var(--ink);font-variant-numeric:tabular-nums}
.rev-counts span{font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.rev-line{margin:0 0 12px;font-size:12.5px;line-height:1.5;color:var(--muted)}
.rev-people{margin:0 0 14px;padding:0;list-style:none;display:flex;flex-direction:column;gap:7px}
.rev-people li{display:flex;align-items:center;gap:9px;flex-wrap:wrap;padding:9px 11px;border:1px solid var(--line);border-radius:12px;font-size:12.5px}
.rev-people li b{font-weight:650;color:var(--ink)}
.rev-people li small{color:var(--muted);font-size:11.5px}
.rev-people li i{margin-left:auto;font-style:normal;font-size:11px;color:var(--muted)}
.rev-people li.is-sent{border-color:var(--pane-ok)}
.rev-people li.is-sent i{color:var(--pane-ok)}
.inv-email{flex:1 1 150px;min-width:120px;padding:7px 10px;border:1px solid var(--line);border-radius:999px;background:var(--pane-field);color:var(--ink);font:inherit;font-size:12px}
.inv-send{padding:7px 14px;border:1px solid var(--line);border-radius:999px;background:none;color:var(--ink);font:inherit;font-size:12px;cursor:pointer}
.inv-send:disabled{color:var(--muted);cursor:default}
.rev-people .inv-out{flex:1 1 100%;display:flex;gap:7px;align-items:center}
.rev-people .inv-out[hidden]{display:none}
.inv-link{flex:1 1 auto;min-width:0;padding:7px 10px;border:1px solid var(--line);border-radius:999px;background:var(--pane-field);color:var(--ink);font:inherit;font-size:12px}
.rev-problems{margin:0 0 12px;padding:11px 13px;border:1px solid var(--pane-warn);border-radius:12px}
.rev-problems p{margin:0 0 5px;font-size:12.5px;color:var(--pane-warn)}
.rev-problems p:last-child{margin:0}

@media (max-width:760px){
  .wiz-type{grid-template-columns:1fr}
  .rev-counts{grid-template-columns:1fr 1fr}
  .epick-q,.erole .eother,.inv-email,.inv-link{font-size:16px}
  .wiz-step span{display:none}
  .wiz-step.on span{display:inline}
}

/* ---- the people directory, as a place ---- */
.dir-head{margin:0 0 14px;font-size:12.5px;line-height:1.55;color:var(--muted);max-width:64ch}
/* SQUARES, NOT RECTANGLES. "A decent sized profile picture, the person, then
   whatever information is there." A collaborator is a face first; the counts
   and the claim state are what you read second. */
.dir-grid{margin:0;padding:0;list-style:none;
  display:grid;grid-template-columns:repeat(auto-fill,minmax(178px,1fr));gap:12px}
.dir-card{display:flex;flex-direction:column;align-items:center;gap:6px;text-align:center;
  padding:20px 14px 16px;border:1px solid var(--line);border-radius:18px;min-width:0;
  transition:border-color .2s var(--ease),background .2s var(--ease)}
.dir-card:hover{border-color:var(--muted)}
/* The page anyone can open for this person — the owner sends it, or opens
   his own. */
.dir-link{font-size:11px;color:var(--muted);text-decoration:none;border-bottom:1px solid var(--line)}
.dir-link:hover{color:var(--ink)}
.dir-card.is-you{background:var(--pane-field);border-color:transparent}
.dir-face{width:84px;height:84px;border-radius:50%;background:var(--pane-field) center/cover no-repeat;
  display:grid;place-items:center;margin-bottom:4px;
  font-family:var(--serif);font-size:26px;font-weight:900;letter-spacing:-.03em;color:var(--muted)}
.dir-name{font-family:var(--serif);font-size:15px;font-weight:800;letter-spacing:-.028em;color:var(--ink);
  max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dir-roles{font-size:11px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);
  max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dir-meta{font-size:11.5px;color:var(--muted);font-variant-numeric:tabular-nums}
.dir-state{font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.dir-state.ok{color:var(--pane-ok)}
.dir-open{margin-top:8px;width:100%}
/* Their page over Records together: side by side they did not fit a
   phone's half-width card, and "Records together" was cut off. */
.dir-card .dir-acts{flex-direction:column}
.dir-card .dir-acts .fix-btn{flex:none;width:100%}
.dir-acts .dir-page{display:inline-flex;align-items:center;justify-content:center;text-decoration:none;color:inherit}
/* RECORDS TOGETHER, dropped under the card's button: the gallery's dropped
   track list (.grid-tracks, above) — laid over the cards below, so the card
   keeps its size and no other card moves; the rows fall in one after another
   on the gallery's curve and 44ms step; the other cards recede while it is
   open. Unlike the hover list it is opened by a tap, so it works on a phone,
   and it scrolls inside itself when it is long. */
.dir-grid{align-items:start}
.dir-card{position:relative}
.dir-card.is-open{z-index:30;border-color:var(--muted)}
.dir-grid.has-open .dir-card:not(.is-open){opacity:.15;transition:opacity .24s var(--ease)}
.dir-drop{position:absolute;left:-1px;right:-1px;top:calc(100% - 10px);z-index:31;
  padding:6px 6px 8px;border:1px solid var(--muted);border-top:0;border-radius:0 0 18px 18px;
  background:var(--page);text-align:left;
  max-height:min(62svh,520px);overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch}
.dir-drop-list{margin:0;padding:0;list-style:none}
.dir-drop-row{opacity:0;transform:translateY(-12px) scale(.95);
  transition:opacity .24s var(--ease),transform .36s cubic-bezier(.22,.82,.18,1);
  transition-delay:calc(var(--i) * 44ms)}
.dir-drop.is-in .dir-drop-row{opacity:1;transform:none}
.dir-drop-row > button,.dir-drop-row:not(:has(button)){display:flex;align-items:center;gap:9px;width:100%;
  padding:8px 4px;border:0;border-bottom:1px solid var(--line);background:none;color:inherit;font:inherit;text-align:left}
.dir-drop-row > button{cursor:pointer}
.dir-drop-row:last-child > button,.dir-drop-row:last-child:not(:has(button)){border-bottom:0}
.dir-drop-row > button:hover .dir-drop-text b{color:var(--ink)}
.dir-drop-art{flex:none;width:36px;height:36px;border-radius:7px;overflow:hidden;background:var(--object-ground)}
.dir-drop-art img{width:100%;height:100%;object-fit:cover;display:block}
.dir-drop-text{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:1px}
.dir-drop-text b{font-family:var(--serif);font-size:13.5px;font-weight:800;letter-spacing:-.015em;line-height:1.15;
  color:color-mix(in srgb,var(--ink) 88%,transparent);
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
.dir-drop-text i{font-style:normal;font-size:11px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media (prefers-reduced-motion:reduce){.dir-drop-row{transition:none;transform:none}}
/* TEAM CHIPS (migration 0015, read-only): Everyone, then one chip per team
   with its member count. One row that scrolls sideways, so a phone never
   gets many lines of them. The pill look is .pill's. */
.dir-chips{display:flex;flex-wrap:nowrap;gap:8px;margin:0 0 16px;padding:2px 0 4px;overflow-x:auto;
  overscroll-behavior-x:contain;scrollbar-width:none;-webkit-overflow-scrolling:touch}
.dir-chips::-webkit-scrollbar{display:none}
.dir-chip{flex:none;display:inline-flex;align-items:center;gap:7px;padding:8px 13px;border:1px solid var(--line);
  border-radius:999px;background:var(--pane-field);color:var(--muted);font:inherit;font-size:11px;font-weight:600;
  letter-spacing:.07em;text-transform:uppercase;white-space:nowrap;cursor:pointer;
  transition:color .2s var(--ease),border-color .2s var(--ease),background .2s var(--ease)}
.dir-chip:hover{color:var(--ink);border-color:var(--muted)}
.dir-chip b{font-weight:600;color:var(--ink);font-variant-numeric:tabular-nums}
.dir-chip[aria-pressed="true"]{background:var(--ink);border-color:var(--ink);color:var(--page)}
.dir-chip[aria-pressed="true"] b{color:var(--page)}
.dir-chip:focus-visible{outline:2px solid var(--focus-ring);outline-offset:1px}
/* Inside a team: the title under the name, a quiet mark where they run it,
   and a person's own teams on their card. */
.dir-title{font-size:12px;font-weight:600;color:var(--ink);max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dir-runs{font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--pane-accent,var(--muted))}
.dir-teams{font-size:11px;color:var(--muted);max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dir-meta.is-quiet{opacity:.7}
/* The admin's corner: profiles on none of his records, each with Remove. */
.dir-loose{margin-top:28px;padding-top:16px;border-top:1px solid var(--line)}
.dir-loose-head{margin:0 0 4px;font-size:12px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.dir-loose-list{margin:0;padding:0;list-style:none}
.dir-loose-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 0;border-bottom:1px solid var(--line)}
.dir-loose-name{flex:1 1 auto;font-size:14px;font-weight:700;color:var(--ink);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dir-loose-name small{font-weight:500;color:var(--muted);margin-left:6px}
.dir-loose-row .fix-btn{flex:none;width:auto;margin:0;padding-left:18px;padding-right:18px}
.dir-empty{margin:26px 2px;font-size:13px;color:var(--muted)}
@media (max-width:760px){
  .dir-grid{grid-template-columns:repeat(auto-fill,minmax(146px,1fr));gap:10px}
  .dir-face{width:68px;height:68px}
}

/* The migration banner. Loud enough to be read, quiet enough not to alarm. */
.maint-bar{position:fixed;left:0;right:0;top:0;z-index:90;display:flex;gap:10px;align-items:baseline;flex-wrap:wrap;
  padding:11px 18px;background:var(--pane-warn);color:#fff;font-size:12.5px;line-height:1.45}
.maint-bar[hidden]{display:none}
.maint-bar b{font-weight:700}
.maint-bar span{opacity:.92}
body.is-frozen .header{top:42px}
body.is-frozen button:disabled{opacity:.45;cursor:not-allowed}
@media (max-width:760px){ .maint-bar{padding:9px 14px;font-size:12px} }
/* iOS Safari zooms the page into any field smaller than 16px when it is
   focused, and the page sits zoomed and shifted while the owner types (the
   role pickers, the share boxes and the invite inputs were 11-13px; seen in
   the first collaborator test, 2026-09-27). On a phone every field is 16px. */
@media (max-width:760px){input,select,textarea{font-size:16px}}

/* ================= the public page (/@<person id>) =================
 * The same front page, read-only (docs/04_DATA/PUBLIC_FRONT_PAGE.md). The
 * Worker puts .is-public on <html> and public-boot.js sets it again. What is
 * the owner's alone goes: Manage and its count (manage.js is not even on the
 * page), the "confirmed by the artist" line (claims are not public), and the
 * workspace. Hidden outright, with !important, because `hidden` alone loses
 * to any rule that sets display on these. The theme control stays: it is the
 * viewer's own, and writes nothing but their own choice.
 */
.is-public .manage-toggle:not(.public-door),.is-public #manageDot,.is-public #heroConfirmed,.is-public #managePane{display:none!important}
/* Highlights with nothing picked says nothing to a visitor: the section goes
   until there is something in it. (hero-dive.js only writes styles to it, so
   its place in the dive is unaffected.) */
.is-public .highlights:has(.highlights-empty){display:none}
/* No name on the left of the public header (the name card shows it), so the
   empty slot is only the flexible half that keeps the controls on the right.
   The owner's Manage is cut from this page; the controls that stand where it
   stood (Manage as a door, and Studio for the owner) are public-boot.js's own
   `.public-door` pills, the owner's pill look (QUIET PILL, FLOATING, ROUND). */
.is-public .who-col{flex:1 1 auto;min-width:0}
.is-public .header-right{flex:none}
/* SIGN IN (public-boot.js): the way in for a collaborator with an account.
   Manage's shape, since it stands where Manage stood: a quiet outlined pill
   with the theme control beside it. */
.sign-in{display:inline-flex;align-items:center;text-decoration:none;white-space:nowrap;
  transition:color .2s var(--ease),border-color .2s var(--ease)}
.sign-in:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}
/* SEARCH (public-boot.js): a glass, left of Sign in, to /search — everyone
   who has a page. The share button's shape (QUIET PILL, FLOATING, ROUND). */
.search-link{display:grid;place-items:center;flex:none;text-decoration:none;transition:color .2s var(--ease)}
.search-link svg{display:block}
.search-link:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}
/* The same 44px fingertip the other header controls get, without moving a
   pixel of the layout. */
@media (pointer:coarse){
  .sign-in,.search-link{position:relative}
  .sign-in::after,.search-link::after{content:"";position:absolute;left:50%;top:50%;translate:-50% -50%;width:max(100%,44px);height:max(100%,44px)}
}

/* ---- the header's buttons, one size and one look (the owner, 2026-10-01:
   "smaller, more consistent buttons that blend with the design"). Sign in on
   the public page, the edit button on the owner's, and the theme button: the
   same height, the same hairline, the same frosted ground as the round view
   buttons at the foot of the screen. The hit area stays 44px on touch (the
   ::after rule above). Their shape, ground and type are the shared recipes
   at the end of this file (QUIET PILL, FLOATING, ROUND); only the glyph
   sizes are their own. ---- */
.site-header .theme-toggle{margin-left:0;font-size:14px}
@media (max-width:760px){
  .site-header .theme-toggle{font-size:13px}
}
/* The specimen's hover (ink, a muted ring) sticks after a tap on a touch
   screen. Put back to the resting look there: the page's muted, like the
   header's other buttons. */
@media (hover:none){
  .theme-toggle:hover{color:var(--muted);border-color:var(--line)}
}

/* The line under the title carries more now ("4 tracks · 12 contributors"):
   a touch less letter-spacing on a phone keeps it on one line under a
   phone-width cover. */
@media (max-width:760px){.shelf-view .record-kicker{font-size:.6875rem;letter-spacing:.07em}}

/* ================= the shared recipes =================
 * A control adopts a recipe by joining its selector list, and then deletes its
 * own height, padding, font, border and radius. Plain selector lists, never
 * :is(), which would lift every member to the specificity of the strongest.
 * The order matters: FLOATING comes after QUIET PILL and gives it a ground.
 */
/* QUIET PILL: an outlined pill in the name style. Quiet means the muted
   colour, not a lighter weight; it turns ink under the pointer or the focus. */
.site-header .sign-in,.site-header .manage-toggle,.site-header .search-link,.socials a,.share-btn{
  height:var(--control);padding:0 var(--space-3);border:1px solid var(--line);border-radius:var(--radius-pill);
  background:transparent;color:var(--muted);font:var(--t-name);letter-spacing:var(--tr-name)}
.site-header .sign-in:focus-visible,.site-header .manage-toggle:focus-visible,.site-header .search-link:focus-visible,.socials a:focus-visible,.share-btn:focus-visible{color:var(--ink)}
/* Under a pointer only: a touch screen keeps :hover after the tap, and an ink
   pencil after the tap that closes Manage reads as on. */
@media (hover:hover){
  .site-header .sign-in:hover,.site-header .manage-toggle:hover,.site-header .search-link:hover,.socials a:hover,.share-btn:hover{color:var(--ink)}
}
/* FLOATING: for a control that sits over content, the header's own frosted
   ground. */
.site-header .sign-in,.site-header .manage-toggle,.site-header .theme-toggle,.site-header .search-link,.socials a,.share-btn{
  background:var(--header-bg);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}
/* ROUND: a control that is one glyph. Manage is one on a phone, where its
   word gives way to the pencil. */
.site-header .theme-toggle{width:var(--control);height:var(--control);border-radius:50%}
.site-header .search-link,.share-btn{width:var(--control);height:var(--control);padding:0;border-radius:50%}
@media (max-width:760px){
  .site-header .manage-toggle{width:var(--control);height:var(--control);padding:0;border-radius:50%}
}
/* PRESSED: Manage while it is open, filled in the ink with the page's colour
   for its word or pencil — the active view button's look. After the recipes
   above, which give it its quiet ground, and after their hover and focus, so
   the open state is what shows. */
.site-header .manage-toggle[aria-pressed="true"]{background:var(--ink);border-color:var(--ink);color:var(--page)}
/* PRIMARY: the accent's fill with its own text colour. Today only the Manage
   count dot; the one action on a screen joins it in a later stage. */
.manage-dot{background:var(--accent);color:var(--on-accent)}

/* The Studio pill (home.html header) is a link to another app; it dresses like the Manage button, not like a
   link in text. */
.site-header .studio-link,.site-header .studio-link:hover,.site-header .public-door,.site-header .public-door:hover{text-decoration:none}
/* A link has no centring of its own: the word sat above Manage's. Same box, same middle. */
.site-header .studio-link,.site-header .public-door{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;line-height:1}

/* ================= the share menu (hero.js, #shareMenu) =================
 * The round share button opens it: Share profile, Share a record…, and the
 * asset line that waits for the Library. A popover under the button on a wide
 * screen (hero.js sets --share-right and --share-top / --share-bottom from the
 * button), a bottom sheet with a scrim on a phone. The page's own tokens, so
 * both themes follow; items are a fingertip tall on a phone.
 */
.share-scrim{display:none}
.share-menu[hidden],.share-scrim[hidden]{display:none!important}
.share-menu{position:fixed;z-index:70;top:var(--share-top,auto);bottom:var(--share-bottom,auto);right:var(--share-right,12px);
  box-sizing:border-box;width:min(280px,calc(100vw - 24px));max-height:min(60svh,420px);overflow:auto;overscroll-behavior:contain;
  padding:var(--space-1);border:1px solid var(--line);border-radius:var(--radius-panel);
  background:var(--page);color:var(--ink);box-shadow:0 18px 40px -18px rgba(0,0,0,.45);
  text-transform:none;letter-spacing:0;animation:share-in .18s var(--ease)}
.share-item{display:flex;align-items:center;gap:var(--space-2);box-sizing:border-box;width:100%;min-height:40px;padding:0 var(--space-3);
  border:0;border-radius:var(--radius-pill);background:none;color:var(--ink);font:inherit;text-align:left;cursor:pointer}
.share-item .share-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:var(--t-name);letter-spacing:var(--tr-name)}
.share-item svg{flex:none;color:var(--muted)}
.share-sub{flex:none;font:var(--t-small);letter-spacing:var(--tr-small);color:var(--muted)}
.share-item:focus-visible{outline:2px solid var(--focus-ring);outline-offset:-2px}
@media (hover:hover){.share-item:not(.is-off):hover{background:color-mix(in srgb,var(--ink) 7%,transparent)}}
.share-item.is-off{cursor:default}
.share-item.is-off .share-label{color:var(--muted)}
.share-item.is-off .share-label .share-sub{font-weight:400}
.share-back{position:sticky;top:0;z-index:1;background:var(--page);color:var(--muted)}
.share-list{display:flex;flex-direction:column}
.share-empty{margin:var(--space-3);font:var(--t-small);letter-spacing:var(--tr-small);color:var(--muted)}
@keyframes share-in{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
@keyframes share-up{from{transform:translateY(24px);opacity:.6}to{transform:none;opacity:1}}
@keyframes share-fade{from{opacity:0}to{opacity:1}}
@media (max-width:760px){
  .share-scrim:not([hidden]){display:block;position:fixed;inset:0;z-index:69;background:rgba(0,0,0,.38);animation:share-fade .2s var(--ease)}
  .share-menu{top:auto;bottom:0;left:0;right:0;width:auto;max-height:min(72svh,540px);
    padding:var(--space-3) var(--space-3) calc(var(--space-4) + env(safe-area-inset-bottom,0px));
    border-width:1px 0 0;border-radius:var(--radius-panel) var(--radius-panel) 0 0;animation:share-up .24s var(--ease)}
  .share-menu::before{content:"";display:block;width:36px;height:4px;margin:0 auto var(--space-2);border-radius:2px;background:var(--line)}
  .share-item{min-height:48px}
}
@media (prefers-reduced-motion:reduce){.share-menu,.share-scrim{animation:none!important}}

/* ---------- THE LIBRARY (Manage -> Library, migration 0017) ----------
   Every file the studio holds, as rows in the look the records and people
   already have: the same pill chips, the same field ground, the same
   hairlines. Phone first: one column, the chips scroll sideways, a file's
   editor opens under its row, and the bulk bar sticks to the bottom of the
   screen. A stem or an extend nests under its original and folds away. */
.mg-views{max-width:100%}
@media (max-width:560px){
  .mg-views{overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none}
  .mg-views::-webkit-scrollbar{display:none}
  /* Six tabs, and "Alerts · 2" the widest: 8px a side keeps all six on one
     375px line with a count showing; narrower than that they scroll, and the
     edge that has more fades (below). */
  .mg-views button{padding:10px 8px;flex:1 0 auto;white-space:nowrap}
}
/* A ROW THAT SCROLLS SIDEWAYS SAYS SO. The Manage tabs on a phone and the
   People and Library chip rows: the edge with more behind it fades over
   24px, driven by the row's own scroll, so a cut-off chip reads as "more this
   way", not as a clipped one. A row that fits has no scroll timeline, the
   animation does nothing and nothing fades. Where scroll-driven animation is
   not supported the row simply scrolls, as before. */
@property --edge-l{syntax:"<length>";inherits:false;initial-value:0px}
@property --edge-r{syntax:"<length>";inherits:false;initial-value:0px}
@keyframes edge-fade{
  0%{--edge-l:0px;--edge-r:24px}
  8%,92%{--edge-l:24px;--edge-r:24px}
  100%{--edge-l:24px;--edge-r:0px}
}
@supports (animation-timeline:scroll()){
  .dir-chips{
    -webkit-mask-image:linear-gradient(to right,transparent,#000 var(--edge-l),#000 calc(100% - var(--edge-r)),transparent);
    mask-image:linear-gradient(to right,transparent,#000 var(--edge-l),#000 calc(100% - var(--edge-r)),transparent);
    animation:edge-fade linear both;animation-timeline:scroll(self inline)}
  @media (max-width:560px){
    .mg-views{
      -webkit-mask-image:linear-gradient(to right,transparent,#000 var(--edge-l),#000 calc(100% - var(--edge-r)),transparent);
      mask-image:linear-gradient(to right,transparent,#000 var(--edge-l),#000 calc(100% - var(--edge-r)),transparent);
      animation:edge-fade linear both;animation-timeline:scroll(self inline)}
  }
}
.manage-library{max-width:980px;padding-bottom:96px}
.manage-library[hidden]{display:none}
.lib-banner{margin:0 0 14px;padding:10px 14px;border:1px solid var(--line);border-radius:var(--radius-panel);background:var(--pane-field);font-size:12.5px;line-height:1.5;color:var(--muted)}
.lib-miss-row{display:flex;flex-wrap:wrap;gap:8px;margin:-6px 0 16px}
.lib-listbar{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:0 0 10px}
.lib-count{font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.lib-link{min-height:36px;padding:6px 2px;border:0;background:none;color:var(--muted);font:inherit;font-size:12px;text-decoration:underline;text-underline-offset:3px;cursor:pointer}
.lib-link:hover{color:var(--ink)}
.lib-list,.lib-kids{list-style:none;margin:0;padding:0}
.lib-item{margin:0 0 8px}
.lib-row{display:flex;align-items:center;gap:12px;padding:10px 12px;border:1px solid var(--line);border-radius:16px;background:var(--pane-field);
  transition:background .2s var(--ease),border-color .2s var(--ease)}
.lib-row:hover{border-color:var(--muted)}
.lib-item.is-selected>.lib-row{border-color:var(--pane-accent);box-shadow:0 0 0 1px var(--pane-accent) inset}
.lib-item.is-context>.lib-row{opacity:.62}
.lib-kids{margin:8px 0 0 22px;padding-left:12px;border-left:2px solid var(--line)}
.lib-kids .lib-row{padding:8px 10px}
.lib-pick{flex:none;display:grid;place-items:center;width:28px;height:44px;margin:-8px 0 -8px -6px;cursor:pointer}
.lib-pick input{width:18px;height:18px;margin:0;accent-color:var(--ink);cursor:pointer}
.lib-prev{flex:none;position:relative;display:grid;place-items:center;width:52px;height:52px;padding:0;border:0;border-radius:10px;overflow:hidden;
  background:var(--object-ground);color:var(--muted);cursor:pointer}
.lib-kids .lib-prev{width:44px;height:44px}
.lib-prev:hover{color:var(--ink)}
.lib-prev:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}
.lib-prev svg{width:24px;height:24px}
.lib-play,.lib-vid{border-radius:50%;background:var(--ink);color:var(--page)}
.lib-play:hover,.lib-vid:hover{color:var(--page);opacity:.88}
.lib-play[aria-pressed="true"],.lib-vid[aria-pressed="true"]{background:var(--pane-accent)}
.lib-vid{border-radius:10px}
.lib-img img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.lib-ph{font-size:8.5px;font-weight:700;letter-spacing:.1em;color:var(--muted)}
.lib-other{cursor:default}
.lib-main{flex:1;min-width:0}
.lib-title{font-family:var(--display);font-weight:800;font-size:16px;line-height:1.2;letter-spacing:-.015em;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lib-sub{margin-top:3px;font-size:11.5px;line-height:1.4;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lib-who{display:flex;flex-wrap:wrap;gap:0 10px;white-space:normal}
.lib-who span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lib-chips{display:flex;flex-wrap:wrap;gap:5px;margin-top:6px}
.lib-chips:empty{display:none}
.lib-chip{display:inline-flex;align-items:center;padding:3px 9px;border:1px solid var(--line);border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:10.5px;font-weight:600;letter-spacing:.02em;white-space:nowrap}
.lib-chip-miss{color:var(--pane-warn);border-color:var(--pane-warn)}
.lib-chip-rights.is-owned{color:var(--pane-ok);border-color:var(--pane-ok)}
.lib-chip-rights.is-third-party{color:var(--pane-no);border-color:var(--pane-no)}
.lib-chip-tag{background:var(--pane-field)}
.lib-chip-tag.is-inherited{font-style:italic;opacity:.8}
button.lib-chip{min-height:32px;padding:5px 12px;cursor:pointer}
button.lib-chip:hover{color:var(--ink);border-color:var(--muted)}
.lib-acts{flex:none;display:flex;align-items:center;gap:6px}
.lib-edit-btn{min-height:36px;padding:7px 14px;border:1px solid var(--line);border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:11.5px;cursor:pointer;
  transition:color .2s var(--ease),border-color .2s var(--ease)}
.lib-edit-btn:hover,.lib-edit-btn[aria-expanded="true"]{color:var(--ink);border-color:var(--muted)}
.lib-fold{display:inline-flex;align-items:center;gap:6px;min-width:44px;height:32px;padding:0 10px;border:1px solid var(--line);border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:11.5px;font-weight:600;cursor:pointer}
.lib-fold:hover{color:var(--ink);border-color:var(--muted)}
.lib-fold .etrack-chev{margin-top:-3px}
.lib-fold[aria-expanded="true"] .etrack-chev{transform:rotate(-135deg);margin-top:3px}
.lib-slot:empty{display:none}
.lib-view{margin:8px 0 0;padding:10px;border:1px solid var(--line);border-radius:16px;background:var(--pane-field)}
.lib-big{display:block;width:100%;max-height:min(70vh,640px);object-fit:contain;border-radius:10px;background:var(--object-ground)}
.lib-aud{display:block;width:100%}
.lib-note{margin:6px 0 0;font-size:11.5px;line-height:1.45;color:var(--muted)}
.lib-err{margin:10px 0 0;font-size:12.5px;line-height:1.45;color:var(--pane-no)}
.lib-more{display:flex;justify-content:center;margin:16px 0}

/* the editor, under its row, and the bulk panel */
.lib-ed{margin:8px 0 0;padding:14px 14px 12px;border:1px solid var(--line);border-radius:16px;background:var(--page)}
.lib-ed-h{margin:0 0 4px;font:var(--t-name);letter-spacing:var(--tr-name);color:var(--ink)}
.lib-sec{padding:12px 0;border-top:1px solid var(--line)}
.lib-sec:first-of-type{border-top:0;padding-top:4px}
.lib-ed-h+.lib-note+.lib-sec{border-top:0;padding-top:10px}
.lib-sec h4{margin:0 0 8px;font-size:10px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:var(--muted)}
.lib-now{margin:0 0 6px;font-size:13px;line-height:1.4;color:var(--ink);overflow-wrap:anywhere}
.lib-lab{font-size:10px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:var(--muted)}
.lib-sel,.lib-in{min-width:0;max-width:100%;min-height:40px;padding:8px 12px;border:1px solid var(--line);border-radius:999px;background:var(--pane-field);color:var(--ink);font:inherit;font-size:16px}
.lib-sel{flex:1 1 130px}
.lib-in{flex:1 1 110px}
.lib-in-s{flex:0 1 120px}
.lib-notes{display:block;width:100%;border-radius:14px;resize:vertical;font-size:16px;line-height:1.45}
.lib-sel:focus,.lib-in:focus{outline:2px solid var(--focus-ring);outline-offset:1px;border-color:transparent}
.lib-add{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:8px}
.lib-add .fix-btn{padding:9px 14px}
.lib-add .fix-btn[aria-pressed="true"],.lib-suggest .lib-chip[aria-pressed="true"]{background:var(--ink);border-color:var(--ink);color:var(--page)}
.lib-people,.lib-tags{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px}
.lib-people{flex-direction:column;gap:0}
.lib-people li{display:flex;align-items:center;justify-content:space-between;gap:10px;min-height:36px;padding:2px 0;border-bottom:1px solid var(--line);font-size:13px;color:var(--ink)}
.lib-people li:last-child{border-bottom:0}
.lib-people i{font-style:normal;color:var(--muted);margin-left:4px}
.lib-people small{font-size:10.5px;color:var(--muted)}
.lib-people .is-inherited{opacity:.75}
.lib-people .is-new span{color:var(--pane-ok)}
.lib-people .is-gone span,.lib-tags .is-gone span{text-decoration:line-through;opacity:.6}
.lib-people .is-none,.lib-tags .is-none{color:var(--muted);border:0;font-size:12.5px}
.lib-tags li{display:inline-flex;align-items:center;gap:2px;padding:2px 4px 2px 11px;border:1px solid var(--line);border-radius:999px;background:var(--pane-field);font-size:12px;color:var(--ink)}
.lib-tags .is-new{border-color:var(--pane-ok)}
.lib-tags .is-none{padding:2px 0}
.lib-x{flex:none;display:inline-grid;place-items:center;min-width:32px;height:32px;padding:0 6px;border:0;border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:15px;line-height:1;cursor:pointer}
.lib-x:hover{color:var(--pane-no)}
.lib-suggest{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.lib-seg{display:flex;flex-wrap:wrap;gap:8px}
.lib-pair{display:grid;grid-template-columns:1fr 1fr;gap:16px}
@media (max-width:560px){.lib-pair{grid-template-columns:1fr}}
.lib-ed-acts{display:flex;gap:8px;margin-top:6px;padding-top:12px;border-top:1px solid var(--line)}
.lib-ed-acts .fix-btn{flex:1 1 0;max-width:180px}
.lib-ed-acts .fix-btn:disabled{opacity:.5;cursor:default}

/* the bulk bar: stuck to the bottom of the screen while files are selected */
.lib-bar{position:sticky;bottom:0;z-index:5;margin:16px calc(var(--pad-r) * -1) 0 calc(var(--pad-l) * -1);padding:10px var(--pad-r) calc(10px + env(safe-area-inset-bottom,0px)) var(--pad-l);
  border-top:1px solid var(--line);background:var(--header-bg);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}
.lib-bar[hidden]{display:none}
.lib-bar-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.lib-bar-n{flex:1 1 auto;font-size:12.5px;font-weight:600;color:var(--ink)}
.lib-bulk{max-height:60vh;overflow-y:auto;margin:0 0 10px;overscroll-behavior:contain}
.lib-bulk .lib-ed{margin:0}
@media (prefers-reduced-motion:reduce){.lib-row,.lib-edit-btn{transition:none}}
@media (max-width:560px){
  .lib-row{gap:10px;padding:9px 10px}
  .lib-title{font-size:15px}
  .lib-acts{flex-direction:column;align-items:flex-end;gap:6px}
  .lib-kids{margin-left:10px;padding-left:8px}
  .lib-prev{width:48px;height:48px}
}
/* the phone rule makes every .fix-btn full width; inside the Library they size to their words */
.manage-library .fix-btn{width:auto}
.lib-bar-row .fix-btn{flex:1 1 auto}

/* NO RECORDS (catalog-shelf-core.js renderCounts): the title slot says so in
   the body voice, muted, and the kicker and the view switcher step aside. */
.shelf-view.is-empty .record-identity h2{font:var(--t-body);letter-spacing:var(--tr-body);color:var(--muted);-webkit-line-clamp:unset}
.shelf-view.is-empty .record-kicker,.shelf-view.is-empty .version-switch,.header-row.is-empty .mode-switch{display:none}

/* ---- The person docks top left once the hero has gone (the owner, 2026-10-18): face and name, back to the top. The
   room mark gives way to them; inside the map's frame (#via=map) the map's own round button sits top left, so the
   page leaves it room and shows no mark at all. ---- */
.who-dock{display:none;align-items:center;gap:8px;height:var(--control,30px);min-height:0;padding:0 10px 0 3px;border:0;border-radius:var(--radius-pill);background:transparent;color:var(--ink);font:600 14px/1 var(--sans);cursor:pointer;opacity:0;transition:opacity .25s var(--ease)}
.who-dock[hidden]{display:none!important}
.who-dock-face{width:24px;height:24px;border-radius:50%;background:var(--surface-2) center/cover no-repeat;display:grid;place-items:center;font:700 10px/1 var(--sans);color:var(--ink);flex:none}
.who-dock:hover{background:var(--surface-2)}
html.is-in-catalog .who-dock{display:inline-flex;opacity:1}
html.is-in-catalog .header-top>.nb-room{display:none}
html.is-framed .header-top>.nb-room{display:none}
html.is-framed .header-top{padding-left:48px}
/* The public Manage door says its word on a phone too: it is the way to your portal, not a pencil for this page. */
@media(max-width:700px){
  .site-header .public-door{width:auto;height:var(--control);padding:0 12px;border-radius:var(--radius-pill)}
  .site-header .public-door .manage-word{position:static;width:auto;height:auto;clip-path:none;margin-left:6px}
}

/* The theme control shows the time of day it is in: a sun by day, a moon at night (the owner, 2026-10-18). */
.theme-toggle .theme-moon{display:none}
.theme-toggle[aria-pressed="true"] .theme-sun{display:none}
.theme-toggle[aria-pressed="true"] .theme-moon{display:block}

/* ---- The identity block after the owner's card (2026-10-18): the face at the left, the name beside it, then the role
   with its icon and the pin with the place; the links and the bio run under both. No ring around the face. ---- */
.about{display:grid;grid-template-columns:auto minmax(0,1fr);column-gap:var(--space-4);align-items:center}
.about-row{--avatar:clamp(96px,26vw,132px)}
.hero-avatar{grid-column:1;grid-row:1/4;margin:0;box-shadow:none;border:0;align-self:center}
.ident-name{grid-column:2;grid-row:1;align-self:end}
.ident-role{grid-column:2;grid-row:2;display:flex;align-items:center;gap:6px;margin:var(--space-1) 0 0}
.hero-place{grid-column:2;grid-row:3;display:flex;align-items:center;gap:6px;margin:var(--space-1) 0 0;align-self:start}
.about .socials-line{grid-column:1/-1;grid-row:4}
.about #heroBio{grid-column:1/-1;grid-row:5}
.line-ic{flex:none;opacity:.9}
.hero-avatar[hidden]~.ident-name,.hero-avatar[hidden]~.ident-role,.hero-avatar[hidden]~.hero-place{grid-column:1/-1}

/* ---- Balance (the owner, 2026-10-18): the name sized to the face, the role and place readable, the share beside the links. ---- */
.about .ident-name{font-size:clamp(26px,7.5vw,32px);line-height:1.08;letter-spacing:-.01em}
.about .ident-role,.about .hero-place{font-size:15px;letter-spacing:0;color:var(--hero-ink);opacity:.82}
.about .socials-line{justify-content:flex-start;gap:var(--space-2)}
.about .socials-end{margin-left:0}
/* The artist's microphone is solid, like the map's (the owner, 2026-10-18: "make the icon full"). */
.about .ident-role .line-ic rect{fill:currentColor;stroke:none}
.about .ident-role .line-ic,.about .hero-place .line-ic{width:15px;height:15px;opacity:1}

/* ---- The account, top left (the owner, 2026-10-18, the map's rule): an outlined pill, Sign in for a visitor, the face and
   Manage for the owner. ---- */
.nb-account{display:inline-flex;align-items:center;gap:8px;height:var(--control,32px);padding:0 14px;border:1px solid var(--nb-line);border-radius:var(--radius-pill);background:color-mix(in srgb,var(--nb-bg) 72%,transparent);color:var(--nb-ink);font:600 13px/1 var(--font-sans);text-decoration:none;white-space:nowrap;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}
.nb-account[hidden]{display:none}
.nb-account:hover{background:var(--nb-hover);text-decoration:none}
.nb-account-face{width:22px;height:22px;margin-left:-8px;border-radius:50%;background:var(--surface-2) center/cover no-repeat;flex:none}
.nb-account-face[hidden]{display:none}
.header-top>.nb-account{flex:none;margin-right:14px}
html.is-in-catalog .header-top>.nb-account{display:none}
html.is-framed .header-top>.nb-account{display:none}
/* ---- The card after the owner's reference (2026-10-18): a bigger face, the share at the card's top right. ---- */
.about{position:relative}
.about-row{--avatar:clamp(112px,30vw,150px)}
.about .socials-end{position:absolute;right:0;top:0}
html.is-framed .header-top{padding-left:40px}

/* ---- The card lined up (the owner, 2026-10-18): a face the height of the name block, the share above the count in the right
   column, level with the name. ---- */
/* ONE CARD, one grid (the owner, 2026-10-18): the face | the name, role, place | the share with the count under it. The
   links and the bio run under all three columns. hero.js moves the releases block into the card's right column. */
.about-row{--avatar:clamp(84px,22vw,100px);align-items:flex-start}
.about{max-width:none;grid-template-columns:auto minmax(0,1fr) auto;grid-template-rows:auto auto auto;row-gap:var(--space-1);align-items:start}
.about .hero-avatar{align-self:center}
.about .ident-name{align-self:start}
.about .ident-role,.about .hero-place{margin:0;align-self:start}
.about .releases,.about-row .releases{position:static;grid-column:3;grid-row:1/4;display:flex;flex-direction:column;align-items:flex-end;justify-content:space-between;gap:var(--space-2);margin:0;align-self:stretch}
.about .releases .share-btn{margin:0}
.about .socials-end{position:static}
.about .releases .num{line-height:1}
.about .releases .num-label{letter-spacing:.04em}
.ident-role .role{display:inline-flex;align-items:center;gap:5px}
.ident-role .role-dot{margin:0 6px;opacity:.6}
/* The page's own way back to the map, inside the map's frame: the far left, the same round control as the rest; hover
   turns the map into the arrow. */
.nb-mapback{border:0;cursor:pointer;color:inherit}
.nb-mapback[hidden]{display:none}
.nb-mapback svg{grid-area:1/1;transition:opacity .15s ease,transform .15s ease}
.nb-mapback .mapback-arrow{opacity:0;transform:translateX(4px)}
.nb-mapback:hover .mapback-map,.nb-mapback:focus-visible .mapback-map{opacity:0}
.nb-mapback:hover .mapback-arrow,.nb-mapback:focus-visible .mapback-arrow{opacity:1;transform:none}
html.is-framed .header-top{padding-left:0}
/* A phone's card: the lines keep to one line each, the count's label stays small, nothing leaves the card. */
@media(max-width:700px){
  .about-row{--avatar:84px}
  .about .ident-role,.about .hero-place{font-size:14px;white-space:nowrap}
  .about .releases .num-label{font-size:9px;letter-spacing:.04em}
  .about .releases .num{font-size:24px}
}
/* THE CARD, SETTLED (the owner, 2026-10-18): one size scale shared with the map's card. Face 100 (84 on a phone),
   name 28 (24), roles and place 14 with 14px icons, share 30, count 24 (22), its label 10. The share sits level with
   the name at the right and the count at the card's bottom right; nothing pushes them down, nothing leaves the page. */
.about-row{--avatar:100px}
.about .releases,.about-row .releases,.about-row:has(.hero-avatar:not([hidden])) .releases{margin:0}
.about .ident-name{font-size:28px;line-height:1.1;letter-spacing:-.01em}
.about .ident-role,.about .hero-place{font-size:14px;line-height:1.35;letter-spacing:0}
.about .ident-role{flex-wrap:wrap;row-gap:2px;white-space:normal}
.ident-role .role{white-space:nowrap}
.ident-role .line-ic-wrap,.hero-place svg{display:inline-grid;place-items:center;width:14px;height:14px;flex:none}
.about .releases .num{font-size:24px;line-height:1}
.about .releases .num-label{font-size:10px;letter-spacing:.04em}
@media(max-width:700px){
  .about-row{--avatar:84px}
  .about .ident-name{font-size:24px}
  .about .ident-role{white-space:normal}
  .about .releases .num{font-size:22px}
  .about .releases .num-label{font-size:10px}
}
/* The roles flow like words: as many to a line as fit, then the next line, close together. The count and its label
   stay one block at the card's bottom right; the share stays level with the name. */
.about .ident-role{display:block}
.ident-role .role{display:inline-flex;vertical-align:middle;line-height:1.35}
.ident-role .role-dot{display:inline;margin:0 6px;vertical-align:middle}
.about .releases{justify-content:flex-start}
.about .releases .num{margin-top:auto}
/* The old phone rule kept 92px clear on the right for a floating count; the count has its own column now. */
.about .ident-name,.about .ident-role,.about .hero-place{padding-right:0}
/* "Releases" in the roles' and place's own type (the owner, 2026-10-18): 14px, plain case, no wide spacing. */
.about .releases .num-label{font:inherit;font-size:14px;line-height:1.35;letter-spacing:0;text-transform:none;color:var(--hero-ink);opacity:.82;margin:2px 0 0}
@media(max-width:700px){.about .releases .num-label{font-size:14px;letter-spacing:0}}
/* Each role's own icon is the separator; no dot to start a wrapped line. */
.ident-role .role-dot{display:none}
.ident-role .role{margin-right:12px}
.ident-role .role:last-child{margin-right:0}
