/* House of Brooklyn HQ
   Palette and type are Brooklyn's own: light is brooklynvanzandt.com — white
   ground, aubergine, DM Serif Text over Instrument Serif. Dark is the brand
   book's "Dark Romantic" — bone on purple-black, dusty rose.
   Mobile first. Every rule below is the phone; the wide layout is one query. */

/* The room palette, carried through the whole app.
   Redefining the tokens rather than rewriting several hundred selectors: every
   existing rule picks up the cream-and-plum world without being touched, which
   is also why nothing here silently changes a layout.

   Every value below was measured against the paper it sits on. The old
   --faint was #9A8C99 at 2.97:1 — the contrast failure the product review
   flagged — and it is now 4.82:1. Nothing in this set is under AA for normal
   text, so no color choice here can put a deadline or a permission out of
   reach by being decorative.

   The second selector is Original's swatch inside the picker. Every other look
   is written twice for this reason — once for the page, once for a small
   element carrying the attribute — and Original needs it too, or its card in
   the grid shows whatever palette the page happens to be wearing instead of
   its own. Two selectors, one copy of the palette. */
:root,
[data-look="original"][data-theme="light"]{
  --ground:#FBF6F1; --sunk:#F6EFE9; --raised:#FFFBF7; --lift:#EFE4DC;
  --ink:#38242F; --soft:#5A4351; --muted:#68535E; --faint:#7A6873;
  --line:#E6DAD5; --firm:#D9C9CE;
  --accent:#4B263B; --mauve:#9B4B66; --blue:#4E5F77;
  /* From the approved icon board and the visual guide. --ground, --ink and
     --muted already matched it exactly, so these are the four that were
     missing rather than a new palette laid over the old one. */
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61; --tile:#F4E6EB;
  /* The icon family's own ink, so it can lift after dark without redrawing. */
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61; --ic-cream:#FBF6F1;
  --good:#2D6E45; --warn:#8A5700; --stop:#9B0D30;
  /* A destructive act in a menu (Delete, Remove; app/press-menu.js): the
     house's wine red, not iOS's, and a coral after dark (below). */
  --destructive:#A8323F;
  /* Filled only on the confirming row of a destructive question (shell.css). */
  --destructive-fill:#A8323F; --on-destructive:#FFFFFF;
  --onacc:#FFFBF7; --onsem:#FFFBF7; --tint:rgba(75,31,84,.06);
  --chrome:rgba(251,246,241,.95);
  /* The one solid call to action, kept separate from --accent because --accent
     is also read as TEXT in thirty-five places. A look can put a deep wine
     button on the page without making every link on it unreadable. */
  --cta:#4B263B; --oncta:#FFFBF7;
  /* Whether this room is dark. Components that must flip — the wordmark, the
     song room's washes — read a `data-room` attribute mirrored from this, not
     from `data-theme`. A look decides its own lightness, and keying those
     rules to the OS preference is how a white wordmark ends up on cream. */
  --room:light;
  /* The hero's own two controls: the ground the photograph is washed into, as
     an r,g,b triple so a gradient can take it at several opacities, and the
     film over the photograph itself. Both were hardcoded cream, which is why
     dark mode still washed the Home portrait in daylight. */
  --veil:251,246,241;
  /* How hard the photograph is washed into the page: top, middle, and the
     feathered lower edge. A dark room needs far less of this than a cream one
     — the same .66 that turns ivory into paper turns black into a blank. */
  --veil-a:.66; --veil-b:.54; --veil-c:.88;
  --herofx:saturate(.82) sepia(.12) brightness(1.04);

  --f-d:"DM Serif Text", ui-serif, Georgia, serif;
  --f-l:"Instrument Serif", ui-serif, Georgia, serif;
  --f-s:"Instrument Sans", system-ui, -apple-system, sans-serif;
  --f-b:"Instrument Sans", system-ui, -apple-system, sans-serif;
  --f-m:"IBM Plex Mono", ui-monospace, Menlo, monospace;
  /* Named explicitly rather than left to --accent's other jobs: a link
     and a focus ring are READ, and a disabled label must be a real color
     and not an opacity over an unpredictable surface. */
  --link:#4B263B; --focus:#4B263B;
  --sel:#E2D9D8; --onsel:#38242F; --off:#988C8F;
}
/* Dark is a lit room, not an inverted one: the same plum world after dark. */
html[data-theme="dark"],
[data-look="original"][data-theme="dark"]{
  --ground:#171019; --sunk:#1E1421; --raised:#241729; --lift:#2E1D33;
  --ink:#F2E9EE; --soft:#C3AEBC; --muted:#A8919F; --faint:#9C8394;
  --line:#2C1E31; --firm:#43304A;
  /* The icons keep their own colors after dark — they are artwork, not
     chrome — but the surfaces they sit on have to come with us. */
  --tile:#3A2440;
  /* Lifted for a dark bar, and kept APART. Raising plum and rose together made
     them nearly the same value: the envelope's seal disappeared into its own
     body and First read as a play button in a box. Plum becomes the near-white
     structural ink, rose stays a mid dusty tone behind it, and the knockout
     goes dark so it still reads as a hole. */
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92; --ic-cream:#241729;
  --accent:#E1A5B5; --mauve:#D3AABC; --blue:#A2B9CB;
  --onacc:#1B1020; --onsem:#150E18; --tint:rgba(225,165,181,.10);
  --chrome:rgba(23,16,25,.95);
  --cta:#E1A5B5; --oncta:#1B1020;
  --room:dark;
  --veil:23,16,25;
  --veil-a:.38; --veil-b:.22; --veil-c:.68;
  --herofx:saturate(.78) brightness(.9) contrast(1.04);
  /* Named explicitly rather than left to --accent's other jobs: a link
     and a focus ring are READ, and a disabled label must be a real color
     and not an opacity over an unpredictable surface. */
  --link:#E1A5B5; --focus:#E1A5B5;
  --sel:#3B2B35; --onsel:#F2E9EE; --off:#7A7279;
}

/* STATUS COLORS ARE SEMANTIC, NOT THEMATIC (Jay, 2026-09-26). On track is
   green, needs attention is amber, blocked is red, in every palette: a dot,
   a badge or a label means the same thing whichever look is worn. Each
   palette used to carry its own --good, and most were a washed sage -- in
   80's, Hot Girl Summer and EMO Princess nearly gray -- so the Home release
   dot read as the palette's own color. One light set (in :root above) and
   one dark set (here), chosen to clear 4.5:1 on every palette's ground,
   sunk and raised surfaces (tests/semantic-colors.test.mjs). A dark room is
   the page's darkness, not the person's setting: a decorated look is dark
   even when the device is light, so it is listed by name as well. */
html[data-theme="dark"], html[data-room="dark"],
[data-look="original"][data-theme="dark"],
html:is([data-look="new-year"], [data-look="emerald-moon"], [data-look="prism"],
  [data-look="midnight-sparks"], [data-look="halloween"], [data-look="amber-velvet"],
  [data-look="evergreen"], [data-look="release-era"]){
  --good:#7FCF97; --warn:#EFCF4B; --stop:#F4847E;
  --destructive:#F4939C;
}
/* And the light-only looks are light rooms whatever the device says. */
html:is([data-look="enchanted"], [data-look="sanctuary"], [data-look="redhot"],
  [data-look="mono"]){
  --good:#2D6E45; --warn:#8A5700; --stop:#9B0D30;
  --destructive:#A8323F;
}

/* Colors that used to be written straight into rules.
   A literal in a rule does not change when the look does, so Red Hot would
   have kept a plum badge and Black & White a cream print. Each of these is
   the EXACT value the rule carried, so Original — and every look that does
   not name them — renders the same pixels it did before they were tokens.
   They live on :root only, not in the dark block: every one of these rules
   used one value in both modes, and the dark block is the list a look must
   complete (tests/themes.test.mjs), which these do not need to join.
   The `-rgb` ones are r,g,b triples, like --veil, because the same color is
   used at several strengths. tests/theme-colors.test.mjs keeps new literals
   out of the rules. */
:root{
  /* Her fan page's own colors (the HQ Fan page preview, direct.css): the same in every look. */
  --fanpage-ground:#120B14; --fanpage-raised:#22152A; --fanpage-ink:#F6F0F3; --fanpage-rose:#E1A5B5; --fanpage-firm:#4A3553; --fanpage-oncta:#1B1020;
  --blue-wash:rgba(92,106,128,.13);    /* the Mix tag */
  --good-wash:rgba(78,115,88,.14);     /* live, paid, an insertion, good art */
  --stop-wash:rgba(169,15,53,.10);     /* a deletion in a diff */
  --amber:196,142,58;                  /* the release band, a date conflict */
  --bad:#a33;                          /* failed, late, required */
  --late-rgb:163,51,51;                /* what will not go out, a late card */
  --said-bad:#b4413c;                  /* the Add-to sheet's error line */
  --done-rgb:47,111,107;               /* verified, done, an approved sound */
  --pick-rgb:122,75,143;               /* a selected sound, the 30s lane */
  --due:#8a5a12;                       /* missing, needs review, coming due */
  --onmark:#fff;                       /* the label on a solid status mark */
  --onphoto-rgb:251,246,241;           /* a control laid over a photograph (the portrait viewer's •••) */
  /* The Approved mark (R13): it sits on pictures, so it keeps its own
     ground in every look. */
  --approved-ground:rgb(0 0 0/.66); --approved-ink:#fff; --approved-check:#7FCF97;
  --onink-wash:rgba(255,255,255,.18);  /* a count on an ink-filled chip */
  --dim:rgba(64,38,56,.28);            /* behind the upload drawer */
  /* After dark, the song room washes its art into this rather than into the
     page: Original's own dark ground, which every dark look has inherited. */
  --dusk:23,16,25;
  /* A room's own state washes. Keyed to the ROOM below, not to the light/dark
     preference, exactly as the rules that used to carry them were. */
  --room-block:rgba(155,13,48,.06); --room-ok:rgba(63,99,73,.07);
  --unreach-wash:rgba(122,84,16,.06);
  --state-wait:#9A6A1C; --state-done:#2F6F6B;
}
html[data-room="dark"]{
  --room-block:rgba(224,128,138,.1); --room-ok:rgba(143,191,154,.1);
  --unreach-wash:rgba(239,207,75,.08);
  --state-wait:#D8A44E; --state-done:#7FBDB4;
}

/* ------------------------------------------------ the looks
   Ten approved looks, each a token swap over the one layout. There is no
   second app here and no per-theme stylesheet: every rule already written
   picks these up, which is the whole reason a look can be changed without
   anything moving on the page.

   The selector is written twice on purpose. `html[data-look]` is the page
   itself, at the same specificity as the dark block and later in the file, so
   it wins there. The bare `[data-look]` is for the swatches inside Redecorate:
   a small element carrying the attribute resolves the SAME hexes locally, so
   the grid shows the real palette rather than a picture of one.

   `data-look` is deliberately a SEPARATE attribute from `data-theme`. Each of
   these carries its own complete palette, so it decides light or dark for
   itself — and the person's own light/dark preference is left exactly where it
   was, waiting, for when they go back to Original.

   Every value below was checked against the paper it sits on: ink, soft,
   muted, faint, accent, the three semantic colors and the solid button's
   text all clear 4.5:1 in all ten. tests/themes.test.mjs recomputes that,
   so a future edit to a hex cannot quietly drop one under. */
/* October. Black, plum and wine; elegant cobwebs, candlelight, a black cat. */
html[data-look="halloween"], [data-look="halloween"]{
  --ground:#120912; --sunk:#180D18; --raised:#1F121F; --lift:#2C182C;
  --ink:#F4E8EF; --soft:#CBB2C0; --muted:#B198A5; --faint:#A48C99;
  --line:#2C182C; --firm:#4A2C4A;
  --accent:#EBA9BA; --mauve:#D6A0B2; --blue:#A6BCCE;
  --cta:#8C0B2B; --oncta:#FFF3F5; --tile:#33203A;
  --onacc:#1A0D1A; --onsem:#150B15;
  --tint:rgba(235,169,186,.10);
  --chrome:rgba(18,9,18,.95);
  --veil:18,9,18;
  --veil-a:.34; --veil-b:.18; --veil-c:.66;
  --herofx:saturate(.8) brightness(.86) contrast(1.04) hue-rotate(-6deg);
  --room:dark;
  /* Lifted for a dark room, and kept apart: raising plum and rose to the
     same value once made First's envelope seal disappear into its own
     body. The knockout is this room's own surface. */
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#1F121F;
  /* Named explicitly rather than left to --accent's other jobs: a link
     and a focus ring are READ, and a disabled label must be a real color
     and not an opacity over an unpredictable surface. */
  --link:#EBA9BA; --focus:#EBA9BA;
  --sel:#392630; --onsel:#F4E8EF; --off:#786D75;
}
/* November. Cocoa, amber and oxblood; autumn leaves and a quiet table. */
html[data-look="amber-velvet"], [data-look="amber-velvet"]{
  --ground:#150D0A; --sunk:#1C120D; --raised:#231710; --lift:#312016;
  --ink:#F6EBE0; --soft:#D3BBA6; --muted:#BBA18B; --faint:#AE947E;
  --line:#312016; --firm:#4E3323;
  --accent:#E8B27E; --mauve:#D9A184; --blue:#A9BBC2;
  --cta:#7E1226; --oncta:#FFF2EF; --tile:#3A2618;
  --onacc:#1B1109; --onsem:#150D08;
  --tint:rgba(232,178,126,.10);
  --chrome:rgba(21,13,10,.95);
  --veil:21,13,10;
  --veil-a:.34; --veil-b:.18; --veil-c:.66;
  --herofx:saturate(.95) sepia(.2) brightness(.9) contrast(1.03);
  --room:dark;
  /* Lifted for a dark room, and kept apart: raising plum and rose to the
     same value once made First's envelope seal disappear into its own
     body. The knockout is this room's own surface. */
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#231710;
  /* Named explicitly rather than left to --accent's other jobs: a link
     and a focus ring are READ, and a disabled label must be a real color
     and not an opacity over an unpredictable surface. */
  --link:#E8B27E; --focus:#E8B27E;
  --sel:#3B2B1F; --onsel:#F6EBE0; --off:#7A716A;
}
/* December. Deep evergreen and cranberry, warm metal, greenery, candles. */
html[data-look="evergreen"], [data-look="evergreen"]{
  --ground:#0C1410; --sunk:#101A14; --raised:#142119; --lift:#1D2E23;
  --ink:#ECF3EC; --soft:#B6C8B9; --muted:#9CB1A0; --faint:#8FA594;
  --line:#1D2E23; --firm:#2F4838;
  --accent:#E5B98A; --mauve:#D9A0A6; --blue:#A3BDC4;
  --cta:#8A1226; --oncta:#FFF3F2; --tile:#1F3226;
  --onacc:#0B140E; --onsem:#0A120C;
  --tint:rgba(229,185,138,.10);
  --chrome:rgba(12,20,16,.95);
  --veil:12,20,16;
  --veil-a:.34; --veil-b:.18; --veil-c:.66;
  --herofx:saturate(.85) brightness(.86) contrast(1.04) hue-rotate(14deg);
  --room:dark;
  /* Lifted for a dark room, and kept apart: raising plum and rose to the
     same value once made First's envelope seal disappear into its own
     body. The knockout is this room's own surface. */
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#142119;
  /* Named explicitly rather than left to --accent's other jobs: a link
     and a focus ring are READ, and a disabled label must be a real color
     and not an opacity over an unpredictable surface. */
  --link:#E5B98A; --focus:#E5B98A;
  --sel:#333226; --onsel:#ECF3EC; --off:#717873;
}
/* June. Aubergine with jewelled, prismatic light — not rainbow striping. */
html[data-look="prism"], [data-look="prism"]{
  --ground:#140C1C; --sunk:#1A1024; --raised:#20142C; --lift:#2C1C3D;
  --ink:#F1E9F7; --soft:#C3B2D2; --muted:#A996BB; --faint:#9D8AB0;
  --line:#2C1C3D; --firm:#452D5C;
  --accent:#C7A9F0; --mauve:#D8A4C6; --blue:#93C4DC;
  --cta:#5E2091; --oncta:#F8F2FF; --tile:#31204A;
  --onacc:#150C1E; --onsem:#110A18;
  --tint:rgba(199,169,240,.11);
  --chrome:rgba(20,12,28,.95);
  --veil:20,12,28;
  --veil-a:.34; --veil-b:.18; --veil-c:.66;
  --herofx:saturate(1) brightness(.9) contrast(1.03);
  --room:dark;
  /* Lifted for a dark room, and kept apart: raising plum and rose to the
     same value once made First's envelope seal disappear into its own
     body. The knockout is this room's own surface. */
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#20142C;
  /* Named explicitly rather than left to --accent's other jobs: a link
     and a focus ring are READ, and a disabled label must be a real color
     and not an opacity over an unpredictable surface. */
  --link:#C7A9F0; --focus:#C7A9F0;
  --sel:#342842; --onsel:#F1E9F7; --off:#776F7F;
}
/* July. Navy, red and pearl; a few sparks over the water. */
html[data-look="midnight-sparks"], [data-look="midnight-sparks"]{
  --ground:#0B1120; --sunk:#0F1628; --raised:#131C31; --lift:#1C2743;
  --ink:#EDF1F8; --soft:#B4C0D4; --muted:#9BA9C0; --faint:#8E9DB6;
  --line:#1C2743; --firm:#2C3B60;
  --accent:#9FC1EA; --mauve:#D6A2AE; --blue:#9FC1EA;
  --cta:#9A1226; --oncta:#FFF2F3; --tile:#1E2B48;
  --onacc:#0A1020; --onsem:#080D1A;
  --tint:rgba(159,193,234,.11);
  --chrome:rgba(11,17,32,.95);
  --veil:11,17,32;
  --veil-a:.34; --veil-b:.18; --veil-c:.66;
  --herofx:saturate(.88) brightness(.88) contrast(1.04) hue-rotate(-18deg);
  --room:dark;
  /* Lifted for a dark room, and kept apart: raising plum and rose to the
     same value once made First's envelope seal disappear into its own
     body. The knockout is this room's own surface. */
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#131C31;
  /* Named explicitly rather than left to --accent's other jobs: a link
     and a focus ring are READ, and a disabled label must be a real color
     and not an opacity over an unpredictable surface. */
  --link:#9FC1EA; --focus:#9FC1EA;
  --sel:#263144; --onsel:#EDF1F8; --off:#717681;
}
/* January. Black and plum, pearl and champagne gold; starbursts. */
html[data-look="new-year"], [data-look="new-year"]{
  --ground:#110B12; --sunk:#170F18; --raised:#1D141F; --lift:#291B2C;
  --ink:#F5EFE6; --soft:#CEC0AE; --muted:#B5A692; --faint:#A89985;
  --line:#291B2C; --firm:#453048;
  --accent:#E3C489; --mauve:#D3A6B6; --blue:#A6BBCD;
  --cta:#8A1030; --oncta:#FFF3F4; --tile:#31213A;
  --onacc:#1A1009; --onsem:#140C14;
  --tint:rgba(227,196,137,.10);
  --chrome:rgba(17,11,18,.95);
  --veil:17,11,18;
  --veil-a:.34; --veil-b:.18; --veil-c:.66;
  --herofx:saturate(.85) sepia(.12) brightness(.88) contrast(1.03);
  --room:dark;
  /* Lifted for a dark room, and kept apart: raising plum and rose to the
     same value once made First's envelope seal disappear into its own
     body. The knockout is this room's own surface. */
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#1D141F;
  /* Named explicitly rather than left to --accent's other jobs: a link
     and a focus ring are READ, and a disabled label must be a real color
     and not an opacity over an unpredictable surface. */
  --link:#E3C489; --focus:#E3C489;
  --sel:#372C27; --onsel:#F5EFE6; --off:#787271;
}
/* March. Emerald and gold under a full moon; stone and candlelight. */
html[data-look="emerald-moon"], [data-look="emerald-moon"]{
  --ground:#0A140F; --sunk:#0E1A13; --raised:#122118; --lift:#1A2E21;
  --ink:#EBF4EE; --soft:#B2C9BB; --muted:#98B1A2; --faint:#8AA595;
  --line:#1A2E21; --firm:#2A4833;
  --accent:#E6CE8C; --mauve:#CFAEB8; --blue:#A0BEC6;
  --cta:#12603A; --oncta:#F2FBF5; --tile:#1B3325;
  --onacc:#0A140D; --onsem:#08110B;
  --tint:rgba(230,206,140,.10);
  --chrome:rgba(10,20,15,.95);
  --veil:10,20,15;
  --veil-a:.34; --veil-b:.18; --veil-c:.66;
  --herofx:saturate(.85) brightness(.84) contrast(1.04) hue-rotate(24deg);
  --room:dark;
  /* Lifted for a dark room, and kept apart: raising plum and rose to the
     same value once made First's envelope seal disappear into its own
     body. The knockout is this room's own surface. */
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#122118;
  /* Named explicitly rather than left to --accent's other jobs: a link
     and a focus ring are READ, and a disabled label must be a real color
     and not an opacity over an unpredictable surface. */
  --link:#E6CE8C; --focus:#E6CE8C;
  --sel:#323526; --onsel:#EBF4EE; --off:#6F7973;
}
/* Year round, chosen by hand. Amethyst and wine under stage lights. */
html[data-look="release-era"], [data-look="release-era"]{
  --ground:#150A12; --sunk:#1C0E18; --raised:#23131E; --lift:#321A29;
  --ink:#F6E9EF; --soft:#D0AFBE; --muted:#B795A4; --faint:#AA8898;
  --line:#321A29; --firm:#4E2A3F;
  --accent:#E7A6C0; --mauve:#DBA2B4; --blue:#A7BACD;
  --cta:#7C0F2E; --oncta:#FFF2F5; --tile:#3A1F30;
  --onacc:#1A0A12; --onsem:#140810;
  --tint:rgba(231,166,192,.10);
  --chrome:rgba(21,10,18,.95);
  --veil:21,10,18;
  --veil-a:.34; --veil-b:.18; --veil-c:.66;
  --herofx:saturate(1) brightness(.9) contrast(1.05);
  --room:dark;
  /* Lifted for a dark room, and kept apart: raising plum and rose to the
     same value once made First's envelope seal disappear into its own
     body. The knockout is this room's own surface. */
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#23131E;
  /* Named explicitly rather than left to --accent's other jobs: a link
     and a focus ring are READ, and a disabled label must be a real color
     and not an opacity over an unpredictable surface. */
  --link:#E7A6C0; --focus:#E7A6C0;
  --sel:#3B2631; --onsel:#F6E9EF; --off:#7A6E75;
}
/* April. Luminous ivory and lilac; white flowers and a little magic. */
html[data-look="enchanted"], [data-look="enchanted"]{
  --ground:#F8F5FC; --sunk:#F1ECF8; --raised:#FFFDFF; --lift:#E8E0F3;
  --ink:#33234A; --soft:#524070; --muted:#5E4A7C; --faint:#6E5A8C;
  --line:#E4DCF0; --firm:#D3C7E6;
  --accent:#4A2A75; --mauve:#8A5E92; --blue:#4F6288;
  --cta:#4A2A75; --oncta:#FFFDFF; --tile:#EDE4F8;
  --onacc:#FFFDFF; --onsem:#FFFDFF;
  --tint:rgba(74,42,117,.06);
  --chrome:rgba(248,245,252,.95);
  --veil:248,245,252;
  --veil-a:.58; --veil-b:.42; --veil-c:.86;
  --herofx:saturate(.72) brightness(1.1) contrast(.94) hue-rotate(6deg);
  --room:light;
  /* The icon family keeps its own ink — it is artwork, not chrome —
     but the knockout has to be this room's paper. */
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61;
  --ic-cream:#F8F5FC;
  /* Named explicitly rather than left to --accent's other jobs: a link
     and a focus ring are READ, and a disabled label must be a real color
     and not an opacity over an unpredictable surface. */
  --link:#4A2A75; --focus:#4A2A75;
  --sel:#E0D9E9; --onsel:#33234A; --off:#948BA2;
}
/* Year round, chosen by hand. Warm ivory and whisper lilac. Calm. */
html[data-look="sanctuary"], [data-look="sanctuary"]{
  --ground:#FAF7F6; --sunk:#F3EFF3; --raised:#FFFDFC; --lift:#EBE4EC;
  --ink:#3A2C42; --soft:#584866; --muted:#645471; --faint:#73627F;
  --line:#E7DFE6; --firm:#D6CBD9;
  --accent:#513468; --mauve:#8A6288; --blue:#4E6280;
  --cta:#513468; --oncta:#FFFDFC; --tile:#EFE7F0;
  --onacc:#FFFDFC; --onsem:#FFFDFC;
  --tint:rgba(81,52,104,.06);
  --chrome:rgba(250,247,246,.95);
  --veil:250,247,246;
  --veil-a:.58; --veil-b:.42; --veil-c:.86;
  --herofx:saturate(.6) brightness(1.12) contrast(.92);
  --room:light;
  /* The icon family keeps its own ink — it is artwork, not chrome —
     but the knockout has to be this room's paper. */
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61;
  --ic-cream:#FAF7F6;
  /* Named explicitly rather than left to --accent's other jobs: a link
     and a focus ring are READ, and a disabled label must be a real color
     and not an opacity over an unpredictable surface. */
  --link:#513468; --focus:#513468;
  --sel:#E2DCE2; --onsel:#3A2C42; --off:#968D98;
}

/* ------------------------------------------------ the color-only palettes
   Eleven more looks, and the one structural difference from the ten above:
   these come in two versions, and which one you get is the person's own
   light/dark setting rather than something the look decides.

   That is why the selector carries BOTH attributes. The ten decorated looks
   key on `data-look` alone because each of them is a single room with a fixed
   lightness; a color-only palette is a pair, so it keys on `data-look` and
   `data-theme` together and the page always stamps a resolved `light` or
   `dark` — including when the preference is "match my device", which is
   resolved in the browser and re-resolved when the device changes.

   Written twice, like the blocks above: the `html[...]` form is the page, the
   bare form is the swatch inside the picker, which carries the same two
   attributes so a card can show a palette's light version and its dark
   version side by side and both be real.

   Nothing here is decorative. A color-only palette has no entry in
   DECOR_PLANS, so decorFor() returns nothing and the ornament layers are
   emptied rather than inherited from whatever was on before.

   Derived rather than hand-picked, from the three colors each palette was
   given — background, main text, accent — so all twenty-two are consistent
   with each other and with the nine above, and so the contrast floor holds by
   construction. tests/themes.test.mjs recomputes every pair. */
/* Y2K. Icy lilac, cool silver-gray and violet. */
html[data-look="y2k"][data-theme="light"],
[data-look="y2k"][data-theme="light"]{
  --ground:#F0EDF7; --sunk:#E7E4EE; --raised:#F8F7FB; --lift:#DAD7E2;
  --ink:#282335; --soft:#544F60; --muted:#686473; --faint:#6F6A79;
  --line:#DCD9E4; --firm:#C4C1CC;
  --accent:#6246A6; --mauve:#603E85; --blue:#525A80;
  --cta:#6246A6; --oncta:#F0EDF7; --tile:#DFD9ED;
  --onacc:#F0EDF7; --onsem:#F0EDF7;
  --link:#6246A6; --focus:#6246A6;
  --sel:#DCD6EC; --onsel:#282335; --off:#8C8796;
  --tint:rgba(98,70,166,.08);
  --chrome:rgba(240,237,247,.95);
  --veil:240,237,247;
  --veil-a:.66; --veil-b:.54; --veil-c:.88;
  --herofx:saturate(.86) brightness(1.03);
  --room:light;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61;
  --ic-cream:#F0EDF7;
}
html[data-look="y2k"][data-theme="dark"],
[data-look="y2k"][data-theme="dark"]{
  --ground:#181422; --sunk:#221E2C; --raised:#282432; --lift:#363240;
  --ink:#F0EDF7; --soft:#C0BDC8; --muted:#ABA8B3; --faint:#95929E;
  --line:#302C39; --firm:#504C59;
  --accent:#B6A0ED; --mauve:#C2A5DE; --blue:#A6B4D2;
  --cta:#B6A0ED; --oncta:#181422; --tile:#3B334F;
  --onacc:#181422; --onsem:#181422;
  --link:#B6A0ED; --focus:#B6A0ED;
  --sel:#342D47; --onsel:#F0EDF7; --off:#797682;
  --tint:rgba(182,160,237,.08);
  --chrome:rgba(24,20,34,.95);
  --veil:24,20,34;
  --veil-a:.38; --veil-b:.22; --veil-c:.68;
  --herofx:saturate(.8) brightness(.88) contrast(1.04);
  --room:dark;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#282432;
}
/* 80's. Pink and purple, with restrained aqua highlights. */
html[data-look="eighties"][data-theme="light"],
[data-look="eighties"][data-theme="light"]{
  --ground:#FAEFF7; --sunk:#F1E5EE; --raised:#FDF8FB; --lift:#E3D8E2;
  --ink:#2C1B34; --soft:#594A5F; --muted:#6E5F72; --faint:#796A7C;
  --line:#E5DAE4; --firm:#CDC0CC;
  --accent:#A62870; --mauve:#8C2B62; --blue:#605476;
  --cta:#A62870; --oncta:#FAEFF7; --tile:#F0D7E7;
  --onacc:#FAEFF7; --onsem:#FAEFF7;
  --link:#A62870; --focus:#A62870;
  --sel:#EED3E4; --onsel:#2C1B34; --off:#958897;
  --tint:rgba(166,40,112,.08);
  --chrome:rgba(250,239,247,.95);
  --veil:250,239,247;
  --veil-a:.66; --veil-b:.54; --veil-c:.88;
  --herofx:saturate(.86) brightness(1.03);
  --room:light;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61;
  --ic-cream:#FAEFF7;
}
html[data-look="eighties"][data-theme="dark"],
[data-look="eighties"][data-theme="dark"]{
  --ground:#171326; --sunk:#211D30; --raised:#282436; --lift:#363244;
  --ink:#F8F3FF; --soft:#C6C2CF; --muted:#B0ABBA; --faint:#9A95A4;
  --line:#302C3E; --firm:#524D5E;
  --accent:#F08CC6; --mauve:#E898C4; --blue:#B2B0CA;
  --cta:#F08CC6; --oncta:#171326; --tile:#472E49;
  --onacc:#171326; --onsem:#171326;
  --link:#F08CC6; --focus:#F08CC6;
  --sel:#3E2943; --onsel:#F8F3FF; --off:#7C7888;
  --tint:rgba(240,140,198,.08);
  --chrome:rgba(23,19,38,.95);
  --veil:23,19,38;
  --veil-a:.38; --veil-b:.22; --veil-c:.68;
  --herofx:saturate(.8) brightness(.88) contrast(1.04);
  --room:dark;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#282436;
}
/* 50's. Warm cream, mint and evergreen, with a little muted coral. */
html[data-look="fifties"][data-theme="light"],
[data-look="fifties"][data-theme="light"]{
  --ground:#FAF4E9; --sunk:#F1ECE1; --raised:#FDFAF5; --lift:#E3E0D6;
  --ink:#283E38; --soft:#56665F; --muted:#66736D; --faint:#66736C;
  --line:#E5E2D7; --firm:#CCCCC2;
  --accent:#28685B; --mauve:#3A5455; --blue:#466171;
  --cta:#28685B; --oncta:#FAF4E9; --tile:#E1E3D8;
  --onacc:#FAF4E9; --onsem:#FAF4E9;
  --link:#28685B; --focus:#28685B;
  --sel:#DDE0D5; --onsel:#283E38; --off:#889088;
  --tint:rgba(40,104,91,.08);
  --chrome:rgba(250,244,233,.95);
  --veil:250,244,233;
  --veil-a:.66; --veil-b:.54; --veil-c:.88;
  --herofx:saturate(.86) brightness(1.03);
  --room:light;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61;
  --ic-cream:#FAF4E9;
}
html[data-look="fifties"][data-theme="dark"],
[data-look="fifties"][data-theme="dark"]{
  --ground:#142B26; --sunk:#1E342F; --raised:#253A34; --lift:#334640;
  --ink:#F4EFE3; --soft:#C3C4B9; --muted:#ACB0A7; --faint:#969D94;
  --line:#2D413B; --firm:#4E5E57;
  --accent:#80C2AD; --mauve:#9FBBB4; --blue:#9BBBC5;
  --cta:#80C2AD; --oncta:#142B26; --tile:#2C4C44;
  --onacc:#142B26; --onsem:#142B26;
  --link:#80C2AD; --focus:#80C2AD;
  --sel:#27463E; --onsel:#F4EFE3; --off:#79837B;
  --tint:rgba(128,194,173,.08);
  --chrome:rgba(20,43,38,.95);
  --veil:20,43,38;
  --veil-a:.38; --veil-b:.22; --veil-c:.68;
  --herofx:saturate(.8) brightness(.88) contrast(1.04);
  --room:dark;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#253A34;
}
/* Disco. Champagne, espresso-plum and antique gold. */
html[data-look="disco"][data-theme="light"],
[data-look="disco"][data-theme="light"]{
  --ground:#F8F0E4; --sunk:#EFE7DC; --raised:#FCF8F3; --lift:#E3D9D1;
  --ink:#352135; --soft:#604F5C; --muted:#73636D; --faint:#796A72;
  --line:#E4DBD2; --firm:#CDC2BE;
  --accent:#825818; --mauve:#754A29; --blue:#585E64;
  --cta:#825818; --oncta:#F8F0E4; --tile:#EADECC;
  --onacc:#F8F0E4; --onsem:#F8F0E4;
  --link:#825818; --focus:#825818;
  --sel:#E7DBC7; --onsel:#352135; --off:#95888C;
  --tint:rgba(130,88,24,.08);
  --chrome:rgba(248,240,228,.95);
  --veil:248,240,228;
  --veil-a:.66; --veil-b:.54; --veil-c:.88;
  --herofx:saturate(.86) brightness(1.03);
  --room:light;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61;
  --ic-cream:#F8F0E4;
}
html[data-look="disco"][data-theme="dark"],
[data-look="disco"][data-theme="dark"]{
  --ground:#1C131A; --sunk:#261D23; --raised:#2D2429; --lift:#3B3236;
  --ink:#FAF0E1; --soft:#C9BFB5; --muted:#B3A9A1; --faint:#9D938D;
  --line:#342B30; --firm:#564C4E;
  --accent:#D9B47B; --mauve:#D9B294; --blue:#ADB8BB;
  --cta:#D9B47B; --oncta:#1C131A; --tile:#46362F;
  --onacc:#1C131A; --onsem:#1C131A;
  --link:#D9B47B; --focus:#D9B47B;
  --sel:#3E302B; --onsel:#FAF0E1; --off:#807674;
  --tint:rgba(217,180,123,.08);
  --chrome:rgba(28,19,26,.95);
  --veil:28,19,26;
  --veil-a:.38; --veil-b:.22; --veil-c:.68;
  --herofx:saturate(.8) brightness(.88) contrast(1.04);
  --room:dark;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#2D2429;
}
/* Modern. Warm neutrals, charcoal and cool gray. */
html[data-look="modern"][data-theme="light"],
[data-look="modern"][data-theme="light"]{
  --ground:#F4F2EF; --sunk:#EAE9E6; --raised:#FAF9F8; --lift:#DDDBD9;
  --ink:#202124; --soft:#4F4F51; --muted:#646465; --faint:#6E6F6F;
  --line:#DFDDDB; --firm:#C5C4C2;
  --accent:#424A50; --mauve:#4B414E; --blue:#4C5B6F;
  --cta:#424A50; --oncta:#F4F2EF; --tile:#DFDEDC;
  --onacc:#F4F2EF; --onsem:#F4F2EF;
  --link:#424A50; --focus:#424A50;
  --sel:#DBDAD9; --onsel:#202124; --off:#8D8C8C;
  --tint:rgba(66,74,80,.08);
  --chrome:rgba(244,242,239,.95);
  --veil:244,242,239;
  --veil-a:.66; --veil-b:.54; --veil-c:.88;
  --herofx:saturate(.86) brightness(1.03);
  --room:light;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61;
  --ic-cream:#F4F2EF;
}
html[data-look="modern"][data-theme="dark"],
[data-look="modern"][data-theme="dark"]{
  --ground:#17191B; --sunk:#212325; --raised:#27292B; --lift:#363739;
  --ink:#F2F1EF; --soft:#C2C1C0; --muted:#ACACAB; --faint:#969696;
  --line:#2F3132; --firm:#505152;
  --accent:#B9C2C8; --mauve:#C4BBC6; --blue:#A7BBCA;
  --cta:#B9C2C8; --oncta:#17191B; --tile:#3B3E41;
  --onacc:#17191B; --onsem:#17191B;
  --link:#B9C2C8; --focus:#B9C2C8;
  --sel:#34373A; --onsel:#F2F1EF; --off:#7A7A7A;
  --tint:rgba(185,194,200,.08);
  --chrome:rgba(23,25,27,.95);
  --veil:23,25,27;
  --veil-a:.38; --veil-b:.22; --veil-c:.68;
  --herofx:saturate(.8) brightness(.88) contrast(1.04);
  --room:dark;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#27292B;
}
/* Spring. Ivory, sage and a restrained soft lavender. */
html[data-look="spring"][data-theme="light"],
[data-look="spring"][data-theme="light"]{
  --ground:#F4F2E9; --sunk:#EBEAE1; --raised:#FAF9F5; --lift:#DEDED5;
  --ink:#2C3B32; --soft:#58635A; --muted:#677168; --faint:#677168;
  --line:#E0E0D7; --firm:#C8CAC1;
  --accent:#4C6B53; --mauve:#525650; --blue:#4E6170;
  --cta:#4C6B53; --oncta:#F4F2E9; --tile:#E0E2D7;
  --onacc:#F4F2E9; --onsem:#F4F2E9;
  --link:#4C6B53; --focus:#4C6B53;
  --sel:#DCDFD4; --onsel:#2C3B32; --off:#878E85;
  --tint:rgba(76,107,83,.08);
  --chrome:rgba(244,242,233,.95);
  --veil:244,242,233;
  --veil-a:.66; --veil-b:.54; --veil-c:.88;
  --herofx:saturate(.86) brightness(1.03);
  --room:light;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61;
  --ic-cream:#F4F2E9;
}
html[data-look="spring"][data-theme="dark"],
[data-look="spring"][data-theme="dark"]{
  --ground:#18251E; --sunk:#222E27; --raised:#28342D; --lift:#36423A;
  --ink:#F0F2E8; --soft:#C0C5BC; --muted:#ABB0A7; --faint:#959C93;
  --line:#303C34; --firm:#505A53;
  --accent:#A6C1A0; --mauve:#B8BBAC; --blue:#A3BBC2;
  --cta:#A6C1A0; --oncta:#18251E; --tile:#37473B;
  --onacc:#18251E; --onsem:#18251E;
  --link:#A6C1A0; --focus:#A6C1A0;
  --sel:#324135; --onsel:#F0F2E8; --off:#798179;
  --tint:rgba(166,193,160,.08);
  --chrome:rgba(24,37,30,.95);
  --veil:24,37,30;
  --veil-a:.38; --veil-b:.22; --veil-c:.68;
  --herofx:saturate(.8) brightness(.88) contrast(1.04);
  --room:dark;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#28342D;
}
/* Fall. Cocoa, cinnamon, amber and wine. */
html[data-look="fall"][data-theme="light"],
[data-look="fall"][data-theme="light"]{
  --ground:#F8EDE0; --sunk:#F0E4D7; --raised:#FCF7F1; --lift:#E4D8CB;
  --ink:#402A22; --soft:#68554C; --muted:#7B685F; --faint:#7B6960;
  --line:#E6DACD; --firm:#D0C2B6;
  --accent:#8D482B; --mauve:#7C4036; --blue:#5B5A68;
  --cta:#8D482B; --oncta:#F8EDE0; --tile:#EBD9CA;
  --onacc:#F8EDE0; --onsem:#F8EDE0;
  --link:#8D482B; --focus:#8D482B;
  --sel:#E9D6C7; --onsel:#402A22; --off:#97867C;
  --tint:rgba(141,72,43,.08);
  --chrome:rgba(248,237,224,.95);
  --veil:248,237,224;
  --veil-a:.66; --veil-b:.54; --veil-c:.88;
  --herofx:saturate(.86) brightness(1.03);
  --room:light;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61;
  --ic-cream:#F8EDE0;
}
html[data-look="fall"][data-theme="dark"],
[data-look="fall"][data-theme="dark"]{
  --ground:#231918; --sunk:#2C2221; --raised:#332927; --lift:#403634;
  --ink:#F4EBDD; --soft:#C6BDB2; --muted:#B1A89E; --faint:#9C938A;
  --line:#3A302E; --firm:#59504B;
  --accent:#D4A06B; --mauve:#D6A589; --blue:#ACB4B8;
  --cta:#D4A06B; --oncta:#231918; --tile:#4A372A;
  --onacc:#231918; --onsem:#231918;
  --link:#D4A06B; --focus:#D4A06B;
  --sel:#433127; --onsel:#F4EBDD; --off:#817771;
  --tint:rgba(212,160,107,.08);
  --chrome:rgba(35,25,24,.95);
  --veil:35,25,24;
  --veil-a:.38; --veil-b:.22; --veil-c:.68;
  --herofx:saturate(.8) brightness(.88) contrast(1.04);
  --room:dark;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#332927;
}
/* Hot Girl Summer. Sun-washed peach, berry and confident pink. */
html[data-look="hot-girl-summer"][data-theme="light"],
[data-look="hot-girl-summer"][data-theme="light"]{
  --ground:#FFF3EB; --sunk:#F6EAE3; --raised:#FFFAF6; --lift:#EADCD7;
  --ink:#3F2031; --soft:#694E5A; --muted:#7C646D; --faint:#836A72;
  --line:#ECDED8; --firm:#D5C5C2;
  --accent:#A92556; --mauve:#8E2951; --blue:#605370;
  --cta:#A92556; --oncta:#FFF3EB; --tile:#F5DAD9;
  --onacc:#FFF3EB; --onsem:#FFF3EB;
  --link:#A92556; --focus:#A92556;
  --sel:#F3D6D6; --onsel:#3F2031; --off:#9E898D;
  --tint:rgba(169,37,86,.08);
  --chrome:rgba(255,243,235,.95);
  --veil:255,243,235;
  --veil-a:.66; --veil-b:.54; --veil-c:.88;
  --herofx:saturate(.86) brightness(1.03);
  --room:light;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61;
  --ic-cream:#FFF3EB;
}
html[data-look="hot-girl-summer"][data-theme="dark"],
[data-look="hot-girl-summer"][data-theme="dark"]{
  --ground:#28131F; --sunk:#321D28; --raised:#38242E; --lift:#46323B;
  --ink:#FFF0E8; --soft:#D0BFBC; --muted:#BAA9A8; --faint:#A59394;
  --line:#402B35; --firm:#604C53;
  --accent:#FF91B7; --mauve:#F29CBA; --blue:#B5B1C7;
  --cta:#FF91B7; --oncta:#28131F; --tile:#572F40;
  --onacc:#28131F; --onsem:#28131F;
  --link:#FF91B7; --focus:#FF91B7;
  --sel:#4F2A3A; --onsel:#FFF0E8; --off:#897679;
  --tint:rgba(255,145,183,.08);
  --chrome:rgba(40,19,31,.95);
  --veil:40,19,31;
  --veil-a:.38; --veil-b:.22; --veil-c:.68;
  --herofx:saturate(.8) brightness(.88) contrast(1.04);
  --room:dark;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#38242E;
}
/* Brat. Sharp acid lime against pale neutrals or charcoal. */
html[data-look="brat"][data-theme="light"],
[data-look="brat"][data-theme="light"]{
  --ground:#F1F4EA; --sunk:#E7EAE0; --raised:#F9FAF6; --lift:#D9DCD2;
  --ink:#171B12; --soft:#474B42; --muted:#5D6057; --faint:#6D7067;
  --line:#DBDED4; --firm:#C1C4BA;
  --accent:#3E6500; --mauve:#48521A; --blue:#4B605F;
  --cta:#B5DC45; --oncta:#171B12; --tile:#DCE3CE;
  --onacc:#F1F4EA; --onsem:#F1F4EA;
  --link:#3E6500; --focus:#3E6500;
  --sel:#D8E0C9; --onsel:#171B12; --off:#8A8E85;
  --tint:rgba(62,101,0,.08);
  --chrome:rgba(241,244,234,.95);
  --veil:241,244,234;
  --veil-a:.66; --veil-b:.54; --veil-c:.88;
  --herofx:saturate(.86) brightness(1.03);
  --room:light;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61;
  --ic-cream:#F1F4EA;
}
html[data-look="brat"][data-theme="dark"],
[data-look="brat"][data-theme="dark"]{
  --ground:#171B12; --sunk:#21251C; --raised:#272B22; --lift:#363930;
  --ink:#F1F4EA; --soft:#C1C4BA; --muted:#ABAFA5; --faint:#95998F;
  --line:#2F332A; --firm:#50534A;
  --accent:#B5DC45; --mauve:#C2CC70; --blue:#A6C0B0;
  --cta:#B5DC45; --oncta:#171B12; --tile:#3A451D;
  --onacc:#171B12; --onsem:#171B12;
  --link:#B5DC45; --focus:#B5DC45;
  --sel:#333E1B; --onsel:#F1F4EA; --off:#797D73;
  --tint:rgba(181,220,69,.08);
  --chrome:rgba(23,27,18,.95);
  --veil:23,27,18;
  --veil-a:.38; --veil-b:.22; --veil-c:.68;
  --herofx:saturate(.8) brightness(.88) contrast(1.04);
  --room:dark;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#272B22;
}
/* EMO Princess. Blush, near-black, dusty pink and berry. Romantic and grown up. */
html[data-look="emo-princess"][data-theme="light"],
[data-look="emo-princess"][data-theme="light"]{
  --ground:#F9EBF2; --sunk:#F0E2E9; --raised:#FCF6F9; --lift:#E3D4DB;
  --ink:#301824; --soft:#5C4651; --muted:#705C66; --faint:#7B6772;
  --line:#E5D6DD; --firm:#CDBDC5;
  --accent:#A62960; --mauve:#8C2B58; --blue:#605472;
  --cta:#A62960; --oncta:#F9EBF2; --tile:#EFD4E0;
  --onacc:#F9EBF2; --onsem:#F9EBF2;
  --link:#A62960; --focus:#A62960;
  --sel:#EDD0DE; --onsel:#301824; --off:#98848E;
  --tint:rgba(166,41,96,.08);
  --chrome:rgba(249,235,242,.95);
  --veil:249,235,242;
  --veil-a:.66; --veil-b:.54; --veil-c:.88;
  --herofx:saturate(.86) brightness(1.03);
  --room:light;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61;
  --ic-cream:#F9EBF2;
}
html[data-look="emo-princess"][data-theme="dark"],
[data-look="emo-princess"][data-theme="dark"]{
  --ground:#160F18; --sunk:#201821; --raised:#271E28; --lift:#352C35;
  --ink:#F4DCE8; --soft:#C3AFBA; --muted:#AD9AA5; --faint:#978691;
  --line:#2E262F; --firm:#50444E;
  --accent:#D85D8F; --mauve:#D87AA0; --blue:#ADA7BF;
  --cta:#D65388; --oncta:#160F18; --tile:#412032;
  --onacc:#160F18; --onsem:#160F18;
  --link:#D85D8F; --focus:#D85D8F;
  --sel:#391D2D; --onsel:#F4DCE8; --off:#7A6B76;
  --tint:rgba(216,93,143,.08);
  --chrome:rgba(22,15,24,.95);
  --veil:22,15,24;
  --veil-a:.38; --veil-b:.22; --veil-c:.68;
  --herofx:saturate(.8) brightness(.88) contrast(1.04);
  --room:dark;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#271E28;
}
/* Tribute to Prince. Deep aubergine, ivory and luminous purple. A color tribute only. */
html[data-look="prince"][data-theme="light"],
[data-look="prince"][data-theme="light"]{
  --ground:#F3ECFA; --sunk:#EAE2F1; --raised:#FAF6FD; --lift:#DDD4E5;
  --ink:#29133D; --soft:#554367; --muted:#6A5879; --faint:#776685;
  --line:#DFD6E7; --firm:#C7BCD0;
  --accent:#7534AE; --mauve:#6C338B; --blue:#565682;
  --cta:#7534AE; --oncta:#F3ECFA; --tile:#E4D6F1;
  --onacc:#F3ECFA; --onsem:#F3ECFA;
  --link:#7534AE; --focus:#7534AE;
  --sel:#E1D2EF; --onsel:#29133D; --off:#9384A0;
  --tint:rgba(117,52,174,.08);
  --chrome:rgba(243,236,250,.95);
  --veil:243,236,250;
  --veil-a:.66; --veil-b:.54; --veil-c:.88;
  --herofx:saturate(.86) brightness(1.03);
  --room:light;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61;
  --ic-cream:#F3ECFA;
}
html[data-look="prince"][data-theme="dark"],
[data-look="prince"][data-theme="dark"]{
  --ground:#1D0C2B; --sunk:#271633; --raised:#2D1D39; --lift:#3C2C45;
  --ink:#F7EFE3; --soft:#C7BDBB; --muted:#B1A6A8; --faint:#9B9096;
  --line:#35253F; --firm:#56475B;
  --accent:#AE70F1; --mauve:#BD86E0; --blue:#A4AAD3;
  --cta:#AE70F1; --oncta:#1D0C2B; --tile:#3D2257;
  --onacc:#1D0C2B; --onsem:#1D0C2B;
  --link:#AE70F1; --focus:#AE70F1;
  --sel:#371E4F; --onsel:#F7EFE3; --off:#7F727E;
  --tint:rgba(174,112,241,.08);
  --chrome:rgba(29,12,43,.95);
  --veil:29,12,43;
  --veil-a:.38; --veil-b:.22; --veil-c:.68;
  --herofx:saturate(.8) brightness(.88) contrast(1.04);
  --room:dark;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#2D1D39;
}

/* ------------------------------------------------ the House palettes
   Two palettes a House can wear for everyone (Brand & Appearance), alongside
   Original. Colors only, like the eleven above, but each is ONE light room
   rather than a pair: they were given as light palettes, and a dark Red Hot
   would be a palette nobody chose. So they key on `data-look` alone, like
   Enchanted and Sanctuary, and leave the person's light/dark preference
   waiting underneath for when the House goes back to Original.

   The selector is written three times. The first is the page and the anchor
   tests/themes.test.mjs reads. The second carries `[data-theme]` as well,
   which the page always has, so the palette also outranks a published
   brand's after-dark block (/api/brand.css, loaded after this file, at the
   same specificity as the first). The third is the swatch in a picker.

   The given colors are used as given; everything the brief did not name is
   derived from them and measured — tests/themes.test.mjs recomputes every
   pair. The semantic three, the icon family's own ink and the photograph's
   treatment (--herofx) are Original's: a theme is a palette, and the warning
   colors and the imagery are not part of one. */
/* Red Hot. Black, white and hot red; the red does all the talking. */
html[data-look="redhot"], html[data-look="redhot"][data-theme], [data-look="redhot"]{
  --ground:#FFFFFF; --sunk:#F3F3F3; --raised:#FFFFFF; --lift:#EBEBEB;
  --ink:#0B0B0B; --soft:#333333; --muted:#6E6E6E; --faint:#707070;
  --line:#E3E3E3; --firm:#CDCDCD;
  --accent:#D81F1F; --mauve:#8F0E0E; --blue:#4A4A4A;
  --cta:#D81F1F; --oncta:#FFFFFF; --tile:#FBD9D9;
  --onacc:#FFFFFF; --onsem:#FFFFFF;
  --link:#D81F1F; --focus:#D81F1F;
  --sel:#FBD9D9; --onsel:#0B0B0B; --off:#8F8F8F;
  --tint:rgba(216,31,31,.06);
  --chrome:rgba(255,255,255,.95);
  --veil:255,255,255;
  --veil-a:.66; --veil-b:.54; --veil-c:.88;
  --herofx:saturate(.82) sepia(.12) brightness(1.04);
  --room:light;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61;
  --ic-cream:#FFFFFF;
  /* The ones that used to be written into rules (see the top of the file). */
  --blue-wash:rgba(74,74,74,.13); --pick-rgb:216,31,31;
  --dim:rgba(11,11,11,.28);
  --room-rose:#FBD9D9; --room-frame:#E3E3E3;
  --room-glass:rgba(248,248,248,.86); --room-wave:#CDCDCD; --room-print:#FFFFFF;
}
/* Black & White. Near-black on white, in full grayscale. */
html[data-look="mono"], html[data-look="mono"][data-theme], [data-look="mono"]{
  --ground:#F6F6F6; --sunk:#EEEEEE; --raised:#FFFFFF; --lift:#E9E9E9;
  --ink:#0D0D0D; --soft:#333333; --muted:#5E5E5E; --faint:#6B6B6B;
  --line:#E2E2E2; --firm:#CFCFCF;
  --accent:#161616; --mauve:#000000; --blue:#4A4A4A;
  --cta:#161616; --oncta:#FFFFFF; --tile:#E9E9E9;
  --onacc:#FFFFFF; --onsem:#FFFFFF;
  --link:#161616; --focus:#161616;
  --sel:#E9E9E9; --onsel:#0D0D0D; --off:#8A8A8A;
  --tint:rgba(22,22,22,.06);
  --chrome:rgba(246,246,246,.95);
  --veil:246,246,246;
  --veil-a:.66; --veil-b:.54; --veil-c:.88;
  --herofx:saturate(.82) sepia(.12) brightness(1.04);
  --room:light;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61;
  --ic-cream:#F6F6F6;
  --blue-wash:rgba(74,74,74,.13); --pick-rgb:22,22,22;
  --dim:rgba(13,13,13,.28);
  --room-rose:#E9E9E9; --room-frame:#E2E2E2;
  --room-glass:rgba(252,252,252,.86); --room-wave:#CFCFCF; --room-print:#FFFFFF;
}

/* ------------------------------------------------ IndyHouse
   IndyHouse's own look and what every new House wears (PROMPT-10): paper
   #FAFAF7, carbon #111113, cobalt #355CFF, citron #D9EF63 and silver
   #B9BEC8, from indyhouse.starhousellc.com. A pair, keyed on `data-look` and
   `data-theme` together like the eleven color-only palettes. In daylight the
   cobalt does the talking on paper; after dark the ground is carbon, the
   buttons are citron and the links a lifted cobalt, because cobalt itself is
   too dark to read on carbon. Silver is the muted text after dark. */
html[data-look="indyhouse"][data-theme="light"],
[data-look="indyhouse"][data-theme="light"]{
  --ground:#FAFAF7; --sunk:#F1F1EC; --raised:#FFFFFF; --lift:#E7E7E2;
  --ink:#111113; --soft:#3A3B40; --muted:#5B5E66; --faint:#63666F;
  --line:#E3E3DE; --firm:#CCCDC8;
  --accent:#355CFF; --mauve:#2440C0; --blue:#4A5068;
  --cta:#355CFF; --oncta:#FFFFFF; --tile:#EEF6C8;
  --onacc:#FFFFFF; --onsem:#FFFFFF;
  --link:#355CFF; --focus:#355CFF;
  --sel:#E3E9FF; --onsel:#111113; --off:#8B8E97;
  --tint:rgba(53,92,255,.07);
  --chrome:rgba(250,250,247,.95);
  --veil:250,250,247;
  --veil-a:.66; --veil-b:.54; --veil-c:.88;
  --herofx:saturate(.86) brightness(1.03);
  --room:light;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#5C3049; --ic-rose:#D9AFC1; --ic-sage:#5E7A61;
  --ic-cream:#FAFAF7;
  --blue-wash:rgba(74,80,104,.13); --pick-rgb:53,92,255;
  --dim:rgba(17,17,19,.28);
  --room-rose:#E3E9FF; --room-frame:#E3E3DE;
  --room-glass:rgba(252,252,250,.86); --room-wave:#CCCDC8; --room-print:#FFFFFF;
  /* Ji's mark in IndyHouse's own two colors (.jayi below): cobalt J and i,
     a citron spark. Citron alone vanishes into paper, so in daylight the
     spark keeps a deep-cobalt edge, the way the emblem sets it on cobalt. */
  --ji-ink:#355CFF; --ji-spark:#D9EF63; --ji-edge:#2440C0;
}
html[data-look="indyhouse"][data-theme="dark"],
[data-look="indyhouse"][data-theme="dark"]{
  --ground:#111113; --sunk:#18181B; --raised:#1D1D21; --lift:#2A2A2F;
  --ink:#FAFAF7; --soft:#D3D6DC; --muted:#B9BEC8; --faint:#9EA3AD;
  --line:#26262B; --firm:#43444B;
  --accent:#8FA4FF; --mauve:#D9EF63; --blue:#A9B4D6;
  --cta:#D9EF63; --oncta:#111113; --tile:#232A4A;
  --onacc:#111113; --onsem:#111113;
  --link:#8FA4FF; --focus:#D9EF63;
  --sel:#252C4F; --onsel:#FAFAF7; --off:#73767E;
  --tint:rgba(143,164,255,.08);
  --chrome:rgba(17,17,19,.95);
  --veil:17,17,19;
  --veil-a:.38; --veil-b:.22; --veil-c:.68;
  --herofx:saturate(.8) brightness(.88) contrast(1.04);
  --room:dark;
  --plum:#5C3049; --rose:#D9AFC1; --sage:#5E7A61;
  --ic-plum:#EBDCE4; --ic-rose:#A4708A; --ic-sage:#8FAE92;
  --ic-cream:#1D1D21;
  --blue-wash:rgba(169,180,214,.13); --pick-rgb:143,164,255;
  --ji-ink:#8FA4FF; --ji-spark:#D9EF63;
}

*{box-sizing:border-box}
[hidden]{display:none!important}
html{background:var(--ground)}
body{
  margin:0;background:var(--ground);color:var(--ink);
  font-family:var(--f-b);font-size:16px;line-height:1.6;font-weight:400;
  -webkit-font-smoothing:antialiased;
  padding:0 22px calc(94px + env(safe-area-inset-bottom,0px));
  max-width:760px;margin:0 auto;
}
/* Named, so a palette whose accent is a fill color can give the ring its
   own readable value — Brat's lime is a button, not a focus indicator. */
:focus-visible{outline:2px solid var(--focus);outline-offset:3px;border-radius:3px}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* ---------------- chrome ---------------- */
.topbar{display:flex;align-items:center;gap:12px;padding:16px 0 4px;min-height:52px}
.back{background:none;border:0;color:var(--accent);font-family:var(--f-l);font-size:15px;
  letter-spacing:.1em;text-transform:uppercase;cursor:pointer;padding:4px 0}
.tsw{margin-left:auto;width:32px;height:32px;border-radius:50%;cursor:pointer;
  border:1px solid var(--firm);background:var(--sunk);color:var(--muted);
  font-size:13px;display:flex;align-items:center;justify-content:center}
.who{font-family:var(--f-m);font-size:11px;color:var(--faint)}
.inline{color:var(--accent);text-decoration:none;border-bottom:1px solid var(--line);white-space:nowrap}
.inline:hover{border-bottom-color:var(--accent)}

.eyebrow{font-family:var(--f-l);font-size:11px;letter-spacing:.26em;text-transform:uppercase;
  color:var(--faint);margin:0}
h1{font-family:var(--f-d);font-weight:400;font-size:30px;line-height:1.08;
  letter-spacing:-.01em;margin:6px 0 4px;text-wrap:balance}
h1.song{font-size:34px;line-height:1.04;margin:10px 0 6px}
.meta{font-size:13.5px;color:var(--muted);font-weight:300;margin:0}
.mono{font-family:var(--f-m);font-size:12px;letter-spacing:-.01em}

.slab{font-family:var(--f-l);font-size:10.5px;letter-spacing:.24em;text-transform:uppercase;
  color:var(--faint);margin:32px 0 12px;display:flex;justify-content:space-between;align-items:baseline}
.slab span{letter-spacing:0;font-family:var(--f-b);font-size:12px;text-transform:none}

/* ---------------- rows ---------------- */
.rows{display:flex;flex-direction:column;gap:1px;background:var(--line);
  border:1px solid var(--line);border-radius:12px;overflow:hidden}
.row{background:var(--sunk);padding:14px 15px;display:grid;grid-template-columns:1fr auto;
  gap:12px;align-items:center;border:0;width:100%;text-align:left;font:inherit;color:inherit;cursor:pointer}
.row:hover{background:var(--lift)}
.row .nm{font-family:var(--f-d);font-size:17px;line-height:1.2;margin:0 0 3px}
.row .sb{font-size:12.5px;color:var(--muted);font-weight:300;margin:0}
.row .rt{display:flex;align-items:center;gap:9px}
.tag{font-family:var(--f-l);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;
  padding:3px 8px;border-radius:4px;white-space:nowrap;background:var(--lift);color:var(--muted)}
/* A tag is named for what it means, never for a stage (audit 5.16, Round R9):
   a bare .tag is a plain fact, .accent and .info set one apart, and a state
   (registered, owed, approved) is .tag.state with its tone from tones.js. */
.tag.accent{background:var(--tint);color:var(--accent)}
.tag.info{background:var(--blue-wash);color:var(--blue)}

/* ---------------- player ---------------- */
.player{margin:20px 0 0;border:1px solid var(--line);border-radius:12px;
  background:var(--sunk);padding:14px 15px 12px}
.ptop{display:flex;align-items:center;gap:13px}
.play{flex:0 0 auto;width:44px;height:44px;border-radius:50%;border:0;cursor:pointer;
  background:var(--accent);color:var(--onacc);display:flex;align-items:center;
  justify-content:center;font-size:14px;font-family:var(--f-b)}
.play:disabled{opacity:.4;cursor:default}
.wave{flex:1;display:flex;align-items:center;gap:1.5px;height:40px;cursor:pointer;min-width:0}
.wave i{display:block;flex:1;background:var(--firm);border-radius:1px;min-width:1px;
  transition:background .08s linear}
.wave i.p{background:var(--accent)}
.ptime{display:flex;justify-content:space-between;margin:8px 2px 0;
  font-family:var(--f-m);font-size:10.5px;color:var(--faint)}
.vpill{display:inline-flex;align-items:center;gap:8px;margin:12px 0 0;padding:6px 12px;
  border-radius:20px;background:var(--lift);border:1px solid var(--firm)}
.vpill b{font-family:var(--f-l);font-size:10px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--accent);font-weight:400}
.vpill span{font-family:var(--f-m);font-size:11.5px;color:var(--soft)}

/* ---------------- version rows ---------------- */
.vrow{display:grid;grid-template-columns:auto 1fr auto;gap:11px;align-items:center;
  padding:12px 0;border-bottom:1px solid var(--line);cursor:pointer}
.vrow:last-child{border-bottom:0}
.vrow .vs{font-family:var(--f-l);font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;
  white-space:nowrap;width:64px;text-align:center;padding:3px 0;border-radius:999px;
  background:color-mix(in srgb, var(--stage-on) 15%, transparent);color:var(--stage-on)}
.vrow .vn{font-family:var(--f-m);font-size:12px;color:var(--soft);min-width:0;overflow-wrap:anywhere}
.vrow .vd{font-family:var(--f-m);font-size:10.5px;color:var(--faint);white-space:nowrap}
.vrow.cur{background:var(--tint);margin:0 -10px;padding-left:10px;padding-right:10px;border-radius:8px}
.vrow.cur .vn{color:var(--ink)}
.vrow.playing .vn{color:var(--accent)}

/* ---------------- stages ---------------- */
.stages{display:flex;gap:5px;margin:12px 0 0}
.stg{flex:1;padding:10px 3px;border-radius:8px;border:1px solid var(--line);background:var(--sunk);
  font-family:var(--f-l);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--faint);cursor:pointer;text-align:center}
.stg.on{border-color:var(--accent);color:var(--accent);background:var(--tint)}
.hint{font-size:12.5px;color:var(--muted);font-weight:300;margin:10px 0 0;line-height:1.5}
.hint b{color:var(--soft);font-weight:500}

/* ---------------- kv ---------------- */
.kv{display:flex;flex-direction:column}
.kvr{display:grid;grid-template-columns:104px 1fr;gap:12px;padding:11px 0;
  border-bottom:1px solid var(--line);align-items:baseline}
.kvr:last-child{border-bottom:0}
.kvr .k{font-family:var(--f-l);font-size:10px;letter-spacing:.18em;text-transform:uppercase;color:var(--faint)}
.kvr .v{font-size:13.5px;color:var(--soft);font-weight:300;min-width:0;overflow-wrap:anywhere}
.kvr .v.m{font-family:var(--f-m);font-size:11.5px}
/* A paper is named by its filename now, and a filename such as
   Producer_Agreement_Poison_Garden.pdf is one long word: it wraps inside the
   row rather than running off the side of a phone. */
.kvr .v .doc-title{white-space:normal;overflow-wrap:anywhere}
.kvr .v.none{color:var(--faint);font-style:italic}
/* A row that is a choice: the select covers the whole row, invisible, so the
   tap lands on it anywhere and the phone opens its own picker. 16px keeps iOS
   from zooming the page when it takes focus. */
.kvr.pickrow{position:relative;cursor:pointer}
.kvr.pickrow .v{display:flex;justify-content:space-between;align-items:baseline;gap:8px}
.kvr.pickrow select{position:absolute;inset:0;width:100%;height:100%;opacity:0;
  font-size:16px;cursor:pointer;-webkit-appearance:none;appearance:none}

/* ---------------- proposals ---------------- */
.prop{border:1px solid var(--firm);border-radius:12px;background:var(--sunk);
  padding:14px 15px;margin:14px 0 0}
.prop .ph{font-family:var(--f-d);font-size:16px;margin:0 0 4px}
.prop .pd{font-size:13px;color:var(--muted);font-weight:300;margin:0 0 12px;line-height:1.5}
.propitem{display:grid;grid-template-columns:1fr auto;gap:10px;align-items:center;
  padding:9px 0;border-top:1px solid var(--line)}
.propitem .pi{font-size:13.5px;margin:0 0 2px}
.propitem .ps{font-family:var(--f-m);font-size:10.5px;color:var(--faint);margin:0;
  overflow-wrap:anywhere}
/* =============================================================== THE ONE BUTTON SET
   Five buttons, one size scale, drawn once (Round 4, "One set of controls";
   mockup: indyhouse-rounds/controls-mockup, scene "buttons").

     .btn            secondary: the BARE class is always the outline
     .btn.primary    --cta fill, the one main act of a screen
     .btn.ghost      no fill, no outline, --accent words
     (destructive: one rule in shell.css, Round 3)
     .btn.link       underlined --link words, inline with a sentence
     .btn.small      36 high instead of 44;  :disabled  --sunk fill, --off words

   The older families still render, but their LOOK comes from this block and
   from nowhere else: they are aliases, listed on the same selectors.

     secondary  .tb  .mbtn  .wr-btn  .ih-action  .ok  .act   (bare class)
     primary    .tb.solid  .mbtn.primary  .wr-btn-primary  .ih-action.ih-primary
                .sl-btn.keep  .ok.solid  .act.solid  .rc-primary
     ghost      .sl-btn  .sl-btn.quiet  .tb.quiet  .act.quiet
     link       .act.link
     small      .ok  .tb.mini  .mbtn.sm  .mbtn.xs  .wr-btn-sm

   An alias rule elsewhere may place a button (width, margin, flex, the padding
   of a toolbar) but never paints one: no color, radius, height or font.

   The `--btn-*` hooks let a room that paints on its own paper (the Writing Room)
   hand the set its own ink without a second set of rules; everywhere else they
   are unset and the plain tokens apply. */
:is(.btn,.tb,.mbtn,.wr-btn,.ih-action,.sl-btn,.ok,.act,.rc-primary){
  display:inline-flex;align-items:center;justify-content:center;gap:7px;box-sizing:border-box;
  min-height:44px;padding:6px 18px;border-radius:12px;
  border:1px solid var(--btn-firm,var(--firm));background:var(--btn-raised,var(--raised));
  color:var(--btn-ink,var(--ink));font:500 15.5px/1.25 var(--f-s);letter-spacing:0;text-transform:none;
  text-decoration:none;white-space:nowrap;cursor:pointer;
  transition:border-color 160ms ease, background 160ms ease}
:is(.btn,.mbtn) svg{width:18px;height:18px;flex:none}
:is(.btn,.tb,.mbtn,.wr-btn,.ih-action,.sl-btn,.ok,.act,.rc-primary):focus-visible{
  outline:2px solid var(--focus);outline-offset:2px}
@media (prefers-reduced-motion:reduce){
  :is(.btn,.tb,.mbtn,.wr-btn,.ih-action,.sl-btn,.ok,.act,.rc-primary){transition:none} }

/* ghost: no fill, no outline */
.btn.ghost,.sl-btn,.sl-btn.quiet,.tb.quiet,.act.quiet{
  background:none;border-color:transparent;color:var(--btn-accent,var(--accent))}

/* primary */
.btn.primary,.tb.solid,.mbtn.primary,.wr-btn-primary,.ih-action.ih-primary,.sl-btn.keep,.ok.solid,.act.solid,.rc-primary{
  background:var(--btn-cta,var(--cta));border-color:var(--btn-cta,var(--cta));
  color:var(--btn-oncta,var(--oncta));font-weight:600}
@media (hover:hover){
  .btn.primary:hover,.tb.solid:hover:not(:disabled),.mbtn.primary:hover:not(:disabled),
  .wr-btn-primary:hover:not(:disabled),.ok.solid:hover:not(:disabled),.act.solid:hover:not(:disabled){
    filter:brightness(1.1)} }

/* The destructive variant is not drawn here: Round 3 ships the one rule for it in
   shell.css, over these same selectors. */

/* link: words with an underline, no box. The app's text actions are this one
   link (consistency audit 2.20, Round R9, October 7, 2026): .linky across the
   app and Music's .mlink sit in running text, so they keep their line height
   and reach the 44 point press area through ::after, the way .choice does;
   .btn.link has it from the set. */
.btn.link,.linky,.mlink{position:relative;padding:0 2px;border:0;background:none;color:var(--link);
  text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px;font-weight:500;cursor:pointer}
.linky,.mlink{font:500 14px/1.3 var(--f-s)}
.linky{margin:2px 0 0}
:is(.linky,.mlink)::after{content:"";position:absolute;left:-4px;right:-4px;top:50%;height:44px;transform:translateY(-50%)}
@media (hover:hover){ :is(.btn.link,.linky,.mlink):hover{text-decoration-thickness:2px} }
:is(.linky,.mlink):is(:disabled,[disabled]){color:var(--off);cursor:default;text-decoration:none}

/* small */
.btn.small,.ok,.tb.mini,.mbtn.sm,.mbtn.xs,.wr-btn-sm{
  min-height:36px;padding:4px 13px;font-size:14px;border-radius:10px}

/* disabled: after every variant so it beats them */
:is(.btn,.tb,.mbtn,.wr-btn,.ih-action,.sl-btn,.ok,.act,.rc-primary):is(:disabled,[disabled]){
  background:var(--btn-sunk,var(--sunk));border-color:var(--btn-line,var(--line));
  color:var(--off);cursor:default;filter:none}
.btn.link:is(:disabled,[disabled]),
.btn.ghost:is(:disabled,[disabled]),.sl-btn:is(:disabled,[disabled]){background:none;border-color:transparent}
.btn.wide{width:100%}

/* chev(): the one row chevron. 16 points, 1.7 stroke (drawn in app/chev.js), faint ink */
.chev{flex:none;display:inline-grid;place-items:center;color:var(--faint)}
.chev svg{width:16px;height:16px}

/* .more-btn: the one "More" button. A 44 point square carrying ICONS.ellipsis at
   22 in muted ink; its aria-label says what it opens. */
.more-btn{appearance:none;-webkit-appearance:none;flex:none;box-sizing:border-box;width:44px;height:44px;min-width:44px;
  padding:0;margin:0;border:0;border-radius:50%;background:none;color:var(--muted);cursor:pointer;
  display:inline-grid;place-items:center;position:relative}
.more-btn svg{width:22px;height:22px}
.more-btn:active{background:var(--tint)}
.more-btn:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}

/* Layout only (look: the one button set above). `.act` is the full-width
   button of a form; `.ok` is the small one that sits in a row. */
.act{display:block;width:100%;margin:22px 0 0}

.cover{width:100%;max-width:280px;aspect-ratio:1;border-radius:4px;object-fit:cover;
  display:block;margin:18px 0 0;background:var(--lift)}

/* ---------------- release: steps, scope, planner, schedule ---------------- */
.gateline{border:1px solid var(--firm);border-radius:12px;padding:16px 17px;margin:18px 0 0;
  background:var(--sunk);display:flex;gap:13px;align-items:flex-start}
.gateline .mark{flex:0 0 auto;width:22px;height:22px;border-radius:50%;display:flex;
  align-items:center;justify-content:center;font-size:12px;margin-top:1px;color:var(--onacc)}
.gateline.ok .mark{background:var(--good)} .gateline.ok .t{color:var(--good)}
.gateline.block .mark{background:var(--stop)} .gateline.block .t{color:var(--stop)}
.gateline.wait .mark{background:var(--warn)} .gateline.wait .t{color:var(--warn)}
.gateline .t{font-family:var(--f-d);font-size:17px;line-height:1.25;margin:0 0 3px}
.gateline .d{font-size:13.5px;color:var(--muted);font-weight:300;line-height:1.5;margin:0}

.track{display:flex;gap:8px;margin:18px 0 0}
.step{flex:1;display:flex;flex-direction:column;gap:7px}
.step .bar{height:3px;border-radius:2px;background:var(--firm)}
.step .nm{font-family:var(--f-l);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--faint)}
.step.done .bar{background:var(--good)} .step.done .nm{color:var(--muted)}
.step.now .bar{background:var(--stop)} .step.now .nm{color:var(--stop)}

.todos{display:flex;flex-direction:column;gap:1px;background:var(--line);
  border:1px solid var(--line);border-radius:12px;overflow:hidden}
.todo{background:var(--sunk);padding:13px 15px;display:grid;grid-template-columns:1fr auto;gap:11px;align-items:center}
/* On a phone the name IS the task — "We need Cherry's IPI" with the name cut
   off is not a task anybody can act on — so the request wraps and the button
   drops beneath it rather than squeezing the sentence. */
@media (max-width:520px){
  .todo{grid-template-columns:1fr;gap:9px}
  .todo .ok{justify-self:start;min-height:44px;padding:0 16px}
}
.todo .ti{overflow-wrap:anywhere}
/* The list exists to get shorter. Letting the browser pick a scroll anchor
   inside it means finishing a task moves the page, because the node it latched
   onto is the one that just left. */
.todos[data-tasks]{overflow-anchor:none}
/* Things that are real but not due yet. Quieter, and never in the count. */
.todos.later{opacity:.78}
.slab.sub{margin-top:18px;font-size:12px;letter-spacing:.1em;color:var(--faint)}
.todo .ti{font-size:14.5px;color:var(--ink);margin:0 0 3px;line-height:1.3}
.todo .tw{font-size:12px;font-weight:300;margin:0;display:flex;align-items:center;gap:5px;color:var(--muted)}
.todo .tw i{width:5px;height:5px;border-radius:50%;background:currentColor;display:block;flex:0 0 auto}

.scope{border-top:1px solid var(--line)}
.srow{display:grid;grid-template-columns:1fr auto;gap:14px;align-items:center;
  padding:13px 0;border-bottom:1px solid var(--line)}
.srow .nm{font-size:15px;color:var(--ink);margin:0}
.srow .nm span{display:block;font-size:12.5px;color:var(--muted);font-weight:300;margin-top:2px}
/* The one switch (Round 4, "One set of controls"): a <button role="switch"
   aria-checked>. OFF is a --firm track, ON a filled --accent track with the
   knob slid right; the knob is the surface color in both, so "on" never rests
   on spotting a faint tint. The drawn track is 28px tall, which is not a
   thumb, so ::after grows the press area to 44 without changing anything
   anybody can see. aria-checked is the only on-state: there is no .on. */
.tgl{appearance:none;flex:none;width:48px;height:28px;border-radius:14px;border:0;background:var(--firm);
  padding:0;margin:0;position:relative;cursor:pointer;transition:background .15s}
.tgl::after{content:'';position:absolute;inset:-8px -4px}
.tgl i{position:absolute;top:2px;left:2px;width:24px;height:24px;border-radius:50%;background:var(--raised);
  box-shadow:0 1px 3px rgba(0,0,0,.25);transition:left .15s;display:block}
.tgl[aria-checked="true"]{background:var(--accent)}
.tgl[aria-checked="true"] i{left:22px}
.tgl:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
.tgl:disabled{cursor:default}

.rule{margin:0 0 12px;padding:15px 16px;border-radius:12px;background:var(--tint);border:1px solid var(--firm)}
.rule .rt{font-family:var(--f-d);font-size:16px;line-height:1.3;margin:0 0 5px;color:var(--ink)}
.rule .rd{font-size:13px;font-weight:300;color:var(--muted);margin:0;line-height:1.5}
.fris{border-top:1px solid var(--line)}
.fri{display:grid;grid-template-columns:1fr auto;gap:12px;align-items:center;width:100%;
  background:none;border:0;border-bottom:1px solid var(--line);padding:13px 2px;
  text-align:left;font:inherit;color:inherit;cursor:pointer}
.fri:hover{background:var(--sunk)}
.fri .fd{font-family:var(--f-d);font-size:17px;line-height:1.2;margin:0 0 2px;color:var(--ink)}
.fri .fn{font-size:12.5px;font-weight:300;margin:0;color:var(--muted);line-height:1.4}
.fri .fw{font-family:var(--f-m);font-size:12px;color:var(--faint);white-space:nowrap}
.fri.sel{background:var(--tint)} .fri.sel .fd,.fri.sel .fw{color:var(--accent)}
.fri.tight .fn{color:var(--warn)}

.sched{border-top:1px solid var(--line)}
/* Five columns now: tick, what it is, who has it, when, and the rest. The
   fourth control used to wrap onto its own line and leave a row three times
   taller than it needed to be. The name column is the one that gives, because
   it is the only one that can. */
.ev{display:grid;grid-template-columns:auto minmax(0,1fr) auto auto auto;
  gap:6px 9px;align-items:center;padding:11px 0;border-bottom:1px solid var(--line)}
.ev:last-child{border-bottom:0}
.tick{width:20px;height:20px;border-radius:50%;border:1.5px solid var(--firm);background:none;
  cursor:pointer;padding:0;flex:0 0 auto;position:relative}
.tick.on{background:var(--good);border-color:var(--good)}
.tick.on::after{content:"";position:absolute;left:5.5px;top:2.5px;width:5px;height:9px;
  border:solid var(--onacc);border-width:0 2px 2px 0;transform:rotate(45deg)}
.ev .body{min-width:0;display:flex;flex-direction:column;gap:2px}
.ev .nm2{font-size:14.5px;color:var(--ink);font-weight:300;line-height:1.3}
.ev .dt2{font-size:12px;color:var(--faint);font-weight:300}
.ev.ok .nm2{color:var(--muted);text-decoration:line-through;text-decoration-color:var(--firm)}
.ev.late .nm2{color:var(--stop)}
.ev .dt{font-family:var(--f-m);font-size:11px;color:var(--faint);white-space:nowrap}
.ev.late .dt{color:var(--stop)}
.own{font-family:var(--f-b);font-size:12.5px;color:var(--muted);background:var(--sunk);
  border:1px solid var(--line);border-radius:7px;padding:5px 6px;max-width:6.5em}

/* ---------------- send ---------------- */
.picks{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:8px}
.pick{position:relative;text-align:left;border:1px solid var(--line);background:var(--sunk);
  border-radius:10px;padding:12px 34px 12px 13px;cursor:pointer;font:inherit;color:inherit}
.pick:hover{background:var(--lift)}
.pick.on{border-color:var(--accent);background:var(--tint)}
.pick .pn{display:block;font-family:var(--f-d);font-size:15.5px;line-height:1.2}
.pick .pm{display:block;font-family:var(--f-l);font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--faint);margin-top:4px}
.pick .po{position:absolute;top:10px;right:10px;width:20px;height:20px;border-radius:50%;
  font-family:var(--f-m);font-size:11px;display:flex;align-items:center;justify-content:center;
  color:var(--onacc);background:transparent}
.pick.on .po{background:var(--accent)}

.form,.opts{display:flex;flex-direction:column;gap:12px}
.form label,.opts label{display:flex;flex-direction:column;gap:5px}
.askgrp{display:flex;flex-direction:column;gap:7px}
.askgrp>span{font-family:var(--f-l);font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;color:var(--muted)}
.askgrp.askrow{flex-direction:row;align-items:center;justify-content:space-between}
.form label>span,.opts label>span{font-family:var(--f-l);font-size:10.5px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--faint)}
.form input,.form textarea,.opts input[type=text],.opts input:not([type=checkbox]),.opts select{
  font-family:var(--f-b);font-size:15px;color:var(--ink);background:var(--sunk);
  border:1px solid var(--line);border-radius:9px;padding:11px 12px;width:100%;resize:vertical}
.form input:focus,.form textarea:focus{border-color:var(--accent);outline:none}
.opt{flex-direction:row!important;align-items:flex-start;gap:11px!important;
  border:1px solid var(--line);border-radius:10px;padding:13px;background:var(--sunk);cursor:pointer}
.opt input{margin-top:3px;accent-color:var(--accent);width:17px;height:17px;flex:0 0 auto}
.opt>span{display:flex;flex-direction:column;gap:3px;text-transform:none!important;
  letter-spacing:0!important;font-family:var(--f-b)!important;font-size:14.5px!important;color:var(--ink)!important}
.opt b{font-weight:600}
.opt em{font-style:normal;font-size:12.5px;color:var(--muted);font-weight:300}

.done{margin:20px 0 0;border:1px solid var(--accent);border-radius:12px;padding:16px;background:var(--tint)}
.done .dh{font-family:var(--f-d);font-size:17px;margin:0 0 10px}
.url{width:100%;font-family:var(--f-m);font-size:12px;padding:11px 12px;border-radius:8px;
  border:1px solid var(--firm);background:var(--ground);color:var(--ink)}
.done .act{margin-top:10px}

/* ---------------- download glyphs ---------------- */
.dl{display:inline-flex;align-items:center;gap:5px;color:var(--muted);text-decoration:none;
  border:1px solid var(--line);background:var(--sunk);border-radius:7px;padding:6px 9px;
  font-family:var(--f-m);font-size:10.5px;line-height:1;white-space:nowrap}
.dl:hover{color:var(--accent);border-color:var(--accent);background:var(--tint)}
.dl.sm{padding:5px 7px;border:0;background:none}
.dl.sm:hover{background:var(--tint)}
.coverwrap{position:relative;display:inline-block;margin:18px 0 0}
.coverwrap .cover{margin:0}
.coverwrap .dl{position:absolute;right:8px;bottom:8px;background:var(--chrome);
  backdrop-filter:blur(8px);border-color:var(--firm)}

/* ---------------- releases ---------------- */
.rel{border:1px solid var(--line);border-radius:12px;overflow:hidden;margin:0 0 10px;background:var(--line)}
.rel .relhead{border-radius:0}
.rel.open .chev{transform:rotate(90deg);display:inline-block}
.tracks{background:var(--ground);padding:2px 0}
.trk{display:grid;grid-template-columns:26px 1fr auto auto;gap:10px;align-items:center;
  padding:11px 15px;border-top:1px solid var(--line);cursor:pointer}
.trk:hover{background:var(--sunk)}
.trk .tn{font-family:var(--f-m);font-size:11px;color:var(--faint);text-align:right}
.trk .tt{min-width:0;display:flex;flex-direction:column;gap:2px}
.trk .tt b{font-family:var(--f-d);font-weight:400;font-size:16px;line-height:1.2}
.trk .tt .mono{font-size:10.5px;color:var(--faint)}
.vrow .vn em{font-style:normal;font-family:var(--f-m);font-size:10px;color:var(--faint);margin-left:6px}

/* ---------------- cover candidates ---------------- */
.candidates{display:grid;grid-template-columns:repeat(auto-fill,minmax(84px,1fr));gap:8px;margin:0}
.cand{position:relative;padding:0;border:1px solid var(--line);border-radius:6px;overflow:hidden;
  background:var(--lift);cursor:pointer;aspect-ratio:1;display:block}
.cand img{width:100%;height:100%;object-fit:cover;display:block}
.cand.on{border-color:var(--accent);box-shadow:0 0 0 2px var(--accent)}
.cand .cw{position:absolute;left:4px;bottom:4px;font-family:var(--f-m);font-size:9px;
  color:#fff;background:rgba(18,11,20,.66);padding:1px 4px;border-radius:3px}
.cand.on .cw{background:var(--accent)}

/* ---------------- tabs ---------------- */
/* Five equal destinations. A fine underline marks the active one; the pink
   pill the earlier interpretation used is explicitly out. Each still clears
   44x44 and all five fit at 320 without scrolling. */
.tabs{position:fixed;bottom:0;left:0;right:0;display:flex;background:var(--chrome);
  backdrop-filter:saturate(1.2) blur(8px);z-index:40;
  padding-bottom:env(safe-area-inset-bottom)}
.tab{flex:1 1 0;min-width:0;background:none;border:0;cursor:pointer;position:relative;
  padding:9px 2px 8px;display:flex;flex-direction:column;align-items:center;gap:4px;
  color:var(--muted);min-height:54px}
.tab svg{display:block;flex:none}
.tab span{font-family:var(--f-s);font-size:11.5px;line-height:1.2;font-weight:500;
  white-space:nowrap}
.tab.on{color:var(--ink)}
.tab.on span{font-weight:600}
.tab.on::after{content:"";position:absolute;bottom:4px;width:18px;height:2px;
  border-radius:2px;background:var(--ink)}
/* Promo's dot: new press from Radar (Phase 2 §2.2). The package's one new
   mark. Tokens only, so every look colors it; the ring is the bar's own
   chrome, so it reads as a hole punched in the icon's corner, not a sticker. */
.tabdot{position:absolute;top:7px;left:calc(50% + 7px);width:8px;height:8px;border-radius:50%;
  background:var(--accent);box-shadow:0 0 0 2px var(--chrome);pointer-events:none}
.tnav .tabdot{top:4px;left:auto;right:-9px}
/* Focus has to be distinguishable from selection, not the same signal twice. */
.tab:focus-visible{outline:2px solid var(--accent);outline-offset:-3px;border-radius:10px}
@media (max-width:340px){ .tab span{font-size:11px} }

/* Nothing here yet (emptyState() in app/core.js): the line, and the one next
   step as a real button. The single rule set; it was three that each won a
   little (consistency audit 4.6), and this is what they added up to. */
.empty{font-family:var(--f-s);font-size:15px;color:var(--muted);font-style:italic;
  padding:14px;border:1px dashed var(--firm);border-radius:10px;text-align:center}
.empty p{margin:0}
/* The same line in a surface's own look (emptyState's `look`): one paragraph,
   then the button on its own line. */
[data-empty] > p{margin:0}
[data-empty] > .btn{margin-top:10px}
.empty .btn{margin-top:10px;font-style:normal}
/* Something did not load (errorState() in app/core.js): red, with the warning
   glyph and Try again, so a dead screen never passes for an empty one. */
.errstate{display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px 10px;margin:18px 0;
  padding:12px 14px;border:1px solid var(--stop);border-radius:10px;background:var(--tint);
  font-family:var(--f-s);font-size:14px;line-height:1.5;color:var(--ink)}
.errstate-gl{flex:none;margin-top:1px;color:var(--stop)}
.errstate-t{flex:1 1 14em;margin:0}
.errstate-t b{color:var(--stop);font-weight:600}
.errstate-ref{color:var(--muted);font-size:12px;white-space:nowrap}
.errstate .btn{flex:none;white-space:nowrap;margin-left:auto}
.err{border:1px solid var(--stop);background:var(--tint);border-radius:10px;
  padding:14px 16px;margin:18px 0;font-size:14px;color:var(--stop)}

@media (min-width:760px){
  body{padding-left:40px;padding-right:40px}
  .tabs{max-width:760px;margin:0 auto;border-left:1px solid var(--line);
    border-right:1px solid var(--line);border-radius:14px 14px 0 0}
  h1{font-size:38px} h1.song{font-size:44px}
}

/* ---- Ownership. On a phone a table of percentages is unreadable; a bar that
   visibly fails to reach the end is not. Unallocated space is left gray, so
   "nobody has said" and "adds up wrong" look different from each other. */
.splitbar{display:flex;gap:1.5px;height:9px;border-radius:5px;overflow:hidden;
  background:var(--lift);margin:0 0 10px}
.splitbar i{display:block;border-radius:1px;min-width:2px;transition:width .2s}
.splitrow{display:grid;grid-template-columns:1fr 98px;gap:12px;align-items:center;
  padding:9px 0;border-bottom:1px solid var(--line)}
.splitrow .who{font-size:14px;color:var(--ink);min-width:0;overflow-wrap:anywhere}
.splitrow .who em{font-family:var(--f-m);font-size:10px;color:var(--faint);font-style:normal;
  letter-spacing:.04em}
.splitrow .who em.warn{color:var(--warn)}
.pc{font-family:var(--f-m);font-size:13px;text-align:right;padding:8px 9px;
  border:1px solid var(--firm);border-radius:8px;background:var(--raised);color:var(--ink);
  width:100%;-webkit-appearance:none}
.pc:focus{border-color:var(--accent);outline:none}
.pc.miss{border-style:dashed;color:var(--faint)}
.totrow{display:flex;justify-content:space-between;align-items:baseline;padding:10px 0 0;
  font-family:var(--f-l);font-size:11px;letter-spacing:.22em;text-transform:uppercase;
  color:var(--faint)}
.totrow b{font-family:var(--f-m);font-size:13px;letter-spacing:0;text-transform:none;
  color:var(--good);font-weight:400}
.totrow b.bad{color:var(--stop)}
.addsplit{margin:12px 0 0;width:100%;padding:11px;border-radius:9px;background:var(--raised);
  border:1px dashed var(--firm);color:var(--muted);font-family:var(--f-b);font-size:13px}

.onestop{display:flex;flex-direction:column;gap:3px;padding:13px 15px;margin:0 0 4px;
  border-radius:11px;background:var(--tint);border:1px solid var(--firm)}
.onestop b{font-family:var(--f-l);font-size:11px;letter-spacing:.24em;text-transform:uppercase;
  color:var(--accent);font-weight:400}
.onestop span{font-size:13px;color:var(--muted);font-weight:300;line-height:1.5}

.kvr .v em.path{display:block;font-family:var(--f-m);font-size:10px;color:var(--faint);
  font-style:normal;margin:3px 0 0;overflow-wrap:anywhere}
.kvr .v em.paid{font-family:var(--f-l);font-size:9.5px;letter-spacing:.18em;text-transform:uppercase;
  font-style:normal;color:var(--good);margin-left:6px}
.kvr .v em.warn{font-family:var(--f-l);font-size:9.5px;letter-spacing:.18em;text-transform:uppercase;
  font-style:normal;color:var(--warn);margin-left:6px}
/* Every missing thing on this screen is fixable where it is named — the chip
   that says an IPI is absent is the control that records it. */
.idb{font-family:var(--f-m);font-size:10px;letter-spacing:.04em;color:var(--faint);
  background:none;border:0;padding:2px 0;cursor:pointer;border-bottom:1px dotted var(--firm)}
.idb:hover{color:var(--accent);border-bottom-color:var(--accent)}
.idb.warn{color:var(--warn);border-bottom-color:var(--warn)}

/* ---- A value and the control for it are the same object. The dotted rule is
   the only affordance: enough that it reads as tappable, quiet enough that a
   screen of them still reads as a list of facts. */
.fld{font:inherit;font-size:13.5px;color:var(--soft);font-weight:300;background:none;
  border:0;padding:1px 0;text-align:left;cursor:pointer;border-bottom:1px dotted var(--firm);
  max-width:100%;overflow-wrap:anywhere}
.fld.m{font-family:var(--f-m);font-size:11.5px}
.fld.none{color:var(--faint);font-style:italic}
.fld:hover{color:var(--accent);border-bottom-color:var(--accent)}
.fld:active{opacity:.6}
.fld[disabled]{color:var(--off);border-color:var(--line);cursor:default}

.pill{font-family:var(--f-l);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;
  border-radius:20px;padding:3px 9px;margin-left:6px;cursor:pointer;border:1px solid transparent;
  vertical-align:2px;white-space:nowrap}
.pill.paid{background:var(--good-wash);color:var(--good)}
.pill.owing{background:var(--lift);color:var(--warn);border-color:var(--firm)}
.kvr .v em.who{font-family:var(--f-b);font-style:normal;font-size:12px;color:var(--faint);
  margin-left:6px}
.todo .goes{display:flex;flex-wrap:wrap;gap:6px;margin:7px 0 0}
.todo .goes .pill{margin-left:0}
.pill.go{background:var(--lift);color:var(--accent);border-color:var(--firm);
  letter-spacing:.1em;text-transform:none;font-family:var(--f-b);font-size:11.5px;padding:4px 10px}
.pill.go:hover{background:var(--tint)}
.fld.flash{animation:flash .9s ease}
@keyframes flash{0%,100%{background:transparent}35%{background:var(--tint)}}
.act.link{text-align:center;display:block}
.ok.wide{display:block;width:100%;margin:12px 0 0;padding:12px}
/* The percentage and the way to remove the person sit together: a row that can
   be edited but not undone is a trap. */
.pcwrap{display:flex;align-items:center;gap:4px}
.pcwrap .pc{flex:1;min-width:0}
.pcwrap .drop{border:0;background:none;font-size:17px;line-height:1;
  min-width:32px;min-height:44px;padding:4px 2px;cursor:pointer;border-radius:5px}
@media (hover:hover){ .pcwrap .drop:hover{background:var(--lift)} }

/* ---- Lyrics. A lyric is read as a block, so it keeps her line breaks and gets
   a comfortable measure rather than being squeezed into a value column. */
.lyr{font-family:var(--f-b);font-weight:300;font-size:14.5px;line-height:1.7;color:var(--soft);
  white-space:pre-wrap;margin:0 0 4px;padding:16px 18px;border-radius:11px;background:var(--sunk);
  border:1px solid var(--line);max-height:340px;overflow:auto}
details.raw{margin:8px 0 0}
details.raw summary{font-size:12.5px;color:var(--muted);cursor:pointer;padding:4px 0}
details.raw summary:hover{color:var(--accent)}

.lyrbox{margin:14px 0 0}
.lyrbox textarea{width:100%;font-family:var(--f-b);font-weight:300;font-size:14.5px;
  line-height:1.65;color:var(--ink);background:var(--raised);border:1px solid var(--firm);
  border-radius:11px;padding:14px 16px;resize:vertical;-webkit-appearance:none}
.lyrbox textarea:focus{border-color:var(--accent);outline:none}
.lyrbar{display:flex;gap:8px;flex-wrap:wrap;margin:10px 0 0}
.lyrbar .ok{margin:0;padding:9px 15px}
.hint.bad{color:var(--stop)}

/* The diff is the whole safety story, so it has to be readable on a phone. */
.difftext{font-family:var(--f-b);font-weight:300;font-size:14px;line-height:1.7;
  max-height:380px;overflow:auto;margin:4px 0 12px}
.difftext .dline{display:block;margin:0;padding:1px 0;white-space:pre-wrap}
.difftext .dline.gone{opacity:.7}
.difftext del{background:var(--stop-wash);color:var(--stop);text-decoration:line-through;
  border-radius:3px;padding:0 2px}
.difftext ins{background:var(--good-wash);color:var(--good);text-decoration:underline;
  border-radius:3px;padding:0 2px}

/* ---- Cover options. Before release there is rarely one answer, so the grid is
   a set of candidates with the chosen one marked, and a slot to add another. */
.candwrap{position:relative;display:block}
.candx{position:absolute;top:-6px;right:-6px;width:20px;height:20px;border-radius:50%;
  border:1px solid var(--firm);background:var(--raised);color:var(--muted);font-size:13px;
  line-height:1;cursor:pointer;padding:0;display:none}
.candwrap:hover .candx{display:block}
.candx:hover{color:var(--stop);border-color:var(--stop)}
.cand.add{display:flex;align-items:center;justify-content:center;cursor:pointer;
  border:1px dashed var(--firm);background:transparent;color:var(--muted);
  border-radius:8px;aspect-ratio:1}
.cand.add span{font-size:22px;line-height:1;font-weight:300}
.cand.add:hover{border-color:var(--accent);color:var(--accent);background:var(--tint)}
@media (hover:none){.candx{display:block}}
/* The landing flash. Long enough to find with your eye, short enough not to nag. */
.flash{animation:flash .9s ease}
.slab.flash,.candidates.flash,textarea.flash{border-radius:8px}

/* ---- Artwork detail. The grid is for comparing; this is for deciding. */
.cand.sel{outline:2px solid var(--accent);outline-offset:1px}
.crown{position:absolute;bottom:2px;left:2px;font-family:var(--f-l);font-size:8px;
  letter-spacing:.14em;background:var(--accent);color:var(--onacc);padding:1px 5px;
  border-radius:4px}
.artdetail{display:grid;grid-template-columns:132px 1fr;gap:16px;margin:14px 0 0;
  padding:14px;border:1px solid var(--firm);border-radius:12px;background:var(--sunk)}
.artbig{width:132px;height:132px;object-fit:cover;border-radius:8px;background:var(--lift)}
.artmeta{min-width:0}
.artmeta .an{font-family:var(--f-d);font-size:15px;margin:0 0 4px;overflow-wrap:anywhere}
.artmeta .aq{font-family:var(--f-m);font-size:11px;color:var(--muted);margin:0 0 4px}
.artmeta .aq b{color:var(--ink);font-weight:400}
.artmeta .aq em{font-family:var(--f-l);font-style:normal;font-size:9px;letter-spacing:.14em;
  text-transform:uppercase;padding:1px 6px;border-radius:10px;margin-left:5px}
.artmeta .aq em.good{background:var(--good-wash);color:var(--good)}
.artmeta .aq em.warn{background:var(--lift);color:var(--warn)}
.artmeta .ap{font-family:var(--f-m);font-size:10px;color:var(--faint);margin:0 0 10px;
  overflow-wrap:anywhere}
.artacts{display:flex;flex-wrap:wrap;gap:6px}
.artacts .ok{margin:0;padding:7px 12px;display:inline-block}
@media (max-width:520px){
  .artdetail{grid-template-columns:1fr}
  .artbig{width:100%;height:auto;aspect-ratio:1}
}
/* Cover art on a release row. Small enough to scan a list by, big enough to
   recognize — which is how anyone actually finds a release they remember. */
.relhead{display:grid;grid-template-columns:44px 1fr auto;gap:13px;align-items:center}
.relart{width:44px;height:44px;border-radius:6px;object-fit:cover;background:var(--lift);
  display:block}
.relart.none{background:var(--lift);border:1px dashed var(--firm)}
@media (max-width:420px){
  .relhead{grid-template-columns:38px 1fr auto;gap:10px}
  .relart{width:38px;height:38px}
}

/* ---- Faces. A directory of names is a list; a directory of faces is something
   you scan. Initials stand in until someone uploads one, so an empty record
   still reads as a person rather than as a gap. */
.avatar{width:40px;height:40px;min-width:40px;border-radius:50%;overflow:hidden;
  flex:0 0 auto;padding:0;background:var(--lift);display:flex;align-items:center;
  justify-content:center;position:relative;aspect-ratio:1;align-self:center;cursor:pointer}
.avatar img{width:100%;height:100%;object-fit:cover;display:block}
.avatar .initials{font-family:var(--f-l);font-size:13px;letter-spacing:.06em;color:var(--muted)}
.avatar.noimg{border:1px dashed var(--firm)}
.row.person{display:grid;grid-template-columns:40px 1fr auto;gap:13px;align-items:center}

.phead{display:grid;grid-template-columns:88px 1fr;gap:18px;align-items:start;margin:0 0 4px}
.avatar.big{width:88px;height:88px;min-width:88px}
.avatar.big .initials{font-size:26px}
.avatar.big{border:0;padding:0}
.avatar.big .camera{position:absolute;bottom:0;left:0;right:0;padding:3px 0;
  background:rgba(20,12,22,.62);color:#fff;font-family:var(--f-l);font-size:8.5px;
  letter-spacing:.12em;text-transform:uppercase;text-align:center;opacity:.92}
.avatar.big.noimg{border:1px dashed var(--firm)}
.avatar.big:hover .camera{opacity:1}
.phead h1{margin-top:2px}
@media (max-width:420px){
  .phead{grid-template-columns:64px 1fr;gap:14px}
  /* min-width has to come down with width. Without it the 88px floor from
     .avatar.big survived into the 64px column, so the circle rendered 88 wide
     by 64 tall -- an oval, overflowing its column and sitting 10px on top of
     the person's name. Measured, not guessed: the name is what it covered. */
  .avatar.big{width:64px;height:64px;min-width:64px}
  .avatar.big .initials{font-size:19px}
}
/* A sent link opens to show what happened on it. */
.share{border-bottom:1px solid var(--line)}
.share:last-child{border-bottom:0}
.share.open{background:var(--sunk)}
.share.open .chev{transform:rotate(90deg)}
.share .chev{transition:transform .15s}
.sdetail{padding:4px 15px 18px}

/* ---- Cover art opens where you tapped it.
   The controls used to live in a panel below the grid, which meant looking away
   from the thing you had just tapped to find out what you could do with it. */
/* `display:flex` on a class beats the browser's own [hidden]{display:none},
   which left a full-screen fixed overlay sitting invisibly over every page and
   swallowing every click. It only lays out when it is actually open. */
.lightbox{position:fixed;inset:0;z-index:60;display:none;align-items:center;
  justify-content:center;padding:24px}
.lightbox:not([hidden]){display:flex}
.lbscrim{position:absolute;inset:0;background:rgba(18,11,20,.78);
  backdrop-filter:blur(3px);animation:fade .16s ease}
.lbcard{position:relative;z-index:1;max-width:520px;width:100%;max-height:92vh;overflow:auto;
  background:var(--raised);border:1px solid var(--firm);border-radius:16px;
  box-shadow:0 24px 70px rgba(18,11,20,.45);animation:rise .18s ease}
.lbimg{width:100%;aspect-ratio:1;object-fit:cover;display:block;
  border-radius:15px 15px 0 0;background:var(--lift)}
.lbx{position:absolute;top:10px;right:10px;width:32px;height:32px;border-radius:50%;
  border:0;background:rgba(18,11,20,.55);color:#fff;font-size:19px;line-height:1;
  cursor:pointer;z-index:2}
.lbx:hover{background:rgba(18,11,20,.8)}
.lbfoot{padding:16px 18px 18px}
.lbfoot .an{font-family:var(--f-d);font-size:16px;margin:0 0 5px;overflow-wrap:anywhere}
.lbfoot .an .isnow{font-family:var(--f-l);font-style:normal;font-size:9px;letter-spacing:.16em;
  text-transform:uppercase;background:var(--accent);color:var(--onacc);
  padding:2px 7px;border-radius:10px;margin-left:7px;vertical-align:2px}
.lbfoot .aq{font-family:var(--f-m);font-size:11px;color:var(--muted);margin:0 0 5px}
.lbfoot .aq b{color:var(--ink);font-weight:400}
.lbfoot .aq em{font-family:var(--f-l);font-style:normal;font-size:9px;letter-spacing:.14em;
  text-transform:uppercase;padding:1px 6px;border-radius:10px;margin-left:5px}
.lbfoot .aq em.good{background:var(--good-wash);color:var(--good)}
.lbfoot .aq em.warn{background:var(--lift);color:var(--warn)}
.lbfoot .ap{font-family:var(--f-m);font-size:10px;color:var(--faint);margin:0 0 13px;
  overflow-wrap:anywhere}
/* Three actions now fit here, not two. `.btn` is `flex:1 1 0`, which shares the
   row equally and — with a nowrap label — clips the longest one rather than
   letting the row wrap. Sized from content instead, so a third button wraps to
   its own line on a phone instead of cutting "Download original" in half. */
.lbacts{display:flex;flex-wrap:wrap;gap:7px}
.lbacts .btn{flex:1 1 auto}
.lbacts .ok{margin:0;padding:9px 14px;display:inline-block}
.lbacts .ok.destructive{margin-left:auto}
/* The portrait viewer's one control: the ••• that opens the photo menu. */
.lbmore{margin-left:auto;color:rgb(var(--onphoto-rgb))}
.lbmore:active{background:rgba(var(--onphoto-rgb),.12)}
.lbmore:focus-visible{outline-color:rgb(var(--onphoto-rgb))}
@keyframes fade{from{opacity:0}to{opacity:1}}
@keyframes rise{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@media (max-width:520px){
  .lightbox{padding:0;align-items:flex-end}
  .lbcard{max-height:94vh;border-radius:16px 16px 0 0}
  .lbimg{border-radius:15px 15px 0 0}
  .lbacts .ok{flex:1 1 auto;text-align:center}
  .lbacts .ok.destructive{margin-left:0}
}

/* Visually hidden but still rendered — a display:none file input cannot always
   be opened, by a label or by script. */
/* For a screen reader and nobody else.
   `.sr` was used in five places and defined in none, so every label written to
   be heard rather than seen was simply on the page — "Search photos" sitting
   above a search box that already says so. Same declaration as `.vh`; both
   names exist because both are used, and renaming five call sites is a worse
   trade than one extra selector. */
.vh,
.sr{position:absolute;width:1px;height:1px;opacity:0;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0;padding:0;margin:-1px}
.lyrmore{display:flex;gap:16px;flex-wrap:wrap;margin:8px 0 0}

/* ---- A question with two or three answers shows them. The cycle chip made you
   tap and guess where you would land. */
.pickset{display:inline-flex;gap:5px;flex-wrap:wrap;vertical-align:middle}
.kvr .v em.unset{display:block;font-family:var(--f-b);font-style:italic;font-size:12px;
  color:var(--faint);margin:5px 0 0}

/* ---- Ownership on a release: one block per track, editable where it is shown. */
.ownblock{border:1px solid var(--line);border-radius:12px;padding:14px 16px;margin:0 0 10px;
  background:var(--sunk)}
.ownhead{display:flex;align-items:baseline;gap:9px;flex-wrap:wrap;margin:0 0 2px}
.ownhead .tn{font-family:var(--f-m);font-size:11px;color:var(--faint)}
.ownhead .inline{font-family:var(--f-d);font-size:16px;border-bottom-color:transparent}
.ownhead .tag{font-style:normal}
.ownby{font-size:12.5px;color:var(--muted);font-weight:300;margin:0 0 4px}
.ownby.none{color:var(--warn);font-style:italic}

/* ---- Reading an agreement. The clause under each number is the whole point:
   it is what a person checks against before accepting anything. */
.agree{margin:14px 0 0}
.agrow{display:grid;grid-template-columns:118px 1fr;gap:12px;padding:9px 0;
  border-bottom:1px solid var(--line);align-items:baseline}
.agk{font-family:var(--f-l);font-size:10px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--faint)}
.agv{font-size:13.5px;color:var(--soft);font-weight:300;overflow-wrap:anywhere}
.agv b{color:var(--ink);font-weight:500}
.agv .none{color:var(--faint);font-style:italic}
.agv em.warn{font-family:var(--f-l);font-style:normal;font-size:9px;letter-spacing:.14em;
  text-transform:uppercase;background:var(--lift);color:var(--warn);padding:1px 6px;
  border-radius:10px;margin-left:5px}
.clause{font-size:12px;line-height:1.55;color:var(--muted);font-style:italic;
  margin:6px 0 10px;padding:8px 12px;border-left:2px solid var(--firm);background:var(--raised)}
.agnotes{margin:12px 0 0;padding:10px 13px;border-radius:9px;background:var(--lift)}
.agnotes p{margin:0 0 5px;font-size:12.5px;color:var(--warn)}
/* A name that is close to somebody in HQ but not exactly them: one question,
   answered in place, before the terms can be accepted (Phase 3 §3.6). The
   notes box's own ground, so it reads as part of the same review. */
.agclose{margin:12px 0 4px;padding:10px 13px;border-radius:9px;background:var(--lift)}
.agclose p{margin:0 0 6px;font-size:13.5px;color:var(--ink)}
.agclose .lyrbar{margin:0}
.agnotes p:last-child{margin:0}

/* ---------------------------------------------------------------- intake
   "Release a song". One column, generous targets, and nothing that looks
   compulsory except the title — because nothing is. Every control clears the
   44px touch target the design system asks for even where the glyph is small. */
.intake{display:grid;gap:24px;margin:20px 0 48px}
.lede{font-size:17px;color:var(--soft);margin:0 0 8px;max-width:34em}

.ifs{border:1px solid var(--line);border-radius:12px;padding:16px;margin:0;
  background:var(--raised);display:grid;gap:12px}
.ifs legend{font-family:var(--f-l);font-size:19px;padding:0 6px;color:var(--accent)}

.lbl{display:block;font-size:14px;color:var(--muted);margin:4px 0 -4px}
.in{width:100%;box-sizing:border-box;min-height:44px;padding:11px 12px;
  font:inherit;font-size:16px;color:var(--ink);background:var(--ground);
  border:1px solid var(--firm);border-radius:9px}
.in:focus-visible{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}
.ta{min-height:140px;line-height:1.55;resize:vertical}
select.in{appearance:none;background-image:linear-gradient(45deg,transparent 50%,var(--muted) 50%),
  linear-gradient(135deg,var(--muted) 50%,transparent 50%);
  background-position:calc(100% - 19px) 20px,calc(100% - 14px) 20px;
  background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:38px}

/* A real <label for>, not a div with a click handler. A display:none input
   cannot be opened by script in Safari — we have already been caught by that. */
.filepick{display:grid;gap:3px;min-height:56px;align-content:center;cursor:pointer;
  padding:12px 14px;border:1.5px dashed var(--firm);border-radius:10px;
  background:var(--sunk);transition:border-color 140ms,background 140ms}
.filepick:hover,.filepick:focus-within{border-color:var(--accent);background:var(--tint)}
.fpmain{font-size:16px;color:var(--accent);font-weight:500}
.fpsub{font-size:13.5px;color:var(--muted)}
.or{margin:2px 0;font-size:13.5px;color:var(--faint);text-align:center}

.go{display:inline-block;min-height:48px;padding:13px 22px;border:0;border-radius:10px;
  background:var(--cta);color:var(--oncta);font:inherit;font-size:16px;font-weight:500;
  cursor:pointer;text-align:center;text-decoration:none}
.go:hover{filter:brightness(1.1)}
.go[disabled]{color:var(--off);cursor:default}
.go.primary{margin:2px 0 18px}
.istatus{margin:2px 0;font-size:14.5px;color:var(--muted);min-height:1.4em}
.istatus.bad{color:var(--stop)}
.hint{font-size:13.5px;color:var(--muted);margin:2px 0}

/* The bordered confirmation box above, with room at its sides too: `0` here
   put the words against the border (seen on the release plan's "ready"). */
.done{padding:28px 20px}

/* ------------------------------------------------------------- tracklist
   Move up / move down rather than drag only: dragging is unreachable by
   keyboard, unreliable on a phone, and this list is short. */
.tracklist{margin:26px 0}
.tl{list-style:none;margin:0;padding:0;display:grid;gap:6px}
.tr{display:grid;grid-template-columns:26px 1fr auto;gap:10px;align-items:center;
  padding:9px 10px;border:1px solid var(--line);border-radius:10px;background:var(--raised)}
.tno{font-family:var(--f-m);font-size:13px;color:var(--faint);text-align:right}
.tt{display:grid;gap:1px;min-width:0}
.tt a{color:var(--ink);text-decoration:none;font-size:16px}
.tt a:hover{color:var(--accent);text-decoration:underline}
/* A tracklist row's song stage (bars + word), read-only, under the title. */
.tt .rtl-stage{display:block;font-size:12px;line-height:1.3}
.tv{font-size:13px;color:var(--muted);overflow-wrap:anywhere}
.tv .drift{color:var(--warn);font-weight:500;font-style:normal}
.tbtns{display:flex;gap:4px}
/* Born an icon button -- a 38px square for an arrow or an x -- and since
   reused for words: "Publish Brand Kit", "Reset to IndyHouse default",
   "Choose it", "Sign out". With no padding of its own the words sat on the
   border, and ten screens had each patched their own padding back in (build
   10, item 3 and the audit after it). The padding lives here now: an icon
   still fits the 38px minimum, a label gets room, and a long label wraps
   inside the button instead of running out of it. */
/* A toolbar label may be a whole phrase, so it wraps inside its own border. */
.tb{min-width:38px;max-width:100%;overflow-wrap:anywhere;white-space:normal}
.tb.add{min-width:62px}
.addrow{display:grid;grid-template-columns:1fr auto;gap:8px;margin-top:10px}
.tstatus{font-size:14px;color:var(--muted);margin:8px 0 0;min-height:1.3em}
.tstatus.bad{color:var(--stop)}

@media (min-width:900px){
  .intake{max-width:52em}
  .ifs{padding:20px 22px}
}

/* ================================================================ song room
   The approved direction: light, feminine, softly witchy, editorial. A large
   translucent enlargement of the song's ACTUAL cover fading into cream, dusty
   rose atmosphere, expressive serif title, and the original circular player
   kept exactly as it was.
   Reference: brooklyn-song-room.html, approved 2026-09-11.

   Two rules the background lives under, both from the brief:
     * It is decorative. It must never obstruct selection, scrolling, hit
       targets, focus rings or reading.
     * It is a presentation layer. opacity and gradients only — never a filter
       or an edit that touches the source, and never the file a download hands
       over. */
/* The room's colors ARE the app's colors now — these alias the palette above
   so a change happens in one place. Only the art variables are the room's own.
   Kept as separate names because the gradients below read better for it and
   because a per-song focal point needs somewhere to live. */
:root{
  --room-paper:var(--ground); --room-ink:var(--ink); --room-soft:var(--muted);
  --room-rose:#D3AABC; --room-rule:var(--firm); --room-frame:#E3D8DF;
  /* The player's glass, its unplayed bars and the print's paper. These were
     written into their rules, which is why no look could reach them. */
  --room-glass:rgba(248,244,247,.86); --room-wave:#C3ACBC; --room-print:#FFFAF6;
  --room-art-opacity:.46;
  /* Focal point. Both axes are tokens so a per-song override has somewhere to
     live, and so each breakpoint can crop past the furniture a cover carries at
     its own edges — a title band at the top, an artist credit at the bottom. */
  --room-art-x:50%;
  --room-art-y:42%;
}
html[data-room="dark"]{
  /* The room is a light idea. After dark it becomes a lit room rather than a
     bleached one: the art carries more, the paper recedes. Same structure, so
     nothing has to be laid out twice.

     Keyed to the room and not to the OS preference, so a dark LOOK gets the
     lit room too — otherwise Evergreen would put cream-mode art treatment on
     a near-black page. */
  --room-rose:#8E5F75; --room-frame:#33223A;
  --room-glass:rgba(36,23,41,.86); --room-print:#241729;
  --room-art-opacity:.34;
}

.room{position:relative;isolation:isolate;overflow:hidden;margin:-14px -18px 26px;
  padding:18px 18px 30px;background:var(--room-paper);color:var(--room-ink);
  font-family:var(--f-s);font-synthesis:none}

/* The actual cover, enlarged and faded. Sharp — opacity does the fading, not a
   blur, because the brief asks for the art to stay recognizable. */
/* right:-50% + width:140% puts the image's LEFT edge at 10% of the viewport,
   which reads as a faint vertical seam down the page where the photograph
   simply stops. 165% pushes that edge off-screen so the art fades out through
   the gradient instead of ending at a line. */
/* A large ENLARGEMENT, which is the word the brief uses. At 165% of a 390px
   phone the image is 644px against a 620px frame — barely cropped, so the whole
   cover is in shot including its own furniture. Eaten By Flowers has its title
   printed across the top, and it landed straight through the page's title:
   "Eaten By" in plum with "BY FLO" in white running through it.
   At 260% the frame shows the middle of the picture. A cover's title band and
   artist credit sit at its edges, so cropping past them is both the fix and
   the more striking image — which is what an enlargement is for. */
.room-backdrop{position:absolute;top:0;right:-50%;width:260%;height:620px;z-index:-3;
  pointer-events:none;opacity:var(--room-art-opacity);
  object-fit:cover;object-position:var(--room-art-x) var(--room-art-y);
  /* The image fades out at its OWN bottom edge. The wash alone was not enough:
     when the room grows taller than the backdrop — a long task list, a tablet
     width — the photograph simply stopped, leaving a hard horizontal line
     across the page. A mask travels with the image whatever height it ends up. */
  -webkit-mask-image:linear-gradient(0deg,transparent 0%,#000 26%);
  mask-image:linear-gradient(0deg,transparent 0%,#000 26%)}
/* Phone: the vertical stop is what does the work. Solid paper from the bottom
   up past the player and the task list; the art is left to the top third,
   where only the eyebrow and the 68px title sit over it. */
.room-wash{position:absolute;inset:0;z-index:-2;pointer-events:none;
  background:
    linear-gradient(90deg,rgba(var(--veil),.55) 0%,rgba(var(--veil),.3) 55%,rgba(var(--veil),.04) 100%),
    linear-gradient(0deg,var(--room-paper) 0%,var(--room-paper) 52%,
      rgba(var(--veil),.9) 62%,rgba(var(--veil),.35) 82%,rgba(var(--veil),.12) 100%)}
html[data-room="dark"] .room-wash{
  background:
    linear-gradient(90deg,rgba(var(--dusk),.6) 0%,rgba(var(--dusk),.34) 55%,rgba(var(--dusk),.06) 100%),
    linear-gradient(0deg,var(--room-paper) 0%,var(--room-paper) 52%,
      rgba(var(--dusk),.9) 62%,rgba(var(--dusk),.38) 82%,rgba(var(--dusk),.14) 100%)}
/* No art: the intentional cream-and-rose fallback, never a broken image. */
.room.noart .room-wash,.room:not(:has(.room-backdrop)) .room-wash{
  background:radial-gradient(120% 80% at 88% 4%,var(--room-rose) 0%,transparent 62%),
    linear-gradient(0deg,var(--room-paper) 0%,var(--room-paper) 30%,rgba(var(--veil),.7) 70%)}

/* A protective ground under the words.
   Readability must not be a property of whichever cover this song has: a dark
   or busy photograph drops supporting type to about 2.2:1, well under AA.
   How that is guaranteed differs by width, because the constraint does:

     DESKTOP — there is space beside the column, so the art simply begins where
     the words end. No glyph is ever composited over the photograph.

     PHONE — the column IS the screen. Keeping text off the art would mean no
     art, which is the whole design. So the art stays and the wash carries the
     contrast: solid paper up from the bottom across the reading area, with the
     photograph present at the top where only the eyebrow and the big title sit
     — and a 68px title needs 3:1, not 4.5:1.
   Measured, not assumed; the numbers are in docs/IMPLEMENTATION.md. */
.room-content{position:relative;max-width:none}

@media (min-width:781px){
  .room-content::before{content:"";position:absolute;z-index:-1;pointer-events:none;
    top:-24px;bottom:-24px;left:-100vw;right:-280px;
    background:linear-gradient(90deg,
      var(--room-paper) 0%,
      var(--room-paper) calc(100% - 280px),
      rgba(var(--veil),.72) calc(100% - 150px),
      rgba(var(--veil),0) 100%)}
  html[data-room="dark"] .room-content::before{
    background:linear-gradient(90deg,
      var(--room-paper) 0%,
      var(--room-paper) calc(100% - 280px),
      rgba(var(--dusk),.74) calc(100% - 150px),
      rgba(var(--dusk),0) 100%)}
}

/* Ink, not soft. The eyebrow sits at the very top of the page where the art is
   strongest, and in --room-soft it measured 3.16:1 against a real cover — under
   AA for text this size. It also carries the song's status and its ISRC, which
   the brief is explicit about not demoting to decorative label color. */
/* The visible way back to the catalog (Phase 4 punch list, §9: a song page
   with no way back to the list it came from). Swipe-from-edge and the
   browser/phone back button still work; this is the on-screen affordance
   for a tap. */
.room-back{display:inline-flex;align-items:center;gap:3px;min-height:32px;margin:0 0 10px;
  font:600 13px var(--f-s);color:var(--room-ink);text-decoration:none;opacity:.85}
.room-back:hover{opacity:1;text-decoration:underline}
.room-back span{font-size:17px;line-height:1}

.room-eyebrow{font:500 11.5px/1.5 var(--f-s);letter-spacing:.18em;text-transform:uppercase;
  margin:0 0 17px;color:var(--room-ink)}
.room-eyebrow .mono{font-family:var(--f-m);letter-spacing:.04em;text-transform:none}

.room-title{font:400 clamp(52px,13vw,68px)/.87 var(--f-d);letter-spacing:-.055em;
  margin:0 0 20px;color:var(--room-ink);text-wrap:balance}
.room-title span{display:block}
.room-title em{font-style:italic;display:block;margin-left:28px;margin-top:8px}

/* --soft, not --muted. Over Eaten By Flowers this measured 4.72:1 — passing,
   but with 0.22 of margin, and these are the writers' names. --soft puts it
   near 6:1 with no visible change on paper. */
.room-intro{font:400 21px/1.25 var(--f-l);margin:0 0 26px;max-width:24ch;color:var(--soft)}
.room-intro .ri2{font-size:18px}

/* ================================================================ release planning
   The countdown, in the hero, under the credits and above the player.

   The numeral is the composition — it is the one thing a person crossing the
   room should be able to read — so it is fluid rather than fixed and it sits on
   the display serif the titles already use. It leads the label rather than
   being labeled: "40" then "DAYS TO RELEASE", the way the approved image has
   it, so the number is never waiting on a word to make sense.

   All of it lives inside .room and therefore on the room's own tokens, which is
   what keeps it legible over the photograph in every look. Nothing here paints
   its own color. */
.relplan{margin:20px 0 0}
.rel-count{display:flex;align-items:center;gap:13px;margin:0 0 4px}
.rel-count b{font:400 clamp(88px,23vw,112px)/.78 var(--f-d);letter-spacing:-.045em;
  color:var(--room-ink);font-variant-numeric:lining-nums tabular-nums}
.rel-count span{font:400 clamp(18px,4.4vw,23px)/1.08 var(--f-d);letter-spacing:.055em;
  text-transform:uppercase;color:var(--room-ink)}
.rel-when{font:400 17px/1.4 var(--f-l);color:var(--room-soft);margin:0}
.rel-eyebrow{font:500 11.5px/1.5 var(--f-s);letter-spacing:.18em;text-transform:uppercase;
  color:var(--room-soft);margin:0 0 4px}
.rel-nodate{font:400 27px/1.15 var(--f-d);color:var(--room-ink);margin:0}
.rel-state{font:400 clamp(30px,7vw,38px)/1.06 var(--f-d);letter-spacing:-.02em;
  color:var(--room-ink);margin:0 0 2px}

.rel-acts{display:flex;align-items:center;flex-wrap:wrap;gap:10px 20px;margin:15px 0 0}
.rel-btn{display:inline-flex;align-items:center;gap:9px;min-height:44px;padding:0 17px;
  border:1px solid var(--room-frame);border-radius:10px;background:transparent;
  color:var(--room-ink);font:400 15.5px/1 var(--f-s);cursor:pointer}
.rel-btn:hover{border-color:var(--accent);color:var(--accent)}
.rel-btn svg{flex:none}
.rel-link{font:400 15.5px/1 var(--f-s);color:var(--room-ink);text-decoration:none;
  display:inline-flex;align-items:center;gap:7px;min-height:44px}
.rel-link:hover{color:var(--accent);text-decoration:underline}

/* The next team target. Deliberately subordinate: one line of fact, one way in.
   It is a TEAM target and never a distributor's deadline, so it is warm rather
   than red — amber says "look at this", red says "something is broken", and
   nothing here is broken. */
.rel-band{display:flex;align-items:center;gap:13px;margin:16px 0 0;padding:13px 15px;
  /* The text column is 445px on a wide screen, which folds "September 11" onto
     a line of its own. The band is one fact and one way in; it reads as one
     line, so it is allowed the width that takes, capped so it never runs under
     the photograph. */
  width:max-content;max-width:min(620px,100%);
  border-radius:12px;background:var(--band, rgba(var(--amber),.11));
  border:1px solid var(--band-line, rgba(var(--amber),.26))}
.rel-band-ic{flex:none;display:flex;color:var(--room-ink);opacity:.75}
.rel-band-txt{flex:1;min-width:0}
.rel-band-txt b{display:block;font:500 16.5px/1.25 var(--f-s);color:var(--room-ink)}
.rel-band-txt small{display:block;font:400 13.5px/1.45 var(--f-s);color:var(--room-soft);
  margin-top:1px}
.rel-band-act{flex:none;font:400 14.5px/1 var(--f-s);color:var(--room-ink);
  text-decoration:none;display:inline-flex;align-items:center;gap:6px;min-height:44px}
.rel-band-act:hover{color:var(--accent);text-decoration:underline}

/* The plan and the saved timeline disagree.

   Its own block rather than a third state of .rel-band, because it is not a
   deadline — it is a question about which deadline is real, and it carries an
   action that changes stored dates. Amber, with the words doing the work: the
   color is a cue and never the message. */
.rel-conflict{margin:12px 0 0;padding:13px 15px;max-width:min(620px,100%);
  border-radius:12px;background:rgba(var(--amber),.11);
  border:1px solid rgba(var(--amber),.34)}
.rc-t{font:500 15.5px/1.3 var(--f-s);color:var(--room-ink);margin:0}
.rc-s{font:400 13.5px/1.5 var(--f-s);color:var(--room-soft);margin:4px 0 0}
.rc-k{font:400 12.5px/1.45 var(--f-s);color:var(--room-soft);margin:6px 0 0;opacity:.85}
.rc-act{margin-top:10px;min-height:44px;padding:0 14px;border-radius:9px;
  font:500 14.5px/1 var(--f-s);color:var(--room-ink);cursor:pointer;
  background:transparent;border:1px solid var(--room-ink)}
.rc-act:hover{background:var(--room-ink);color:var(--ground)}
.rc-act[disabled]{opacity:.55;cursor:default}

/* Narrow: the action wraps under the text rather than squeezing both. */
@media (max-width:640px){
  .rel-band{flex-wrap:wrap;row-gap:4px}
  .rel-band-txt{flex:1 1 auto;min-width:60%}
  .rel-band-act{margin-left:32px}
}

/* The wide composition the reference shows: a bigger numeral, and the label
   allowed onto one line once there is room for it. */
@media (min-width:1024px){
  .rel-band{max-width:min(620px,calc(100vw - 2 * var(--edge) - 300px))}
  .rel-count b{font-size:clamp(128px,11vw,160px)}
  .rel-count span{font-size:26px}
  .rel-when{font-size:19px}
}

/* The exact version, and what the file actually is. Raised to a readable size
   rather than copying the reference's 10px specimen: this is the line somebody
   checks before a delivery. */
.room-original{display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  margin:0 0 10px;font:400 13px/1.5 var(--f-s);color:var(--room-ink)}
.room-original b{font-weight:500}
.room-original span{font:400 12px/1.5 var(--f-m);color:var(--room-soft);text-align:right}

/* The original player, unchanged in identity: circular control, real waveform,
   elapsed/total. Only the surface is retuned to the room. */
.room-player{border:1px solid var(--room-frame);border-radius:12px;
  background:var(--room-glass);padding:14px 15px 12px;backdrop-filter:none}
.room-player .play{width:44px;height:44px;border-radius:50%;background:var(--accent);
  color:var(--onacc);display:flex;align-items:center;justify-content:center;flex:none;border:0;
  cursor:pointer;font-size:0}
.room-player .play svg{margin-left:2px}
.room-player .play[disabled]{opacity:.4;cursor:default}
.room-player .ptop{display:flex;align-items:center;gap:13px}
.room-player .wave{flex:1;display:flex;align-items:center;gap:1.5px;height:40px;min-width:0}
.room-player .wave i{display:block;flex:1;min-width:1px;background:var(--room-wave);border-radius:1px}
.room-player .wave i.p{background:var(--accent)}
.room-player .ptime{display:flex;justify-content:space-between;margin:8px 2px 0;
  font:400 12px/1.5 var(--f-m);color:var(--room-soft)}

.room-hint{font:400 13.5px/1.5 var(--f-s);color:var(--room-soft);margin:10px 0 0}
.room-hint.none{font-style:italic}
.room-download{display:inline-flex;gap:8px;align-items:center;min-height:44px;padding:10px 0;
  margin-top:4px;color:var(--room-ink);font:400 14px/1.5 var(--f-s);text-decoration:none}
.room-download:hover{color:var(--accent);text-decoration:underline}

/* "Your part today" — a real queue off the gates, not decorative copy. */
.room-prompt{margin-top:32px}
.room-prompt h2{font:400 27px/1.1 var(--f-l);letter-spacing:-.01em;margin:0 0 12px;
  color:var(--room-ink)}
.room-task{display:flex;justify-content:space-between;align-items:center;gap:20px;width:100%;
  padding:14px 0;border:0;border-top:1px solid var(--room-rule);background:none;
  color:var(--room-ink);font:400 15px/1.5 var(--f-s);text-align:left;cursor:pointer;
  min-height:44px}
.room-task:hover:not([disabled]){color:var(--accent)}
.room-task[disabled]{cursor:default;color:var(--room-soft)}
.room-task small{display:block;font:400 12.5px/1.5 var(--f-s);color:var(--room-soft);margin-top:2px}
.room-task .arr{flex:none;font-size:17px;font-style:normal;color:var(--room-soft)}
.room-clear{margin-top:30px;padding-top:16px;border-top:1px solid var(--room-rule);
  font:400 14px/1.6 var(--f-s);color:var(--room-soft);max-width:34ch}

/* The tilted print: decorative framing of the real cover. Hidden on phones,
   where the backdrop already carries the image. */
.room-sleeve{display:none}
.room-sleeve-frame{padding:9px 9px 28px;background:var(--room-print);
  box-shadow:0 12px 24px rgba(64,38,56,.12)}
html[data-room="dark"] .room-sleeve-frame{box-shadow:0 12px 28px rgba(0,0,0,.4)}
.room-cover{width:100%;aspect-ratio:1;display:block;object-fit:cover}
.room-sleeve figcaption{font:400 15px/1.3 var(--f-l);text-align:center;color:var(--room-soft);
  margin-top:12px}
.room-sleeve figcaption a{color:inherit;text-decoration:none}
.room-sleeve figcaption a:hover{color:var(--accent);text-decoration:underline}

/* The wordmark, at its own aspect ratio. Never rebuilt from a font, never
   stretched — it is the supplied asset. */
/* The wordmark gives way; the controls do not.
   `flex:none` meant a 150px image refused to shrink, so at 150% text on a
   phone the header could not fit the wordmark plus the three circles and the
   whole document scrolled sideways by 20px. Nobody who needs larger text
   should have to scroll horizontally to reach the profile button. */
.mark{display:flex;align-items:center;flex:0 1 auto;min-width:0;margin-right:auto}
.mark img{width:150px;max-width:100%;height:auto;display:block}
html[data-room="dark"] .mark img{filter:invert(1) brightness(1.9)}

/* Tablet and compact desktop */
@media (min-width:781px){
  .room{margin:-14px -28px 30px;padding:22px 38px 36px}
  .room-content{max-width:400px}
  .room-title{font-size:74px}
  .room-backdrop{width:110%;right:-24%;height:730px;--room-art-y:50%}
  .room-wash{background:
    linear-gradient(90deg,var(--room-paper) 0%,rgba(var(--veil),.96) 19%,rgba(var(--veil),.6) 42%,rgba(var(--veil),.02) 72%),
    linear-gradient(0deg,var(--room-paper) 0%,var(--room-paper) 7%,rgba(var(--veil),.91) 20%,rgba(var(--veil),.05) 57%,rgba(var(--veil),.18) 100%)}
  html[data-room="dark"] .room-wash{background:
    linear-gradient(90deg,var(--room-paper) 0%,rgba(var(--dusk),.96) 19%,rgba(var(--dusk),.62) 42%,rgba(var(--dusk),.04) 72%),
    linear-gradient(0deg,var(--room-paper) 0%,var(--room-paper) 7%,rgba(var(--dusk),.92) 20%,rgba(var(--dusk),.06) 57%,rgba(var(--dusk),.2) 100%)}
  .room-sleeve{display:block;position:absolute;right:32px;top:170px;width:135px;margin:0;
    transform:rotate(3deg)}
}

/* Roomy desktop: the reference's 70px padding, 445px column, art in the rest */
@media (min-width:1000px){
  .room{margin:-14px -34px 34px;padding:22px 70px 44px}
  .room-content{max-width:445px}
  .room-title{font-size:clamp(74px,6vw,94px)}
  .room-intro{font-size:22px;max-width:27ch}
  .room-backdrop{width:83%;right:-10%;height:760px;--room-art-y:54%}
  .room-sleeve{right:62px;top:332px;width:200px}
  .room-sleeve figcaption{font-size:17px}
}

/* Motion: functional only, and honored. No parallax, no ambient loop. */
@media (prefers-reduced-motion:reduce){
  .room-task,.room-download{transition:none}
}

/* Top chrome, rebalanced around the wordmark.
   The wordmark is the anchor; Back sits to its left and the account controls to
   its right. On a phone the email is the first thing to go — it is the least
   useful item up there and the one most likely to shove the theme control off
   the edge, which is what it was doing. */
.topbar{gap:10px;padding:14px 0 6px;background:var(--room-paper)}
.back{order:-1;flex:none;font-size:13px;letter-spacing:.08em;min-height:44px;
  display:flex;align-items:center}
.mark img{width:132px}
.who{margin-left:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:40vw}
.tsw{margin-left:0;flex:none;min-width:38px;min-height:38px}
@media (max-width:640px){
  .who{display:none}
  .mark img{width:118px}
  .back{font-size:0}                  /* the chevron alone; the word is noise here */
  .back::before{content:"‹";font-size:22px;line-height:1}
}
@media (min-width:781px){
  .mark img{width:172px}
}

/* The room runs up under the top chrome so the art is not cut off by a seam.
   The chrome keeps its own solid background, so nothing it holds sits on top of
   the photograph — the brief is explicit that controls stay readable. */
body{background:var(--room-paper)}
html{background:var(--room-paper)}

/* The room breaks the 760px column on desktop.
   Everything else in HQ is a reading column and should stay one. The room is
   the one place the art needs the whole width, so it escapes and re-establishes
   its own padding.
   One trap worth naming: a percentage in `padding` resolves against the
   CONTAINING BLOCK, not the element. `calc(50vw - 50% ...)` therefore measured
   half of body's 760px column, not half of the full-bleed room, and shoved the
   text into the middle of the page. Everything below is absolute. */
/* The page column's LEFT EDGE, expressed the same way body computes it, so the
   room can line its text up with the sections below instead of guessing.
   --shell is body's max-width at this breakpoint, --edge is body's padding.
   These must track the body rules: 760/22 by default, 40px padding from 760px
   up, and the 1240px desktop shell from 900px up. They replace `--col`/`--gutter`,
   which stood in for all of this at a flat 760/22 and put the room's text 222px
   to the right of every heading under it at 1440px. */
:root{ --shell:760px; --edge:22px; }
@media (min-width:760px){ :root{ --edge:40px } }
@media (min-width:900px){ :root{ --shell:1240px } }

@media (min-width:781px){
  .room{
    width:100vw;
    margin-left:calc(50% - 50vw);
    margin-right:calc(50% - 50vw);
    margin-top:-14px;margin-bottom:30px;
    /* Line the room's text up with every other column on the page, so moving
       from the hero to the sections below is not a sideways jump. */
    padding:22px calc(max(0px, (100vw - var(--shell)) / 2) + var(--edge)) 40px;
  }
  .room-backdrop{height:100%;min-height:560px}

  /* The print lives in the space to the right of the reading column. Mirroring
     the page gutter guarantees a gap: the column ends at gutter+445, the print
     starts at 100vw-gutter-width, and below 1180px there is not enough between
     them, so it goes rather than collides. */
  .room-sleeve{left:auto;
    right:calc(max(0px, (100vw - var(--shell)) / 2) + var(--edge));
    top:170px;width:150px}
}
@media (min-width:1000px){
  .room-sleeve{top:300px;width:200px}
  .room-sleeve figcaption{font-size:17px}
}
@media (min-width:781px) and (max-width:1179px){
  .room-sleeve{display:none}
}

/* ============================================== the room, through the app
   The song page established the language. This carries it to every other
   screen without turning anything into dashboard chrome: editorial headings,
   fine separators, real breathing room, and operational facts left precise.
   What deliberately does NOT change: tables of splits, fees, archive status
   and release blockers stay as legible as they were. The brief is explicit
   that visual minimalism must not cost an operational fact. */

/* Headings. One expressive family for titles, a quieter serif for section
   heads, and a readable sans everywhere a person has to work. */
h1{font-family:var(--f-d);font-size:clamp(30px,7vw,38px);line-height:1.04;
  letter-spacing:-.02em;margin:8px 0 6px}
h1.song{font-size:clamp(34px,9vw,44px)}
h1.big{font-family:var(--f-d);font-size:clamp(32px,8vw,42px);letter-spacing:-.03em}

/* The old slab was 10.5px, tracked out, uppercase — decorative, and carrying
   counts somebody needs to read. Now a real section heading in the reference's
   second serif, with its count beside it rather than shrunk into it. */
.slab{font-family:var(--f-l);font-size:23px;letter-spacing:-.01em;text-transform:none;
  color:var(--ink);margin:34px 0 12px;padding:0;border:0;
  display:flex;align-items:baseline;gap:10px}
.slab span{font-family:var(--f-s);font-size:13px;letter-spacing:0;color:var(--muted);
  text-transform:none}
.slab::after{content:"";flex:1;height:1px;background:var(--line);margin-left:4px}

.eyebrow{font-family:var(--f-s);font-weight:500;font-size:11.5px;letter-spacing:.18em;
  text-transform:uppercase;color:var(--muted)}
.meta{font-family:var(--f-l);font-size:17px;font-weight:400;color:var(--muted);
  line-height:1.35}
.lede{font-family:var(--f-l);font-size:21px;line-height:1.3;color:var(--muted)}
.hint{font-family:var(--f-s);font-size:13px;color:var(--muted);font-weight:400;line-height:1.55}

/* Lists are editorial rows separated by hairlines, not stacked cards. A card
   says "distinct working surface"; a song in a list is not one. */
.rows{display:block;background:none;border:0;border-radius:0}
.row{background:none;border:0;border-top:1px solid var(--line);border-radius:0;
  padding:15px 2px;min-height:60px;align-items:center}
.rows .row:last-child{border-bottom:1px solid var(--line)}
.row:hover{background:var(--tint)}
.row .nm{font-family:var(--f-l);font-size:19px;line-height:1.25;color:var(--ink);margin:0 0 2px}
.row .sb{font-family:var(--f-s);font-size:12.5px;color:var(--muted);font-weight:400}
/* Status reads as a word first and a color second, per the brief: an
   unexplained amber dot is not a status. */
.tag{font-family:var(--f-s);font-weight:500;font-size:10.5px;letter-spacing:.1em;
  text-transform:uppercase;border-radius:4px;padding:4px 7px}

/* Primary actions: solid, readable, never translucent. */
/* Small secondary buttons. The old 10.5px tracked-out uppercase belonged to
   the previous chrome; in the room a button reads as a phrase. 13px also puts
   it back over the size where a label is comfortably legible. */

/* Identifiers stay mono and stay readable — 12px, not the reference's 10px
   specimen. An ISRC that has to be transcribed into a delivery form is not
   decorative type. */
.mono{font-family:var(--f-m);font-size:12px;letter-spacing:-.01em}
.path{font-family:var(--f-m);font-size:11.5px;color:var(--muted);font-style:normal}

/* Key/value tables — splits, fees, identifiers, archive status. Deliberately
   plain and deliberately unchanged in structure: these are the operational
   facts the design is not allowed to soften. */
.kvr{border-top:1px solid var(--line);padding:12px 0;align-items:baseline}
.kvr .k{font-family:var(--f-s);font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted)}
.kvr .v{font-family:var(--f-s);font-size:15px;color:var(--ink)}
.kvr .v.none{color:var(--faint);font-style:italic}


/* Bottom navigation. The old rule here set 10px uppercase letter-spaced labels,
   which fought the approved board — sentence case, and never below 11px. */
.tabs{background:var(--chrome);border-top:1px solid var(--line);
  backdrop-filter:saturate(1.1) blur(8px)}

/* A song page's sections sit on paper, so the sunk surfaces that used to
   separate them are unnecessary weight. */
.todo,.vrow{background:none;border-top:1px solid var(--line);border-radius:0}

/* A quiet row of secondary actions. One primary per decision area; everything
   else is a text link, because a screen with three full-width buttons has no
   primary action at all.

   `.quietrow`, not `.quiet` (build 10, items 2 and 3). `.quiet` is also the
   modifier on a quiet BUTTON -- `.act.quiet`, `.tb.quiet`, `.sl-btn.quiet` --
   and this row rule, written for a container, reached every one of them:
   display:flex and padding:0 put "Remove this song from the catalog" hard
   against the top of its box and ran "Reset to IndyHouse default" out past
   its border. A container and a modifier cannot share a name. */
.quietrow{display:flex;flex-wrap:wrap;gap:6px 20px;margin:14px 0 6px;padding:0}
.quietrow .linky{min-height:44px;align-self:flex-start}

/* Buttons speak, they do not shout. The tracked-out uppercase label belonged to
   the old chrome; in the room a button is a sentence. */

/* A release's one-line state, in the hero. Said as a sentence with a color
   behind it rather than as an unexplained dot — the brief is explicit that an
   amber dot is not a status. The detail stays below, in full. */
.room-state{display:inline-block;font:500 13.5px/1.4 var(--f-s);margin:4px 0 0;
  padding:9px 13px;border-radius:8px;border:1px solid var(--firm);
  background:var(--raised);color:var(--ink)}
.room-state.block{border-color:var(--stop);color:var(--stop);background:var(--room-block)}
.room-state.wait{border-color:var(--firm);color:var(--soft)}
.room-state.ok{border-color:var(--good);color:var(--good);background:var(--room-ok)}
/* After dark both washes come from html[data-room="dark"] at the top. */

/* ---------------------------------------------------------------- home
   The work queue. Editorial rows on hairlines, the same language as the song
   room — no KPI tiles, no status-pill cloud, no dashboard chrome. The only
   thing here that raises its voice is a release with a real problem. */
.clearday{font-family:var(--f-l);font-size:21px;line-height:1.35;color:var(--muted);
  max-width:32ch;margin:18px 0 8px}

/* Reusing the song room's task row, as a link. Same shape, same target size. */
a.room-task{text-decoration:none}
.hrow{width:100%;box-sizing:border-box}
.hrow.mine span{font-weight:500}
.hrow.stop{border-top-color:var(--stop)}
.hrow.stop span{color:var(--stop)}

/* A release with something outstanding. A card here is right — it IS a
   distinct working surface, and it is the one place on Home that should stop
   the eye. Everything else stays a row. */
.riskcard{display:block;text-decoration:none;color:inherit;
  border:1px solid var(--firm);border-radius:12px;background:var(--raised);
  padding:15px 16px;margin:0 0 10px}
.riskcard:hover{border-color:var(--accent)}
.rkhead{display:flex;justify-content:space-between;align-items:baseline;gap:14px;margin:0 0 9px}
.rkhead b{font-family:var(--f-l);font-weight:400;font-size:20px;color:var(--ink)}
.rkwhen{font-family:var(--f-m);font-size:12px;color:var(--muted);white-space:nowrap}
.rkwhen.soon{color:var(--warn)}
.rkwhy{margin:0;padding:0;list-style:none;display:grid;gap:5px}
.rkwhy li{font-family:var(--f-s);font-size:14.5px;color:var(--ink);
  padding-left:15px;position:relative;line-height:1.4}
.rkwhy li::before{content:"";position:absolute;left:0;top:.58em;width:5px;height:5px;
  border-radius:50%;background:var(--mauve)}
/* The reason goes on its own line. Inline, "Every mix approved" and "Brooklyn
   has not signed these off" ran together into one sentence that read as
   neither a label nor an explanation. */
.rkwhy em{display:block;font-style:normal;font-size:13px;color:var(--muted);
  margin-top:1px;line-height:1.4}
.rklate{font-family:var(--f-s);font-size:13px;color:var(--stop);margin:9px 0 0}
.rklate.warn{color:var(--warn)}

/* Tidying. Collapsed, uncounted in anything urgent, and it says so on the
   summary line — eight records from 2024 with gaps are not an emergency, and
   presenting them as one is how a person learns to ignore the whole screen. */
.tidy{margin:30px 0 0;border-top:1px solid var(--line);padding-top:6px}
/* display:flex on a <summary> removes the disclosure triangle in every
   browser, so the affordance has to be drawn back on. Without it this reads as
   a dead heading and nobody discovers there is anything under it. */
.tidy summary{font-family:var(--f-l);font-size:19px;color:var(--muted);cursor:pointer;
  padding:12px 0 12px 22px;min-height:44px;display:flex;align-items:baseline;gap:10px;
  flex-wrap:wrap;position:relative;list-style:none}
.tidy summary::-webkit-details-marker{display:none}
.tidy summary::before{content:"›";position:absolute;left:2px;top:11px;font-size:19px;
  color:var(--faint);transition:transform 140ms ease;transform-origin:40% 55%}
.tidy[open] summary::before{transform:rotate(90deg)}
@media (prefers-reduced-motion:reduce){.tidy summary::before{transition:none}}
.tidy summary span{font-family:var(--f-s);font-size:12.5px;color:var(--faint)}
.tidy[open] summary{color:var(--ink)}
.homefoot{margin-top:34px;padding-top:16px;border-top:1px solid var(--line)}

@media (min-width:781px){
  /* Desktop uses the width: the queue on the left, releases beside it. Not a
     phone column stretched to 1440. */
  .hgrid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.85fr);
    column-gap:44px;align-items:start}
}

/* first. unreachable. Distinct from "nothing sent yet", which looks identical
   on a list and means the opposite. */
.unreachable{font-family:var(--f-s);font-size:14px;line-height:1.5;color:var(--warn);
  border:1px solid var(--warn);border-radius:10px;padding:12px 14px;margin:14px 0 0;
  background:var(--unreach-wash)}

/* An approval that lapsed reads differently from one that was never given. */
/* The global .ok is a button (a border, capitals, no wrapping). An approval
   line that shares the class is a sentence: it wraps, and a long filename
   breaks inside the column rather than running off a phone's edge. */
.room-hint.ok{color:var(--good);border:0;padding:0;background:none;border-radius:0;cursor:auto;
  white-space:normal;text-transform:none;letter-spacing:0;font:400 13.5px/1.5 var(--f-s);min-height:0}
.room-hint.ok:hover{background:none}
.room-hint .mono{overflow-wrap:anywhere}
.room-hint.warn{color:var(--warn)}
.room-hint .mono{font-size:11.5px}

/* ---------------------------------------------------------------- delivery
   A frozen package IS a distinct working surface — somebody sent it, somebody
   received it, it has its own receipt — so this is one of the few places a
   card earns itself. The lists inside stay plain rows. */
.pkg{border:1px solid var(--firm);border-radius:12px;background:var(--raised);
  padding:14px 16px;margin:0 0 10px}
.pkghead{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin:0 0 3px}
.pkghead b{font-family:var(--f-l);font-weight:400;font-size:19px;color:var(--ink)}
.pkgsub{font-family:var(--f-s);font-size:12.5px;color:var(--muted);margin:0 0 4px}
.pkgstate{font-family:var(--f-s);font-size:11px;font-weight:500;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted)}
.pkgstate.live{color:var(--good)}
.pkgstate.corrections{color:var(--warn)}
.pkgacts{margin:6px 0 0}
.pkgdetail{margin-top:8px;border-top:1px solid var(--line);padding-top:8px}

.prep{border-top:1px solid var(--line);padding-top:4px;margin-top:14px}
.prep summary{font-family:var(--f-l);font-size:20px;color:var(--ink);cursor:pointer;
  padding:12px 0 12px 22px;min-height:44px;position:relative;list-style:none;
  display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.prep summary::-webkit-details-marker{display:none}
.prep summary::before{content:"›";position:absolute;left:2px;top:11px;font-size:19px;
  color:var(--faint);transition:transform 140ms ease;transform-origin:40% 55%}
.prep[open] summary::before{transform:rotate(90deg)}
.prep summary span{font-family:var(--f-s);font-size:12.5px;color:var(--muted)}

/* What is going, and what is not. Two lists that look related but not alike —
   the second is information, never an error, because a package with no lyrics
   is a legitimate thing to send. */
.willgo{list-style:none;margin:8px 0;padding:0;display:grid;gap:1px}
.willgo li{display:flex;justify-content:space-between;gap:14px;align-items:baseline;
  padding:7px 0;border-top:1px solid var(--line)}
.wgp{font-family:var(--f-s);font-size:13.5px;color:var(--ink);overflow-wrap:anywhere}
.wgd{font-family:var(--f-s);font-size:12px;color:var(--muted);white-space:nowrap;flex:none}
.wgd.mono{font-family:var(--f-m);font-size:11px}
.willgo.miss .wgp{color:var(--muted)}
.wgmiss{font-family:var(--f-s);font-size:12.5px;color:var(--muted);margin:14px 0 0}

/* A file a delivery cannot go without.

   Marked rather than left to the reader to infer from the sentence beside it.
   The list already said "the master predates original-file tracking, so its
   hash is unknown", which is true and does not tell anybody that this is the
   one that stops the package — it read the same as "lyrics: none supplied". */
.willgo li.req{border-top-color:var(--stop)}
.willgo li.req .wgp{color:var(--ink)}
.reqmark{font:600 10.5px/1 var(--f-s);letter-spacing:.06em;text-transform:uppercase;
  color:var(--stop);border:1px solid currentColor;border-radius:4px;
  padding:2px 5px;margin-left:7px;vertical-align:1px}
/* A missing file's row (Phase 3 §3.5). It used to be two columns, with the
   reason held on one line -- which squeezed the name into a sliver that broke
   mid-word down the screen and folded the badge in half. The name and badge
   share a line; the reason wraps beneath; the fix sits under that. */
.willgo.miss li{flex-direction:column;align-items:stretch;gap:3px}
.wghead{display:flex;align-items:center;justify-content:space-between;gap:10px;min-width:0}
.willgo.miss .wgp{overflow-wrap:normal;word-break:normal;min-width:0}
.willgo.miss .wgd{white-space:normal;flex:initial}
.wghead .reqmark{flex:none;white-space:nowrap}
.wgfix{align-self:flex-start;margin-top:4px;min-height:44px}
.wgblock{font-family:var(--f-s);font-size:13.5px;line-height:1.5;color:var(--ink);
  margin:14px 0 8px;padding:10px 12px;border-radius:10px;
  background:rgba(var(--late-rgb),.08);border:1px solid rgba(var(--late-rgb),.28)}
.wgblock b{display:block}

.evform{display:grid;gap:8px;margin-top:4px}
.evform .act{margin-top:6px}

/* ---------------------------------------------------------------- filing
   Where a contract will land in her Drive, shown while it is still a typo.

   Deliberately quiet: a bordered panel, not a card with a shadow and a radius
   like everything else on the page. It is a statement of fact about a path,
   and it should read as one. The only color it earns is the folder name,
   because that is the part somebody has to get right. */
.filing{border:1px solid var(--line);border-left:3px solid var(--accent);
  border-radius:0 10px 10px 0;padding:14px 16px;background:var(--sunk)}
.filing.vague{border-left-color:var(--firm)}
.flabel{margin:0 0 8px;font-family:var(--f-s);font-size:12px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--faint)}
.fpath{margin:0;font-family:var(--f-l);font-size:19px;line-height:1.3;color:var(--muted)}
.fpath i{font-style:normal;color:var(--faint);padding:0 4px}
.fpath b{font-weight:400;color:var(--accent)}
.fname{margin:4px 0 0;font-family:var(--f-m);font-size:13px;line-height:1.55;
  color:var(--soft);word-break:break-word}
.fgap{margin:10px 0 0;font-family:var(--f-s);font-size:13px;line-height:1.5;color:var(--faint)}
.fgap:empty{display:none}

/* The receipt after a contract is filed. Label on the left, fact on the right,
   one per line — a list of separate claims rather than a paragraph that blurs
   "kept in HQ" together with "copied to Drive". */
.receipt{list-style:none;margin:16px 0 0;padding:0;display:grid;gap:1px;
  background:var(--line);border:1px solid var(--line);border-radius:10px;overflow:hidden}
.receipt li{display:flex;gap:12px;justify-content:space-between;align-items:baseline;
  padding:10px 14px;background:var(--raised)}
.receipt span{font-family:var(--f-s);font-size:13px;color:var(--faint);flex:none}
.receipt b{font-family:var(--f-s);font-size:14px;font-weight:400;color:var(--ink);
  text-align:right;word-break:break-word}
.receipt b.mono{font-family:var(--f-m);font-size:12.5px}

/* The receipt after a contract is filed. Its own container rather than .done,
   which is shared with the song intake and carries a border plus a padding rule
   from a later block that cancels its own horizontal padding — reusing it drew
   a box with the text against the edge. */
.kept{margin:8px 0 40px}
.kept .fpath{margin-top:18px}
.keptact{display:flex;flex-wrap:wrap;gap:14px;align-items:center;margin:20px 0 0}

/* ---------------------------------------------------------------- access
   One person per card, read top to bottom: who, then whether they can actually
   get in, then what they can reach. The "cannot sign in yet" line is the point
   of the screen, so it is the only thing here that carries a color. */
.mcard{border:1px solid var(--line);border-radius:12px;padding:14px 16px;margin:10px 0;
  background:var(--raised)}
.mcard.gone{opacity:.62;background:var(--sunk)}
.mhead{display:flex;gap:10px;align-items:baseline;justify-content:space-between;margin:0}
.mhead b{font-family:var(--f-l);font-size:20px;font-weight:400;color:var(--ink)}
.mrole{font-family:var(--f-s);font-size:12px;letter-spacing:.06em;text-transform:uppercase;
  color:var(--faint);flex:none}
.maddr{margin:2px 0 0;font-family:var(--f-m);font-size:12.5px;color:var(--muted);
  word-break:break-all}
.mnote{margin:8px 0 0;font-family:var(--f-s);font-size:14px;color:var(--soft)}

/* Three states, not two. Confirmed, nobody-has-said, and turned off. */
.mok{margin:10px 0 0;font-family:var(--f-s);font-size:13px;color:var(--good)}
.mwarn{margin:10px 0 0;font-family:var(--f-s);font-size:13.5px;line-height:1.5;
  color:var(--stop)}
.mwarn.off{color:var(--faint)}

.mscope{margin:12px 0 0;display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.mscope em{font-family:var(--f-s);font-size:13px;color:var(--faint);font-style:normal}
.schip{display:inline-flex;align-items:center;gap:4px;font-family:var(--f-s);font-size:13px;
  background:var(--tint);border:1px solid var(--firm);border-radius:999px;padding:3px 4px 3px 11px;
  color:var(--soft)}
.sx{border:0;background:none;cursor:pointer;color:var(--faint);font-size:15px;line-height:1;
  padding:2px 6px;border-radius:999px;font-family:var(--f-b)}
.sx:hover{color:var(--stop);background:var(--lift)}

.mgrant,.mact{margin:12px 0 0;display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.in.mini{width:auto;min-width:11em;min-height:38px;padding:7px 10px;font-size:14px}
.mact .hint{margin:0}

/* ---------------------------------------------------------------- replies
   A thread reads top to bottom: who, what it was about, whether that recording
   is still the current one, what they said, what was said back. The staleness
   line is the only thing here that carries a color, because it is the only
   thing that changes how you should answer. */
.nt{border:1px solid var(--line);border-radius:12px;padding:15px 17px;margin:10px 0;
  background:var(--raised)}
.nthead{display:flex;flex-wrap:wrap;gap:8px;align-items:baseline;margin:0}
.nthead b{font-family:var(--f-l);font-size:19px;font-weight:400;color:var(--ink)}
.ntag{font-family:var(--f-s);font-size:11.5px;letter-spacing:.05em;text-transform:uppercase;
  color:var(--muted)}
.ntag.yes{color:var(--good)}
.ntag.no{color:var(--mauve)}
.ntwhen{margin-left:auto;font-family:var(--f-m);font-size:11.5px;color:var(--faint)}

.ntwhat{margin:6px 0 0;display:flex;flex-wrap:wrap;gap:8px;align-items:baseline;
  font-family:var(--f-s);font-size:13px;color:var(--muted)}
.ntver{font-family:var(--f-m);font-size:11.5px;color:var(--soft)}
.ntat{font-family:var(--f-m);font-size:11.5px;color:var(--accent)}

.ntstale{margin:10px 0 0;padding:9px 12px;border-radius:8px;background:var(--tint);
  border-left:3px solid var(--mauve);font-family:var(--f-s);font-size:13px;
  line-height:1.5;color:var(--soft)}
.ntstale.quiet{border-left-color:var(--firm);color:var(--faint)}

.ntbody{margin:10px 0 0;font-size:15px;line-height:1.55;color:var(--ink);white-space:pre-wrap}
.ntreply{margin:12px 0 0;padding-left:13px;border-left:2px solid var(--accent)}
.ntreply .nthead b{font-size:16px}
.ntdone{margin:12px 0 0;font-family:var(--f-s);font-size:12.5px;color:var(--faint)}

.ntform{margin:12px 0 0}
.ntform textarea{width:100%;box-sizing:border-box;min-height:52px;resize:vertical;
  font:inherit;font-size:14.5px;background:var(--sunk);color:var(--ink);
  border:1px solid var(--line);border-radius:9px;padding:10px 12px}
.ntacts{display:flex;flex-wrap:wrap;gap:8px;margin:8px 0 0}

/* The purpose picker on Send. Wider chips than the usual pickset, because each
   one is a sentence's worth of decision rather than a one-word filter. */
.pickset.purposes{gap:7px;margin:2px 0 0}

/* ---------------------------------------------------------------- upload
   A drawer on desktop, a sheet on a phone. Sending a file should never mean
   losing your place, so this sits over the page rather than replacing it. */
.upcta{margin:14px 0 6px}
.upcta .go{font-size:16px}

body.upon{overflow:hidden}
.upscrim{position:fixed;inset:0;background:var(--dim);z-index:40;
  backdrop-filter:blur(1.5px)}
.updrawer{position:fixed;z-index:41;background:var(--raised);overflow-y:auto;
  padding:26px 26px 34px;box-shadow:-18px 0 48px rgba(64,38,56,.16)}
@media (min-width:781px){
  .updrawer{top:0;right:0;bottom:0;width:min(520px,92vw);border-left:1px solid var(--line)}
}
@media (max-width:780px){
  /* Full-height sheet, and the send button clears the home indicator. */
  .updrawer{left:0;right:0;bottom:0;top:6vh;border-radius:18px 18px 0 0;
    border-top:1px solid var(--line);padding-bottom:calc(34px + env(safe-area-inset-bottom))}
}
.upx{position:absolute;top:14px;right:16px;width:40px;height:40px;border:0;background:none;
  font-size:26px;line-height:1;color:var(--faint);cursor:pointer;border-radius:50%}
.upx:hover{color:var(--accent);background:var(--tint)}
/* The drawer can always be closed (Jay, build 13: a long receipt with its
   filing questions scrolled the × away, and the strip of dimmed page above a
   phone's drawer sits under the status bar in the app, so nothing was left
   to tap). The × is fixed to the drawer's corner rather than scrolling with
   what is in it, the drawer starts below the status bar, and Done waits at
   the foot. */
.upx{position:fixed;z-index:42;background:var(--raised)}
@media (min-width:781px){ .upx{top:14px;right:16px} }
@media (max-width:780px){
  .updrawer{top:max(6vh, calc(env(safe-area-inset-top, 0px) + 8px))}
  .upx{top:calc(max(6vh, calc(env(safe-area-inset-top, 0px) + 8px)) + 10px);right:14px}
}
.updone{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:18px 0 0}
.updone .go{margin:0}

/* A file's question in the Housekeeper queue, and its answers. The answers
   are chips that wrap onto as many lines as they need -- each as wide as its
   own words, never squeezed: in a two-column row with a long file name the
   chips shrank until they drew one letter per line (Jay, build 13, the
   Dropbox filing sheet). Every row stacks: the file and its question on
   top, the answers under it. */
.row[data-hk-row]{grid-template-columns:minmax(0,1fr);row-gap:10px}
.row[data-hk-row] .nm, .row[data-hk-row] .sb{overflow-wrap:anywhere}
.row[data-hk-row] .rt{flex-wrap:wrap;justify-content:flex-start;gap:8px}
.row[data-hk-row] .rt > *{flex:0 0 auto;max-width:100%;white-space:normal;
  overflow-wrap:normal;word-break:normal;text-align:left}
.hksongs > *{flex:0 0 auto;max-width:100%}
/* The file beside its filing question: small, square, the picture itself
   (Jay, September 27). A glyph only for a file that is not a picture. */
.hkfile{display:flex;align-items:center;gap:12px;min-width:0}
.hkfile > div{min-width:0}
.hklook{flex:none;width:52px;height:52px;border-radius:8px;object-fit:cover;display:block;
  background:var(--sunk)}
.hkglyph{display:flex;align-items:center;justify-content:center;color:var(--accent);background:var(--tint)}
.hkneither{color:var(--soft)}
.hkmore{margin:12px 0 0;border-top:1px solid var(--line)}
.hkmore > summary{display:flex;align-items:center;gap:6px;min-height:44px;cursor:pointer;
  list-style:none;font:500 14px/1.3 var(--f-s);color:var(--soft)}
.hkmore > summary::-webkit-details-marker{display:none}
.hkmore > summary::after{content:"›";font-size:18px;color:var(--faint);transition:transform .15s}
.hkmore[open] > summary::after{transform:rotate(90deg)}
.uph{font-family:var(--f-d);font-size:30px;font-weight:400;margin:2px 0 6px;color:var(--ink)}
.uph em{font-family:var(--f-l);font-style:italic}

.updrop{display:grid;gap:4px;justify-items:center;text-align:center;cursor:pointer;
  margin:16px 0 0;padding:26px 18px;border:1px dashed var(--firm);border-radius:12px;
  background:var(--sunk);min-height:96px;align-content:center}
.updrop:hover,.updrop:focus-within{border-color:var(--accent);background:var(--tint)}
/* The app's camera, under Choose files: the same target, as a button. */
.updrop.upcam{width:100%;margin-top:10px;font:inherit;color:inherit}
.updrop.upcam:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.updropmain{font-size:16px;font-weight:500;color:var(--accent)}
.updropsub{font-size:13px;color:var(--muted)}

.uplist{list-style:none;margin:8px 0 0;padding:0;display:grid;gap:1px;
  background:var(--line);border:1px solid var(--line);border-radius:10px;overflow:hidden}
.uplist li{display:flex;gap:10px;justify-content:space-between;align-items:center;
  padding:9px 13px;background:var(--raised);font-size:14px}
.uplist small{display:block;font-family:var(--f-m);font-size:11.5px;color:var(--faint)}
/* This device's picture of a chosen photo, before it is sent (lookAtChosen). */
.uplook{flex:none;width:44px;height:44px;border-radius:7px;object-fit:cover;background:var(--sunk)}
.uplook + span{margin-right:auto}
.updrop-x{border:0;background:none;font-size:20px;line-height:1;color:var(--faint);
  cursor:pointer;min-width:40px;min-height:40px;border-radius:50%}
.updrop-x:hover:not([disabled]){color:var(--stop);background:var(--lift)}

.uprow{margin:12px 0 0;padding:13px 15px;border-radius:11px;background:var(--sunk);
  border-left:3px solid var(--good)}
.uprow.held{border-left-color:var(--warn)}
.uprow.bad{border-left-color:var(--stop)}
.upname{margin:0;font-family:var(--f-m);font-size:12.5px;color:var(--soft);
  word-break:break-all}
.upwhy{margin:5px 0 0;font-size:14.5px;line-height:1.5;color:var(--ink)}
.upwhy.ok{color:var(--soft)}
.upwhy.bad{color:var(--stop)}
.upfix{display:flex;flex-wrap:wrap;gap:7px;margin:10px 0 0;align-items:center}
.upacts{display:flex;flex-wrap:wrap;gap:14px;margin:9px 0 0}

/* ---------------------------------------------------------------- release tools
   Below the player, where the work is. Each card carries its real next action;
   a generic tick would say "done" about four different things at once. */
.tools{margin:36px 0 0;padding-top:26px;border-top:1px solid var(--line)}
.toolsh{font-family:var(--f-d);font-size:26px;font-weight:400;margin:0 0 2px;color:var(--ink)}
.toolgrid{display:grid;gap:16px;margin:18px 0 0}
@media (min-width:769px){ .toolgrid{grid-template-columns:1fr 1fr} }
/* A grid item's minimum is its min-content unless told otherwise, so a card
   with one long run of text takes more than its half and squeezes its
   neighbor's buttons into a stack. */
.toolgrid > *{min-width:0}

.tool{border:1px solid var(--line);border-radius:12px;padding:20px 22px;
  background:var(--raised)}
/* A card with nothing in it yet should be the height of its own two lines, not
   stretched to match whatever it happens to sit beside. */
.tool.quiet{background:var(--sunk);opacity:.72;align-self:start}
.toolhead{display:flex;gap:10px;align-items:baseline;justify-content:space-between;margin:0}
.toolhead b{font-family:var(--f-l);font-size:20px;font-weight:400;color:var(--ink)}
.toolstate{font-family:var(--f-s);font-size:11.5px;letter-spacing:.05em;
  text-transform:uppercase;color:var(--faint);flex:none}
.toolsub{margin:4px 0 0;font-size:14px;color:var(--muted)}
.toolacts{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:14px 0 0}

.cvrow{display:flex;gap:14px;margin:14px 0 0;align-items:flex-start}
.cvprev{flex:0 0 84px;border-radius:8px;overflow:hidden;background:var(--lift);
  aspect-ratio:9/16}
.cvprev video,.cvprev img{width:100%;height:100%;object-fit:cover;display:block}
.cvmeta{min-width:0}
.cvmeta .mono{margin:0;font-family:var(--f-m);font-size:12px;color:var(--soft);
  word-break:break-all}
.cvbad{margin:6px 0 0;font-size:13px;line-height:1.5;color:var(--stop)}
.cvok{margin:6px 0 0;font-size:13px;line-height:1.5;color:var(--good)}

/* The pitch, and TikTok.
   Both cards hold a text field the person will actually work in, so they get
   more vertical room than Canvas does — and both carry a history or a warning
   underneath that must stay legible without dominating the card. */
/* An <a class="tb"> was rendering as an underlined link beside real buttons —
   true of the Canvas card before these two existed. `.tb` gives an anchor its
   border and color but not its box, so it needs the layout the UA gives a
   button for free. */
.toolacts .tb{padding:0 13px;min-height:36px}

.pitchbox{width:100%;margin:14px 0 0;padding:11px 12px;border:1px solid var(--line);
  border-radius:9px;background:var(--sunk);color:var(--ink);font:inherit;
  font-size:14.5px;line-height:1.6;resize:vertical;min-height:120px;
  overflow:hidden}
.pitchbox:focus{outline:2px solid var(--accent);outline-offset:1px}
.pitchgaps,.pitchhist{margin:10px 0 0;font-size:13.5px;color:var(--muted)}
.pitchgaps summary,.pitchhist summary{cursor:pointer;color:var(--soft);
  font-family:var(--f-s);font-size:11.5px;letter-spacing:.05em;text-transform:uppercase}
.pitchgaps ul{margin:8px 0 0;padding-left:18px;line-height:1.6}
.pitchgaps b{color:var(--soft);font-weight:400}
.subrow{margin:10px 0 0;padding:10px 12px;border-radius:9px;background:var(--sunk)}
.subtext{margin:5px 0 0;font-size:14px;line-height:1.6;color:var(--ink);
  white-space:pre-wrap}

/* The clip and the sound are separated by a rule, not just a gap: they are
   facts about different things and the card must not read as one form. */
/* ---------------------------------------------------------------- two sounds

   The 30 and the 60, side by side. The layout is the argument: two cards that
   look equally weighted, over one waveform carrying two differently colored
   lanes, so "these are separate choices" is something you see before you read
   anything. A single row with a length dropdown would have said the opposite.

   The lanes are the only place color carries information, and they are
   labeled inside themselves (30s / 60s) so the picture survives being
   printed, screenshotted or seen by somebody who cannot tell the two hues
   apart. */
/* ---------------------------------------------------------- delivery checks

   Class names are prefixed. A bare `.prof` already exists on the account
   avatar in the header, and this block picked it up -- the profile selector
   rendered as a 36px circle with a letter in it. Second collision of the same
   kind in this work; both were found by measuring the render.

   Six results, and the mark is never the whole message -- every row carries
   the result in words beside it. Verified is the only thing drawn green, and
   only for what it actually checked. Gray is "not checked", which is
   deliberately not reassuring. */
.chksum{display:flex;flex-wrap:wrap;gap:8px;margin:12px 0 16px}
.chkc{display:inline-flex;gap:6px;align-items:baseline;padding:6px 10px;
  border-radius:9px;border:1px solid var(--line);
  font:400 12px/1 var(--f-s);color:var(--muted)}
.chkc b{font:600 14px/1 var(--f-s);color:var(--ink)}
.chkc.chk-verified b{color:var(--good)}
.chkc.chk-failed b{color:var(--stop)}
.chkc.chk-missing b{color:var(--warn)}
.chkc.chk-needs-review b{color:var(--warn)}
.chkc.chk-advisory b{color:var(--warn)}

.chkg{margin:0 0 6px;border-top:1px solid var(--line)}
.chkg summary{display:flex;justify-content:space-between;gap:12px;align-items:center;
  min-height:46px;cursor:pointer;font:400 14.5px/1.3 var(--f-s);color:var(--ink)}
.chkg summary span{font:400 12.5px/1 var(--f-s);color:var(--muted)}
.chklist{list-style:none;margin:0 0 10px;padding:0;display:grid;gap:1px}
.chk{display:flex;gap:11px;align-items:flex-start;padding:10px 0;
  border-top:1px solid var(--line)}
.chk-m{flex:none;width:20px;height:20px;border-radius:50%;display:flex;
  align-items:center;justify-content:center;font:600 12px/1 var(--f-s);
  border:1px solid var(--line);color:var(--muted)}
.chk-verified .chk-m{background:var(--good);border-color:var(--good);color:var(--onsem)}
.chk-failed .chk-m{background:var(--stop);border-color:var(--stop);color:var(--onsem)}
.chk-missing .chk-m{border-color:var(--warn);color:var(--warn)}
.chk-needs-review .chk-m{border-color:var(--warn);color:var(--warn)}
/* Short of a team rule, holding nothing up: amber, never the failed red. */
.chk-advisory .chk-m{border-color:var(--warn);color:var(--warn);font-style:italic}
.chk-b{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.chk-t{font:500 14.5px/1.35 var(--f-s);color:var(--ink)}
.chk-sev{font:400 11px/1 var(--f-s);color:var(--muted);font-style:normal;
  margin-left:7px;white-space:nowrap}
.chk-r{font:400 12.5px/1.3 var(--f-s);color:var(--muted)}
.chk-verified .chk-r{color:var(--good)}
.chk-failed .chk-r{color:var(--stop)}
.chk-missing .chk-r,.chk-needs-review .chk-r{color:var(--warn)}
.chk-advisory .chk-r{color:var(--warn)}
.chk-w{font:400 13px/1.45 var(--f-s);color:var(--ink)}
.chk-e{font:400 11.5px/1.4 var(--f-m);color:var(--muted);overflow-wrap:anywhere}
.chk-src{font:400 11px/1.4 var(--f-s);color:var(--faint,var(--muted))}
.chk-src a{color:inherit}
.chk-task{font:400 11.5px/1.4 var(--f-s);color:var(--accent)}
.chk-a{flex:none;display:flex;gap:6px;align-items:flex-start}

.dprof{margin:0 0 18px;padding:12px 13px;border-radius:11px;
  border:1px solid var(--line);background:var(--raised)}
.dprof-t{margin:0 0 8px;font:400 14px/1.4 var(--f-s);color:var(--ink);
  display:flex;gap:9px;align-items:center;flex-wrap:wrap}
.dprof-pick{min-height:40px;max-width:100%;width:auto}
.dprof-open summary{min-height:40px;display:flex;align-items:center;cursor:pointer;
  font:400 12.5px/1.4 var(--f-s);color:var(--muted)}

/* Per destination. One store at a time, never collapsed into a single tick. */
.destlist,.evlist{list-style:none;margin:8px 0 0;padding:0;display:grid;gap:1px}
.dest,.evrow{display:flex;gap:11px;align-items:baseline;padding:8px 0;
  border-top:1px solid var(--line)}
.dest-n{flex:none;min-width:96px;font:500 13.5px/1.3 var(--f-s);color:var(--ink)}
.dest-s,.ev-s{flex:none;min-width:88px;font:400 12.5px/1.3 var(--f-s);color:var(--due)}
.dest-w,.ev-w{flex:1;text-align:right;font:400 11.5px/1.4 var(--f-s);color:var(--muted)}
.ev-b{flex:1;font:400 13px/1.35 var(--f-s);color:var(--ink);min-width:0}
.ev-b small{display:block;font-size:11.5px;color:var(--muted)}
.evadd{margin:12px 0 0}
.evadd summary{min-height:44px;display:flex;align-items:center;cursor:pointer;
  font:500 14px/1.3 var(--f-s);color:var(--accent)}

@media (max-width:560px){
  .chk{flex-wrap:wrap;row-gap:6px}
  .chk-a{flex:1 0 100%;padding-left:31px}
  .dest,.evrow{flex-wrap:wrap;row-gap:2px}
  .dest-w,.ev-w{flex:1 0 100%;text-align:left}
}

/* ------------------------------------------------------- the release views

   Four views on one release. The bar is a real nav of real links, so it reads
   as navigation to a screen reader and a middle-click opens a view in a tab
   like any other link -- a row of buttons would be neither.

   Counts sit inside their tab because a number floating beside a word is a
   number about nothing. Each one counts one thing and says which. */
.relviews{display:flex;gap:4px;margin:0 0 18px;padding:3px;border-radius:12px;
  background:var(--raised);overflow-x:auto;
  -webkit-overflow-scrolling:touch;scrollbar-width:none}
.relviews::-webkit-scrollbar{display:none}
.rv{flex:1 0 auto;display:flex;flex-direction:column;gap:1px;justify-content:center;
  min-height:44px;padding:6px 14px;border-radius:9px;text-decoration:none;
  font:500 14.5px/1.2 var(--f-s);color:var(--muted);white-space:nowrap;text-align:center}
.rv:hover{color:var(--ink)}
.rv.on{background:var(--ground);color:var(--ink);
  box-shadow:0 1px 2px rgba(0,0,0,.06)}
.rv span{font:400 11.5px/1 var(--f-s);color:var(--muted)}
.rv.on span{color:var(--accent)}

/* The stage trail. Evidence under each stage, and "Unknown" where there is
   none -- an empty stage must not read as one that has not happened yet. */
.trail{margin:22px 0 0}
.trail-h{margin:0 0 10px;font:500 15.5px/1.3 var(--f-s);color:var(--ink);
  display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap}
.trail-h span{font:400 12.5px/1.4 var(--f-s);color:var(--muted)}
.trail-l{list-style:none;margin:0;padding:0;display:grid;gap:1px}
.ts{display:flex;gap:11px;align-items:flex-start;padding:9px 0;
  border-top:1px solid var(--line)}
.ts-m{flex:none;width:20px;height:20px;border-radius:50%;display:flex;
  align-items:center;justify-content:center;font:600 12px/1 var(--f-s);
  border:1px solid var(--line);color:var(--muted)}
.ts-t{font:400 14px/1.35 var(--f-s);color:var(--ink)}
.ts-t small{display:block;font-size:12px;color:var(--muted);margin-top:1px}
/* Scoped names. A bare `.unknown` already exists further down this file with
   display:block on it, and being later it won -- so every unreached stage laid
   its marker out above its label instead of beside it. Found by measuring the
   rendered rows, which is the only way this kind of collision ever shows up. */
.ts-done .ts-m{background:var(--good);border-color:var(--good);color:var(--onsem)}
.ts-next .ts-m{border-color:var(--accent);color:var(--accent)}
.ts-next .ts-t{font-weight:500}
.ts-unknown .ts-t,.ts-unknown .ts-t small{color:var(--muted)}
.ts-warn .ts-m{background:var(--warn);border-color:var(--warn);color:var(--onsem)}

/* Assigned to you. Cards rather than rows, because each one is a thing to
   decide and they should not read as a list to skim past. */
.assigned{margin:22px 0 0}
.actcards{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(262px,1fr))}
.actcard{display:flex;flex-direction:column;gap:5px;padding:13px 14px;
  border:1px solid var(--line);border-radius:12px;text-decoration:none;
  background:var(--ground)}
.actcard:hover{border-color:var(--accent)}
.actcard.late{border-color:rgba(var(--late-rgb),.4)}
.ac-top{display:flex;justify-content:space-between;gap:10px;align-items:baseline}
.ac-stream{font:600 10.5px/1 var(--f-s);letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted)}
.ac-due{font:500 12px/1 var(--f-s);color:var(--muted);white-space:nowrap}
.ac-due.late{color:var(--stop)}
.ac-due.none{color:var(--muted);font-weight:400}
.ac-t{font:500 15.5px/1.3 var(--f-s);color:var(--ink)}
.ac-d{font:400 12.5px/1.45 var(--f-s);color:var(--muted)}
.ac-state{font:400 12px/1.4 var(--f-s);color:var(--due)}
.ac-go{margin-top:2px;font:400 13px/1 var(--f-s);color:var(--accent)}
.ac-go i{font-style:normal}

/* Team blockers. Unassigned first, and it looks like a gap rather than a
   person -- the em dash is doing work here. */
.blockers{margin:24px 0 0}
.blklist{list-style:none;margin:6px 0 0;padding:0;display:grid;gap:1px}
.blk{display:flex;gap:12px;align-items:flex-start;padding:9px 0;
  border-top:1px solid var(--line)}
.blk-who{flex:none;display:flex;gap:7px;align-items:center;min-width:132px}
.blk-in{width:24px;height:24px;border-radius:50%;flex:none;display:flex;
  align-items:center;justify-content:center;background:var(--accent);color:var(--ground);
  font:600 10px/1 var(--f-s)}
.blk-in.none{background:transparent;border:1px dashed var(--line);color:var(--muted)}
.blk-nm{font:400 13px/1.3 var(--f-s);color:var(--ink)}
.blk-nm.none{color:var(--muted)}
.blk-t{flex:1;font:400 14px/1.35 var(--f-s);color:var(--ink);min-width:0}
.blk-t small{display:block;font-size:12px;color:var(--due);margin-top:1px}
.blk-due{flex:none;font:400 12.5px/1.4 var(--f-s);color:var(--muted);white-space:nowrap}
.blk-due.late{color:var(--stop)}
.blk.stuck .blk-t{font-weight:500}
.hint.warn{color:var(--due)}

/* The plan filters. A disabled one means the count is zero, which is an
   answer -- it is not hidden, because "nothing is unassigned" is worth
   knowing and a missing button says nothing at all. */
.planfilters{display:flex;flex-wrap:wrap;gap:7px;margin:12px 0 4px}
.pf{display:inline-flex;gap:7px;align-items:center;min-height:38px;padding:0 12px;
  border-radius:9px;border:1px solid var(--line);background:transparent;cursor:pointer;
  font:400 13.5px/1 var(--f-s);color:var(--ink)}
.pf span{font:500 11.5px/1 var(--f-s);color:var(--muted);
  background:var(--raised);border-radius:5px;padding:3px 5px}
.pf.on{background:var(--ink);color:var(--ground);border-color:var(--ink)}
.pf.on span{background:var(--onink-wash);color:var(--ground)}
.pf[disabled]{opacity:.45;cursor:default}

@media (max-width:560px){
  .actcards{grid-template-columns:1fr}
  .blk{flex-wrap:wrap;row-gap:3px}
  .blk-who{min-width:0}
  .blk-t{flex:1 0 100%;order:3}
  /* The date and the row's chevron hold the trailing edge. */
  .blk-due{margin-left:auto}
  .rv{flex:0 0 auto}
}

/* ---------------------------------------------------------------- date coach

   The manager's half of "Release a song". Quiet by design: it is explanation,
   not a control, and an artist reading it should feel told rather than sold to.
   No calendar of red and green days -- a milestone list with real dates, and
   the reasoning one tap away under "Why this date?". */
.coach{margin:14px 0 0;padding:13px 14px;border-radius:11px;
  background:var(--raised);border:1px solid var(--line)}
.coach-says{margin:0;font:400 15px/1.5 var(--f-s);color:var(--ink)}
.coach-says.bad{color:var(--bad)}
.coach-miles{list-style:none;margin:10px 0 0;padding:0;display:grid;gap:1px}
.coach-miles li{display:flex;gap:10px;align-items:baseline;padding:6px 0;
  border-top:1px solid var(--line)}
.coach-miles span{flex:1;font:400 13.5px/1.35 var(--f-s);color:var(--ink)}
.coach-miles b{font:500 13.5px/1 var(--f-s);color:var(--ink);white-space:nowrap}
.coach-miles small{font:400 11.5px/1 var(--f-s);color:var(--muted);white-space:nowrap}
/* Text first: "already gone" and "your estimate is ..." carry the meaning, and
   the color is only there to help somebody find them again. */
.coach-miles li.past b,.coach-miles li.past small{color:var(--stop)}
.coach-miles li.miss b,.coach-miles li.miss small{color:var(--warn)}
.coach-rec{margin:11px 0 0;font:400 14px/1.5 var(--f-s);color:var(--ink)}
.coach-ask{margin:11px 0 0;font:400 14px/1.5 var(--f-s);color:var(--ink)}
.coach-assume{margin:9px 0 0;font:400 12.5px/1.45 var(--f-s);color:var(--muted)}
.coach-why{margin:10px 0 0}
.coach-why summary{font:400 13px/1.4 var(--f-s);color:var(--muted);cursor:pointer;
  min-height:34px;display:flex;align-items:center}
.coach-basis{list-style:none;margin:6px 0 0;padding:0;display:grid;gap:1px}
.coach-basis li{display:flex;gap:10px;align-items:baseline;padding:5px 0;
  border-top:1px solid var(--line)}
.coach-basis span{flex:1;font:400 12.5px/1.3 var(--f-s);color:var(--ink)}
.coach-basis b{font:500 12.5px/1 var(--f-s);white-space:nowrap}
.coach-basis small{font:400 11px/1 var(--f-s);color:var(--muted);white-space:nowrap}
.chk{display:flex;gap:9px;align-items:center;margin:9px 0 0;min-height:44px;
  font:400 14px/1.4 var(--f-s);color:var(--ink);cursor:pointer}
.chk input{width:18px;height:18px;flex:none}

@media (max-width:560px){
  .coach-miles li,.coach-basis li{flex-wrap:wrap;row-gap:2px}
  .coach-miles span,.coach-basis span{flex:1 0 100%}
}

.tksounds{margin:14px 0 0}
.sndcount{float:right;font-weight:400;letter-spacing:0;text-transform:none;
  font-size:12px;color:var(--muted)}

/* One waveform, two windows over it. Position:relative so the lanes can be
   placed as percentages of the measured duration -- which is why an unmeasured
   recording draws no ruler at all rather than a ruler of unknown length. */
.sndruler{position:relative;height:44px;margin:10px 0 2px;border-radius:8px;
  background:var(--raised);overflow:hidden}
.sndwave{position:absolute;inset:0;display:flex;align-items:center;gap:1px;
  padding:0 2px;opacity:.5}
.sndwave i{flex:1;min-width:1px;background:var(--ink);border-radius:1px;display:block}
.sndlane{position:absolute;top:3px;bottom:3px;border-radius:6px;
  display:flex;align-items:flex-start;justify-content:flex-start;
  border:1.5px solid currentColor;cursor:grab;touch-action:none}
.sndlane:active{cursor:grabbing}
/* Focusable, because it is a slider as well as a thing to drag. A visible ring
   is the whole reason the keyboard path is usable at all. */
.sndlane:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.sndlane i{font:600 9.5px/1 var(--f-s);font-style:normal;letter-spacing:.04em;
  padding:2px 4px;border-radius:0 0 4px 0;background:currentColor}
.sndlane i::after{content:"";}
.sndlane.s30{color:rgb(var(--pick-rgb));background:rgba(var(--pick-rgb),.16);top:3px;height:17px;bottom:auto}
.sndlane.s60{color:rgb(var(--done-rgb));background:rgba(var(--done-rgb),.16);bottom:3px;height:17px;top:auto}
.sndlane.s30 i,.sndlane.s60 i{color:var(--onmark)}
.sndends{display:flex;justify-content:space-between;margin:0 0 10px;
  font:400 11px/1 var(--f-m);color:var(--muted)}

.sndcards{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(248px,1fr))}
.sndcard{padding:11px 12px;border:1px solid var(--line);border-radius:11px}
.sndcard.selected{border-color:rgba(var(--pick-rgb),.4)}
.sndcard.approved{border-color:rgba(var(--done-rgb),.45)}
.sndhead{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;margin:0}
.sndhead b{font:500 15px/1.2 var(--f-s);color:var(--ink)}
.snddur{font:600 10.5px/1 var(--f-s);letter-spacing:.05em;color:var(--muted);
  border:1px solid var(--line);border-radius:4px;padding:3px 5px}
/* Text and a mark, never color alone. */
.sndstate{margin-left:auto;font:500 12px/1 var(--f-s);color:var(--muted)}
.sndstate.selected{color:rgb(var(--pick-rgb))}
.sndstate.approved{color:rgb(var(--done-rgb))}
.sndsub{margin:4px 0 0;font:400 12.5px/1.45 var(--f-s);color:var(--muted)}
.sndwin{margin:8px 0 0;font:500 14px/1 var(--f-m);color:var(--ink)}
.sndwin.none{font-family:var(--f-s);font-weight:400;font-size:13px;color:var(--muted)}
.sndcard .tkrow{margin-top:9px}
.sndcard .toolacts{margin-top:9px}
.tkold{margin:14px 0 0;padding-top:13px;border-top:1px solid var(--line)}
.tkold summary{font:400 12.5px/1.4 var(--f-s);color:var(--muted);cursor:pointer;
  min-height:34px;display:flex;align-items:center}

/* Phones: one card above the other. Two of these side by side at 320px put the
   duration badge on its own line and clipped the window time, which is the one
   number on the card somebody is checking. */
@media (max-width:560px){
  .sndcards{grid-template-columns:1fr}
  .sndcount{float:none;display:block;margin-top:3px}
}

.tkclip{margin:14px 0 0}
.tksound{margin:16px 0 0;padding-top:15px;border-top:1px solid var(--line)}
.tklabel{margin:0 0 8px;font-family:var(--f-s);font-size:11.5px;letter-spacing:.05em;
  text-transform:uppercase;color:var(--faint)}
.tkrow{display:flex;flex-wrap:wrap;gap:9px;align-items:center;margin:0;
  font-size:14px;color:var(--muted)}
.tkrow label{display:flex;gap:6px;align-items:center}
.tkrow input{padding:7px 9px;border:1px solid var(--line);border-radius:8px;
  background:var(--sunk);color:var(--ink);font:inherit;font-size:14px;width:88px}
.tkrow input:focus{outline:2px solid var(--accent);outline-offset:1px}
.tkurl{flex:1 1 240px;min-width:0;width:auto}
.tksound .mono{margin:0;font-family:var(--f-m);font-size:12.5px;word-break:break-all}
.tksound .mono a{color:var(--ink)}

/* Rights & registrations.
   Quieter than the release tools above it: this is slower work, done once,
   and it should not compete with the things that happen every week. */
.rightsh{font-family:var(--f-d);font-size:21px;font-weight:400;margin:34px 0 2px;
  color:var(--ink)}
.lede.small{font-size:14px;margin:0}
.toolgrid.rights{margin:14px 0 0}
.tool.rights{background:var(--sunk)}

/* The providers' own wordmarks, at the size they were supplied for and no
   larger. Black-on-transparent, so dark mode inverts them to white rather than
   sitting them on a light plate — inverting keeps the letterforms; a plate adds
   a box that reads as a badge, and a badge reads as a connected account. */
.brandrow{margin:0 0 10px}
/* One box for every provider mark.
   Cosynd's file is width="100%" height="100%" over a 675x208 viewBox, so with
   height:auto and width:auto it filled its container and arrived four times
   the size of the Spotify mark beside it. A height and `contain` mean the
   aspect ratio decides the width and nothing can arrive oversized. */
.wordmark{display:block;height:22px;width:auto;max-width:132px;
  object-fit:contain;object-position:left center;opacity:.78}
.markicon{width:20px;height:20px;flex:none;object-fit:contain}

/* Where no verified asset exists, a clean label — not a drawn approximation.
   Set to read as the provider's name rather than as a second heading. */
.textmark{display:inline-block;font-family:var(--f-s);font-size:12px;font-weight:600;
  letter-spacing:.09em;text-transform:uppercase;color:var(--soft);opacity:.85}
.glyphrow{display:flex;gap:8px;align-items:center;color:var(--soft);opacity:.85}
.glyphrow span{font-family:var(--f-s);font-size:12px;font-weight:600;
  letter-spacing:.09em;text-transform:uppercase}
.glyphrow svg{flex:none}
/* HQ switches on its own html[data-theme] attribute, not prefers-color-scheme —
   the header toggle is the only thing that decides. Same treatment the wordmark
   in the header already gets. */
html[data-room="dark"] .wordmark{filter:invert(1);opacity:.66}
/* TikTok's mark is already built for dark and inverting it would break it. */
html[data-room="dark"] .markicon{filter:none}

.warnbox{margin:12px 0 0;padding:11px 13px;border-radius:9px;
  border:1px solid var(--firm);background:var(--ground)}
.warnbox p{margin:0 0 7px;font-size:13.5px;line-height:1.55;color:var(--muted)}
.warnbox p:last-child{margin:0}
.warnbox b{color:var(--ink);font-weight:400}

/* sumok / sumbad rather than ok / bad: a bare `.ok` already exists in this
   stylesheet as a nowrap utility, and hanging it on a paragraph made the whole
   line — inherited, invisibly — refuse to wrap and run off the card. */
.sharesline{margin:12px 0 0;font-size:14px;line-height:1.55}
.sharesline.sumok{color:var(--muted)}
.sharesline.sumbad{color:var(--stop)}
.sharesline .hint{display:block;margin-top:2px;white-space:normal}

/* The sentence that stops a provider's state being misread. It travels with
   the state everywhere, so it gets its own rule rather than a note somewhere. */
.statusnote{margin:12px 0 0;padding:10px 12px;border-radius:9px;background:var(--ground);
  border-left:2px solid var(--firm);line-height:1.55}
.statusnote b{color:var(--ink)}

.filerow{margin:12px 0 0;padding:11px 13px;border-radius:9px;background:var(--ground)}
.filerow > p:first-child{margin:0;font-size:14.5px;color:var(--ink)}
.filerow .hint{display:block;margin-top:2px}
.filerow .toolacts{margin:9px 0 0}

/* The website card: three pages, each with its own two facts.
   Delivered and live are different things and sit on different lines. */
.pagelist{margin:14px 0 0;display:flex;flex-direction:column;gap:9px}
.pagerow{padding:10px 12px;border-radius:9px;background:var(--sunk)}
.pagename{margin:0;font-size:14.5px;color:var(--ink);display:flex;gap:8px;
  align-items:baseline;flex-wrap:wrap}
.pagename b{font-weight:400}
.pagename .mono{font-family:var(--f-m);font-size:11.5px;color:var(--faint)}
.pagestate{margin:3px 0 0;font-size:13px;line-height:1.5;color:var(--muted)}
.pagestate.good{color:var(--good)}
/* Waiting is not failing. A page held back for a reason nobody can hurry —
   TikTok has not minted the sound yet — should not read as an error. */
.pagestate.waiting{color:var(--soft)}
.pagerow .tb{margin:8px 0 0;padding:0 11px;min-height:32px;font-size:14px}


/* ================================================================ art-led cards
   New Music and Releases both lead with the artwork. A song with no cover gets
   its own mark on a soft surface rather than an empty gray box — a lyric-only
   idea is a real song, not a broken row. */
.nmacts{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:18px 0 14px}
.nmacts .tb{padding:0 14px;min-height:40px}
/* The one line that says audio is optional, now that the button no longer
   does. Sits under the pair rather than beside them, so it does not push
   "Release a song" off a phone. */
.nmhint{margin:-6px 0 16px;max-width:42em}

.findwrap{display:block;margin:0 0 16px}
.find{width:100%;padding:11px 14px;border:1px solid var(--line);border-radius:14px;
  background:var(--raised);color:var(--ink);font:inherit;font-size:15px}
.find:focus{outline:2px solid var(--accent);outline-offset:1px}

.scards,.rcards{display:flex;flex-direction:column;gap:9px}
.scard,.rcard{display:flex;align-items:center;gap:13px;padding:10px 13px 10px 10px;
  border-radius:18px;background:var(--raised);border:1px solid var(--line);
  text-align:left;cursor:pointer;color:var(--ink);text-decoration:none;font:inherit;
  width:100%}
.scard:hover,.rcard:hover{border-color:var(--firm)}
.scard:focus-visible,.rcard:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

.sart,.rart{flex:none;width:56px;height:56px;border-radius:12px;overflow:hidden;
  background:var(--lift);display:flex;align-items:center;justify-content:center}
.rart{width:64px;height:64px;border-radius:14px}
.sart img,.rart img{width:100%;height:100%;object-fit:cover;display:block}
.sart.none,.rart.none{background:var(--tile)}

.sbody,.rbody{min-width:0;flex:1}
.sbody b,.rbody b{display:block;font-family:var(--f-l);font-size:18px;font-weight:400;
  line-height:1.2}
.sbody small,.rbody small{display:block;margin-top:2px;font-size:12.5px;color:var(--muted);
  line-height:1.35}
.rgap{display:block;margin-top:3px;font-style:normal;font-size:12px;color:var(--mauve)}

.stag{flex:none;font-family:var(--f-s);font-size:10.5px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);background:var(--sunk);
  padding:5px 9px;border-radius:999px}

.donebox{margin:24px 0 0}
.donebox summary{cursor:pointer;font-family:var(--f-s);font-size:12px;
  letter-spacing:.06em;text-transform:uppercase;color:var(--soft)}
.donebox summary span{text-transform:none;letter-spacing:0;color:var(--faint)}
.donebox .scards{margin-top:12px}

@media (min-width:769px){
  .scards,.rcards{display:grid;grid-template-columns:1fr 1fr;gap:12px}
}


/* Helper text that stays visible, rather than a placeholder that disappears the
   moment somebody types — which is exactly when they still need it. */
.fieldhelp{display:block;margin:5px 0 0;font-style:normal;font-family:var(--f-s);
  font-size:12.5px;line-height:1.4;color:var(--muted)}

/* The Home photo, shown as what it is: one borrowed image, not a collection. */
.photonote{display:flex;gap:13px;align-items:center;margin:12px 0 0;padding:12px 14px;
  border-radius:16px;background:var(--sunk);border:1px solid var(--line)}
.photonote img{width:64px;height:64px;border-radius:12px;object-fit:cover;flex:none;
  object-position:46% 30%}
.photonote p{margin:0;font-size:13.5px;line-height:1.5;color:var(--muted)}
.photonote b{color:var(--ink);font-weight:500}

/* Track picking, art-led. The cover is what she recognizes a song by. */
.pkart{width:38px;height:38px;border-radius:9px;overflow:hidden;background:var(--lift);
  display:flex;align-items:center;justify-content:center;flex:none;margin:0 0 7px}
.pkart img{width:100%;height:100%;object-fit:cover;display:block}
.pkart.none{background:var(--tile)}

/* ================================================================ Home
   Soft imagery, crisp controls. The photograph is washed into the ivory on its
   own layer and feathered out; nothing containing text or a control is ever
   given opacity, blur or desaturation. */
.home{position:relative;isolation:isolate}

.hero{position:absolute;top:-14px;left:50%;width:100vw;transform:translateX(-50%);
  height:330px;z-index:-2;overflow:hidden;pointer-events:none}
/* Tuned to this photograph, which the direction asks for rather than one
   opacity forced onto every image. Poison Garden has a cool gray sky, so a
   faint warm layer sits under the ivory wash; without it the top of the frame
   reads gray against a warm page. Nothing carrying text is touched. */
.hero img{width:100%;height:100%;object-fit:cover;
  object-position:var(--focal-x,48%) var(--focal-y,33%);display:block;
  filter:var(--herofx)}
/* Two washes: one flattens the photograph into the page, one feathers its lower
   edge so there is no boundary above the greeting. */
.heroveil{position:absolute;inset:0;background:
  linear-gradient(180deg, rgba(var(--veil),var(--veil-a)) 0%,
                  rgba(var(--veil),var(--veil-b)) 30%,
                  rgba(var(--veil),var(--veil-a)) 52%,
                  rgba(var(--veil),var(--veil-c)) 76%,
                  rgba(var(--veil),.99) 93%, var(--ground) 100%)}
.hero.nophoto{background:var(--sunk)}
/* On a phone the band's lower edge is where the photograph meets the page, so
   it dissolves rather than stopping. The veil already fades the bottom; this
   takes the last hard line with it. */
.hero{-webkit-mask-image:linear-gradient(180deg, #000 0%, #000 88%, transparent 100%);
  mask-image:linear-gradient(180deg, #000 0%, #000 88%, transparent 100%)}

.homebody{padding-top:208px}
.greet{font-family:var(--f-d);font-size:27px;line-height:1.14;font-weight:400;
  letter-spacing:-.012em;color:var(--ink);margin:0 0 17px;text-wrap:balance}

/* Two primary actions, side by side. Icons are subordinate to their labels. */
.acts{display:flex;gap:11px;margin:0 0 15px}
/* The one button set (above) draws every .btn. Here only the layout Home's pair
   needs: share the row, and keep a label on one line. */
.btn{flex:1 1 0;min-width:0}
.btn span{white-space:nowrap}
.acts .btn{min-height:50px}

/* Three ways into the work.
   Full-width rows separated by hairlines, not cards: a glyph, a heading with
   its helper underneath, and a chevron at the far right. The whole row is the
   target, which on a phone is the difference between a comfortable tap and an
   aimed one. */
.ways{display:flex;flex-direction:column;margin:4px 0 0;
  border-top:1px solid var(--line)}
/* Home's order puts Upcoming Releases above the ways in (Phase 2). Both end
   in a hairline, so 4px apart they read as one doubled rule; the same 22px
   Home already leaves above "Needs your attention" keeps them two blocks. */
.urels + .ways{margin-top:22px}
.way{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:15px;
  padding:15px 2px;min-height:64px;text-decoration:none;color:var(--ink);
  border-bottom:1px solid var(--line)}
.way:hover{background:var(--tint)}
.way:focus-visible{outline:2px solid var(--focus);outline-offset:-2px;border-radius:6px}
.wayic{display:flex;align-items:center;justify-content:center;width:34px;height:34px;
  flex:none;color:var(--accent)}
.wayic svg{opacity:.9}
.waytx{min-width:0;display:flex;flex-direction:column;gap:3px}
.waytx b{font-family:var(--f-s);font-size:16px;font-weight:600;line-height:1.25;
  overflow-wrap:anywhere}
.waytx small{font-family:var(--f-s);font-size:13.5px;font-weight:300;line-height:1.4;
  color:var(--muted);overflow-wrap:anywhere}
.way > .chev:last-child{flex:none}
/* Enlarged text stacks rather than squeezing the helper to nothing. The labels
   are approved copy and are never truncated. */
@media (max-width:340px){
  .way{grid-template-columns:auto 1fr;gap:12px}
  .way > .chev:last-child{display:none}
}

.hrule{border:0;border-top:1px solid var(--line);margin:0 0 14px}
.resumeh{font-family:var(--f-s);font-size:13.5px;color:var(--muted);margin:22px 0 10px}
.resumes{display:flex;flex-direction:column;gap:4px}
.resume{display:flex;align-items:center;gap:12px;padding:8px 6px 8px 0;min-height:56px;
  text-decoration:none;color:var(--ink);border-radius:10px}
.resume:hover{background:var(--sunk)}
.resume:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
/* Small artwork stays crisp. Only atmospheric background imagery is faded. */
.rthumb{width:46px;height:46px;border-radius:8px;overflow:hidden;flex:none;
  background:var(--lift);display:flex;align-items:center;justify-content:center;
  color:var(--muted)}
.rthumb img{width:100%;height:100%;object-fit:cover;display:block}
.rthumb.none{background:var(--sunk)}
.rtext{min-width:0;flex:1}
.rtext b{display:block;font-family:var(--f-l);font-size:17px;font-weight:400;
  line-height:1.25}
.rtext small{display:block;margin-top:1px;font-family:var(--f-s);font-size:13px;
  color:var(--muted)}
.ropen{display:inline-flex;align-items:center;gap:3px;flex:none;
  font-family:var(--f-s);font-size:13.5px;color:var(--muted)}
.resumenone{margin:0;font-family:var(--f-s);font-size:14.5px;line-height:1.55;
  color:var(--muted);max-width:42ch}

/* At 320, or with enlarged text, the two actions stack rather than shrink. */
@media (max-width:359px){
  .acts{flex-direction:column}
  .acts .btn{width:100%}
}

/* ---------------------------------------------------------------- desktop
   Same hierarchy, the reference's balanced composition: navigation across the
   top, greeting and actions in the ivory, the portrait to the side dissolving
   into it. No bottom bar, no stretched mobile cards, no KPI furniture. */
@media (min-width:900px){
  .home{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.02fr);
    align-items:center;gap:40px;min-height:min(70vh,560px)}
  .hero{position:relative;top:0;left:0;width:auto;transform:none;height:100%;
    min-height:520px;border-radius:0 14px 14px 0;order:2;z-index:0;
    /* Feathered on the inner edge so it belongs to the page rather than
       sitting on it as a framed panel. */
    /* Feathered on every edge, not only the inner one.
       A rectangle with three hard sides reads as a photograph pasted onto a
       page no matter what is drawn around it. Softening the top, right and
       bottom as well lets the picture and the decorated ground become one
       surface — which is what the concepts show. The left stays the deepest
       fade, because that is where it meets the greeting. */
    -webkit-mask-image:
      linear-gradient(90deg, transparent 0%, #000 20%, #000 92%, rgba(0,0,0,.55) 100%),
      linear-gradient(180deg, transparent 0%, #000 12%, #000 86%, transparent 100%);
    mask-image:
      linear-gradient(90deg, transparent 0%, #000 20%, #000 92%, rgba(0,0,0,.55) 100%),
      linear-gradient(180deg, transparent 0%, #000 12%, #000 86%, transparent 100%);
    -webkit-mask-composite:source-in;mask-composite:intersect}
  .hero img{object-position:var(--focal-x,52%) var(--focal-y,22%)}
  /* Dissolves leftward into the content rather than sitting in a hard frame. */
  .heroveil{background:
    linear-gradient(90deg, var(--ground) 0%, rgba(var(--veil),.94) 14%,
                    rgba(var(--veil),var(--veil-a)) 36%,
                    rgba(var(--veil),var(--veil-b)) 64%,
                    rgba(var(--veil),var(--veil-b)) 100%)}
  .homebody{padding-top:0;order:1;max-width:520px}
  .greet{font-size:52px;line-height:1.06;margin:0 0 26px}
  .acts{gap:13px;margin:0 0 19px}
  .acts .btn{flex:0 0 auto;padding:0 22px;min-height:52px}
  .shorts{gap:18px;margin:0 0 22px}
  .short{font-size:14.5px}
  .hrule{margin:0 0 16px}
}

/* ================================================================ the header
   Compact and ivory. The upload pill the earlier interpretation put here was a
   dominant second copy of an action Home already offers, so it becomes a quiet
   mark beside the profile control. */
.hdrup, .prof{width:36px;height:36px;min-width:36px;min-height:36px;padding:0;
  border-radius:50%;border:1px solid var(--firm);background:var(--raised);
  color:var(--soft);display:inline-flex;align-items:center;justify-content:center;
  cursor:pointer;flex:none;font-size:0}
.hdrup:hover, .prof:hover{border-color:var(--accent);color:var(--accent)}
.hdrup:focus-visible, .prof:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.prof{margin-left:2px}
/* The mark stays 36 across; the finger gets the full 44 (ui-conventions §6). */
.hdrup, .prof{position:relative}
.hdrup::after, .prof::after{content:'';position:absolute;inset:-4px;border-radius:50%}

/* Stems coming in (app/stems-header.js): a spinner and the percent, a warning
   dot when it has not moved in a long while, a red one when it needs somebody.
   The same quiet outline as the marks beside it, never a loud pill. */
.hdrimp{display:inline-flex;align-items:center;gap:6px;height:36px;min-height:36px;padding:0 11px;
  border-radius:18px;border:1px solid var(--firm);background:var(--raised);color:var(--soft);
  font-family:var(--f-m);font-size:12px;font-variant-numeric:tabular-nums;text-decoration:none;
  flex:none;position:relative;white-space:nowrap}
.hdrimp[hidden]{display:none}
.hdrimp::after{content:'';position:absolute;inset:-4px;border-radius:22px}
.hdrimp:hover{border-color:var(--accent);color:var(--accent)}
.hdrimp:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.hdrimp-dot{width:8px;height:8px;flex:none;border-radius:50%;background:var(--warn)}
.hdrimp[data-kind="failed"] .hdrimp-dot{background:var(--stop)}
.hdrimp[data-kind="failed"]{color:var(--ink)}
/* "+2": how many more are running beside the first (app/activity.js). */
.hdrimp-more{color:var(--muted)}
.hdrimp-more[hidden]{display:none}

/* The desktop navigation. Hidden on a phone, where the bottom bar has it. */
.topnav{display:none}
@media (min-width:900px){
  .topnav{display:flex;align-items:center;gap:26px;margin:0 22px 0 auto}
  .tnav{background:none;border:0;padding:6px 0 7px;cursor:pointer;position:relative;
    font-family:var(--f-s);font-size:14.5px;color:var(--muted);min-height:44px}
  .tnav:hover{color:var(--ink)}
  .tnav.on{color:var(--ink);font-weight:500}
  .tnav.on::after{content:"";position:absolute;left:0;right:0;bottom:2px;height:2px;
    border-radius:2px;background:var(--ink)}
  .tnav:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:6px}
  .who{margin-left:0}
  /* The bottom bar is a phone control; the top one replaces it here. */
  .tabs{display:none}
  body{padding-bottom:0}
}

/* ================================================================ lists
   One row treatment for Admin, and for anything else that is a labeled list
   of places to go. Fine rules rather than boxes inside boxes; the restraint is
   the point. */
.rowlist{display:flex;flex-direction:column;margin:18px 0 0;
  border-top:1px solid var(--line)}
/* Used on an <a> in most rows and on a <button> in a few — Redecorate on Brand
   is one. A button with no background set keeps the browser's own, which on a
   dark page is a solid white slab. Everything here neutralises the UA button
   styling and leaves the anchor exactly as it was. */
.rowlink{display:flex;align-items:center;gap:13px;padding:15px 4px;min-height:58px;
  border:0;border-bottom:1px solid var(--line);text-decoration:none;color:var(--ink);
  background:transparent;font:inherit;width:100%;text-align:left;cursor:pointer}
.rowlink:hover{background:var(--sunk)}
.rowlink:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.rowlink .rl-ic{flex:none;color:var(--muted);display:flex}
.rowlink .rl-t{min-width:0;flex:1}
.rowlink b{display:block;font-family:var(--f-s);font-size:15px;font-weight:500;
  line-height:1.3}
.rowlink small{display:block;margin-top:2px;font-family:var(--f-s);font-size:13px;
  color:var(--muted);line-height:1.4}
@media (min-width:900px){
  .rowlist{display:grid;grid-template-columns:1fr 1fr;column-gap:32px;
    border-top:0}
  .rowlink{border-top:1px solid var(--line);border-bottom:0}
}

/* A photo shown as what it is, beside plain text about it. */
.photonote{display:flex;gap:13px;align-items:center;margin:12px 0 0;padding:13px 14px;
  border-radius:12px;background:var(--sunk);border:1px solid var(--line)}
.photonote img{width:62px;height:62px;border-radius:9px;object-fit:cover;flex:none;
  object-position:46% 32%}
.photonote p{margin:0;font-family:var(--f-s);font-size:13.5px;line-height:1.5;
  color:var(--muted)}
.photonote b{color:var(--ink);font-weight:500}

/* A destination that exists and is honest about being empty. */
.notyet{margin:22px 0 0;padding:30px 22px;border-radius:12px;background:var(--sunk);
  border:1px solid var(--line);text-align:center;color:var(--muted)}
.notyet svg{margin:0 auto 12px;display:block;color:var(--faint)}
.notyet p{margin:0 auto 8px;font-family:var(--f-s);font-size:14.5px;line-height:1.55;
  max-width:38ch}
.notyet b{color:var(--ink);font-weight:500}

/* ================================================================ desktop shell
   The body is a 760px reading column, which is right for a song page and wrong
   for Home: the approved desktop composition is a balanced two-column layout
   across the width. Home widens; everything else keeps its column. */
@media (min-width:900px){
  body{max-width:1240px;padding-left:40px;padding-right:40px}
  /* Only Home uses the full width. A release page reading 1160px wide would be
     a worse page, not a bigger one.
     `.room` is excluded by name. It is the one screen that deliberately breaks
     the column (see "The room breaks the 760px column on desktop" above), and
     this selector outranks it -- `#view > :not(.home)` is 1,1,0 against the
     room's 0,1,0, and it comes later in the file besides. Clamping the room to
     760px while its padding still measured `(100vw - 760px)/2 + 22` left the
     text a 36px ribbon at 1440px: 362 + 36 + 362. Exclude it here rather than
     escalate specificity over there, so the room rule stays readable. */
  /* The decorative band is not content and must not be measured like it:
     it is the full width of the window, behind everything, and the page's
     own column sits on top of it. A lightbox (the artwork viewer lives
     inside the page it opens from) covers the window, so it is not a
     column either: clamped, its dark backdrop stopped 760px across. */
  /* The fan email builder (public/app/fan-email.js) is three columns side by side: the
     blocks, the email at its real 600px, and what the chosen part says. Show demand
     (public/app/show-demand.js) is a table beside its map and the run it plans. */
  #view > :not(.home):not(.room):not(.pagewash):not(.media):not(.relwork):not(.mlib):not(.wr-wide):not(.lightbox):not(.yh-wide):not(:has(.feb-host)):not(:has(.sd)):not(:has(.fc-grid)){max-width:760px}
  /* Media is a grid of pictures, not a column of prose. At the 760px measure
     it showed two thumbnails on a 1440px screen and pushed every file below
     the fold. Same escape the photo gallery and Direct already take, at the
     same width, so the three wide pages agree. */
  #view > .media{max-width:1180px}
  .home{margin-inline:0}
  .topnav .tnav span{white-space:nowrap}
}

/* ================================================================ Music tabs
   Two tabs, not a chooser screen. The same underline the main navigation uses,
   so "where am I" reads the same way at both levels. */
.tabshead{margin:0 0 18px}
.subtabs{display:flex;gap:22px;border-bottom:1px solid var(--line);margin-top:4px}
.subtab{position:relative;background:none;border:0;cursor:pointer;padding:9px 0 11px;
  font-family:var(--f-s);font-size:16px;color:var(--muted);min-height:44px}
.subtab:hover{color:var(--ink)}
.subtab.on{color:var(--ink);font-weight:500}
.subtab.on::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;
  background:var(--ink);border-radius:2px}
.subtab:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:6px}

/* ================================================================ Photos
   The pictures are the feature. No wash, no veil, no tinting — the atmospheric
   fade belongs on Home and would make a library harder to read. */
/* Search first, and on its own line until there is room for both.
   Side by side on a 375px phone the field came out 173px — narrow enough that
   its own placeholder was clipped mid-word, which reads as broken rather than
   as a hint. Wrapping is the fix; a shorter hint would only have hidden it. */
.photobar{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:18px 0 14px}
.findwrap.grow{flex:1 1 100%;margin:0;min-width:0}
.photobar .btn{flex:0 0 auto}
@media (min-width:560px){
  .findwrap.grow{flex:1 1 auto}
}

/* .choice: the ONE pill (Round 4, "One set of controls"). It replaces .pk,
   .chip, .seg, .fs-chip, .mseg, .mchip, .wr-chip and .media-apill, which drew
   "this one is picked" eight different ways. Raised with a --firm outline off,
   filled --accent with --onacc text on. The on-state is aria-pressed="true" and
   nothing else: no .on, no aria-checked, so a screen reader hears one control.
   A count is a <small> inside it, muted. The pill is 36px, which is not a
   thumb, so ::after grows the press area to 44 without changing what is drawn.
   Where a family needs a layout (a row that never wraps, a segmented row that
   stays one line) that lives on the CONTAINER, never on the pill. */
.choices{display:flex;flex-wrap:wrap;gap:8px}
.choices.spaced{margin:0 0 18px}
.choices.scroll{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}
.choices.scroll::-webkit-scrollbar{display:none}
.choices.joined{flex-wrap:nowrap;gap:6px}
.choices.joined .choice{flex:1 1 0;min-width:0;justify-content:center;overflow:hidden;text-overflow:ellipsis}
.choice{appearance:none;position:relative;display:inline-flex;align-items:center;gap:6px;min-height:36px;padding:0 14px;
  border-radius:999px;border:1px solid var(--firm);background:var(--raised);color:var(--soft);
  font:500 14.5px var(--f-s);cursor:pointer;white-space:nowrap;flex:none}
.choice::after{content:"";position:absolute;inset:-4px 0}
.choice small{font-size:12px;color:var(--faint);font-weight:500;font-variant-numeric:tabular-nums}
.choice svg{flex:none}
.choice:hover{border-color:var(--accent)}
.choice[aria-pressed="true"]{background:var(--accent);border-color:var(--accent);color:var(--onacc)}
.choice[aria-pressed="true"] small{color:inherit;opacity:.75}
.choice[aria-pressed="true"] .jayi .jayi-spark{fill:currentColor;opacity:.75}
.choice:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
.choice:disabled{opacity:.5;cursor:default}

/* A dense, image-led grid, every cell the same square.
   Landscape frames used to carry .wide and span both columns, which on a phone
   — where the grid IS two columns — gave a third of the library the entire
   width and broke the rhythm the grid exists to create. A crop is a viewing
   choice, not a loss: the lightbox still shows the whole frame.
   One --ptile knob drives the column count at every width, so the size control
   below works on a phone and a desktop without a separate rule for each. */
.pgrid{display:grid;gap:6px;
  grid-template-columns:repeat(auto-fill,minmax(var(--ptile,164px),1fr))}
.pgrid.s-s{--ptile:104px}
.pgrid.s-m{--ptile:164px}
.pgrid.s-l{--ptile:min(100%,260px)}
/* A message about the whole grid is not one cell of it. Left as a grid item it
   took a single column and wrapped its sentence four words at a time. */
.pgrid > .empty, .pkgrid > .empty{grid-column:1 / -1}
.ptile{position:relative;padding:0;border:0;border-radius:8px;overflow:hidden;
  background:var(--lift);cursor:pointer;aspect-ratio:1;display:block}
.ptile img{width:100%;height:100%;object-fit:cover;display:block}
.ptile:hover img{opacity:.92}
.ptile:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.pmissing{position:absolute;inset:0;display:flex;flex-direction:column;gap:6px;
  align-items:center;justify-content:center;color:var(--faint);background:var(--sunk)}
.pmissing em{font-style:normal;font-family:var(--f-s);font-size:11.5px}
/* A TIFF is a TIFF. The badge says so; the download hands back the .tif. */
.pfmt{position:absolute;left:6px;bottom:6px;font-family:var(--f-s);font-size:10px;
  letter-spacing:.06em;background:rgba(56,36,47,.72);color:#FBF6F1;
  padding:2px 6px;border-radius:4px}

/* ------------------------------------------------- the photo library chrome

   Everything above the grid, sized so the first photograph is on screen when
   the page opens. The display headline that used to sit here ran to two lines
   at 393px and put the first picture below the fold. */
.libhead{display:flex;align-items:center;justify-content:space-between;
  gap:12px;flex-wrap:wrap;margin:0 0 12px}
.libhead h1{margin:0}
.libhead .tb{display:inline-flex;align-items:center;gap:7px;padding:0 12px;
  min-height:38px;white-space:nowrap}
.pfind{margin:0 0 10px}

/* One row of controls, wrapping rather than stacking. The selects are sized by
   their content — .in is width:100%, which is right for a form field and wrong
   for a toolbar. */
.ptools{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:0 0 10px}
.ptool{min-height:38px}
select.ptool{width:auto;max-width:min(100%,17rem);padding:8px 30px 8px 11px;
  font-size:14px;font-family:var(--f-s)}
button.ptool{padding:0 13px;font-size:14px;font-family:var(--f-s)}
.ptoolgap{flex:1 1 0;min-width:0}

/* A segmented control, one border around the set. */
.psize{display:flex;border:1px solid var(--firm);border-radius:9px;overflow:hidden;
  background:var(--ground);flex:0 0 auto}
.pszb{width:36px;min-height:36px;display:grid;place-items:center;padding:0;border:0;
  border-left:1px solid var(--line);background:none;color:var(--faint);cursor:pointer}
.pszb:first-child{border-left:0}
.pszb:hover{color:var(--accent)}
.pszb[aria-pressed="true"]{background:var(--accent);color:var(--onacc)}
.pszb:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}

/* Only the filters that are ON, each removable on its own. The row of one chip
   per song that used to live here was permanent, wrapped to three lines with
   ninety-four photographs behind it, and showed the same list whether or not
   anything was filtered. */
.fchips{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 10px}
.fchip{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--accent);
  background:var(--tint);color:var(--accent);border-radius:999px;padding:5px 11px;
  min-height:32px;cursor:pointer;font-family:var(--f-s);font-size:13px}
.fchip i{font-style:normal;font-size:15px;line-height:1;opacity:.75}
.fchip:hover i{opacity:1}
.fchip:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.fchip.clearall{border-style:dashed;background:none;color:var(--muted);
  border-color:var(--firm)}
.fchip.clearall:hover{color:var(--accent);border-color:var(--accent)}

/* Two true numbers at once: how many are on screen, out of how many match.
   "Show the other 34" was neither. */
.pcount{margin:0 0 10px;font-variant-numeric:tabular-nums}

@media (pointer:coarse){
  .pszb{min-height:44px;width:42px}
  .fchip{min-height:40px}
}

@media (min-width:600px){ .pgrid{gap:8px} }
@media (min-width:900px){ .pgrid{gap:10px} }

/* ---------------------------------------------------------------- lightbox */
.lightbox{position:fixed;inset:0;z-index:80;background:rgba(28,18,24,.94);
  display:flex;flex-direction:column;
  padding:max(12px,env(safe-area-inset-top)) 12px max(12px,env(safe-area-inset-bottom))}
.lbclose{position:absolute;top:max(10px,env(safe-area-inset-top));right:12px;z-index:2;
  width:44px;height:44px;border-radius:50%;border:1px solid rgba(251,246,241,.3);
  background:rgba(28,18,24,.6);color:#FBF6F1;cursor:pointer;display:flex;
  align-items:center;justify-content:center;transform:rotate(45deg)}
.lbclose:focus-visible{outline:2px solid #FBF6F1;outline-offset:2px}
.lbstage{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;
  position:relative}
.lbimg{max-width:100%;max-height:100%;object-fit:contain;display:block;border-radius:4px}
.lbmissing{color:rgba(251,246,241,.8);font-family:var(--f-s);font-size:15px;
  max-width:30ch;text-align:center;line-height:1.55}
.lbnav{position:absolute;top:50%;transform:translateY(-50%);width:46px;height:46px;
  border-radius:50%;border:1px solid rgba(251,246,241,.22);background:rgba(28,18,24,.55);
  color:#FBF6F1;cursor:pointer;display:flex;align-items:center;justify-content:center}
.lbnav.prev{left:2px;transform:translateY(-50%) rotate(180deg)}
.lbnav.next{right:2px}
.lbnav:focus-visible{outline:2px solid #FBF6F1;outline-offset:2px}

.lbfoot{display:flex;gap:14px;align-items:flex-end;justify-content:space-between;
  flex-wrap:wrap;padding:14px 4px 0;color:#FBF6F1}
.lbname{margin:0;font-family:var(--f-l);font-size:17px;line-height:1.3}
.lbsub{margin:3px 0 0;font-family:var(--f-s);font-size:12.5px;color:rgba(251,246,241,.62)}
.lbacts{display:flex;gap:9px;flex-wrap:wrap}
.lbacts .btn{background:rgba(251,246,241,.09);border-color:rgba(251,246,241,.26);
  color:#FBF6F1;min-height:44px}
/* The lightbox is the same room in every look: a photograph is judged against
   neutral dark, never against the app's palette — which is also why the picture
   itself is never filtered here. That means it must carry its OWN ink. Reading
   the page's gave cream text on a cream button at 1.11:1 under any dark look,
   and the mirror-image failure (near-black on near-black) under a light one. */
.lightbox{
  --ink:#FBF6F1; --soft:#DACFD6; --muted:#C6B9C1; --faint:#A99CA4;
  --lift:#3A2A33; --line:rgba(251,246,241,.18); --firm:rgba(251,246,241,.3);
  --good:#7FCF97; --warn:#EFCF4B; --stop:#F4847E; --destructive:#F4939C;
}
.lbacts .btn.primary{background:#FBF6F1;border-color:#FBF6F1;color:#2A1A22}
.lbacts .btn:hover{border-color:#FBF6F1}

.lbdetails{margin:12px 4px 0;padding-top:12px;border-top:1px solid rgba(251,246,241,.16);
  color:rgba(251,246,241,.8);max-height:34vh;overflow:auto}
/* Who wrote it, said by the mark rather than by the words "AI suggestion".
   The glyph sits on the first line with the sentence beside it. */
.lbai{margin:0 0 10px;font-family:var(--f-s);font-size:14px;line-height:1.55;
  display:flex;align-items:flex-start;gap:7px}
.lbai .jayi{flex:0 0 auto;margin-top:2px;opacity:.75}
/* The mark sits inline with a control's label, at the size of the words. */
.upaibatch b .jayi{vertical-align:-2px;margin-right:5px;opacity:.8}

/* The stage has to be a positioning context now that arrows live inside it. */
.media-viewer-stage{position:relative}
/* Only the position moves; the chevron's own rotation is already right in
   .lbnav above, where prev is the rotated one. Restating it here backwards
   pointed both arrows the same way. */
.media-viewer-stage .lbnav{z-index:2}
.media-viewer-stage .lbnav.prev{left:10px}
.media-viewer-stage .lbnav.next{right:10px}
/* A button that is already on says so by looking different, not only by its
   words -- the same treatment the photo lightbox gives it. */
.media-viewer-actions .btn.on{border-color:var(--accent);color:var(--accent)}
.lbdl{display:grid;grid-template-columns:auto 1fr;gap:4px 14px;margin:0;
  font-family:var(--f-s);font-size:13px}
.lbdl dt{color:rgba(251,246,241,.5)}
.lbdl dd{margin:0}
.lbtags{display:flex;flex-wrap:wrap;gap:5px;margin:12px 0 0}
.lbtags .tag{font-family:var(--f-s);font-size:11.5px;padding:3px 8px;border-radius:999px;
  background:rgba(251,246,241,.11);color:inherit}
.lbtags .tag.ai{background:transparent;border:1px solid rgba(251,246,241,.22)}

@media (min-width:900px){
  .lightbox{padding:20px 28px}
  .lbnav.prev{left:8px} .lbnav.next{right:8px}
}
@media (prefers-reduced-motion:reduce){ .ptile:hover img{opacity:1} }

/* ================================================================ Projects */
.projgrid{display:grid;grid-template-columns:1fr;gap:12px;margin:18px 0 0}
.projcard{display:block;text-decoration:none;color:var(--ink);border-radius:12px;
  overflow:hidden;border:1px solid var(--line);background:var(--raised)}
.projcard:hover{border-color:var(--firm)}
.projcard:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.projart{display:block;aspect-ratio:16/10;background:var(--tile);overflow:hidden;
  display:flex;align-items:center;justify-content:center}
.projart img{width:100%;height:100%;object-fit:cover;display:block}
/* No cover yet: the project's own name, set like a title card. */
.projart.none em{font-family:var(--f-d);font-style:italic;font-size:26px;
  color:var(--accent);opacity:.75;padding:0 18px;text-align:center}
.projbody{display:block;padding:13px 15px 15px}
.projbody b{display:block;font-family:var(--f-l);font-size:19px;font-weight:400}
.projbody small{display:block;margin-top:3px;font-family:var(--f-s);font-size:12.5px;
  color:var(--muted);text-transform:capitalize}
@media (min-width:700px){ .projgrid{grid-template-columns:1fr 1fr} }
@media (min-width:1100px){ .projgrid{grid-template-columns:repeat(3,1fr)} }

.countish{font-family:var(--f-s);font-size:13px;color:var(--faint);font-weight:400}
/* What a picture is FOR, here. The same photo can be inspiration in one project
   and a deliverable in another, so the label belongs to the link, not the file. */
.ppurpose{position:absolute;left:6px;bottom:6px;font-family:var(--f-s);font-size:10px;
  letter-spacing:.04em;background:rgba(56,36,47,.72);color:#FBF6F1;
  padding:2px 7px;border-radius:4px;text-transform:capitalize}

/* ---------------------------------------------------------------- the picker
   A sheet over the project, so she comes back to exactly where she was. */
.picker{position:fixed;inset:0;z-index:70;background:var(--ground);display:flex;
  flex-direction:column;
  padding:max(14px,env(safe-area-inset-top)) 20px max(14px,env(safe-area-inset-bottom))}
.pkhead{flex:none}
.pkback{display:inline-flex;align-items:center;gap:6px;background:none;border:0;
  cursor:pointer;color:var(--muted);font-family:var(--f-s);font-size:14px;
  min-height:44px;padding:0}
.pkback svg{transform:rotate(180deg)}
.pkback:hover{color:var(--ink)}
/* Compact, so the photographs start near the top of the screen rather than
   halfway down it. The name still reads as the heading it is, and it wraps
   rather than truncating — a long project name that ends in "…" stops telling
   you which project you are adding to. */
.pkhead h2{font-family:var(--f-d);font-size:20px;line-height:1.25;font-weight:400;
  margin:2px 0 6px;overflow-wrap:anywhere}
.pkhead .findwrap{margin:8px 0 10px}
@media (min-width:700px){ .pkhead h2{font-size:24px} }
/* The scroll viewport and the grid are two elements, deliberately.
   They used to be one: `.pkgrid` was `flex:1; min-height:0; overflow:auto`
   AND `display:grid`. A grid that is also a height-constrained flex child
   compresses its rows to fit the space it was given, while the tiles keep
   their `aspect-ratio:1` and hold their height — so every row overran the
   next. Measured before the fix: 143px tiles in 62px rows on desktop, 112px
   tiles in 26px rows at iPhone width, nineteen of twenty row pairs
   intersecting, the worst by 94px.
   The viewport bounds the height; the grid inside is sized by its content and
   is free to be taller. Nothing is clipped, no row is given a fixed height,
   and there are no negative margins holding it together. */
.pkscroll{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch}
.pkgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:7px;
  align-content:start;grid-auto-rows:min-content}
/* Selected reads as selected at a glance: a ring and a tick, not a tint. */
.ptile.picked{outline:3px solid var(--accent);outline-offset:-3px}
.ptile.picked::after{content:"✓";position:absolute;top:5px;right:6px;width:20px;height:20px;
  border-radius:50%;background:var(--accent);color:var(--onacc);font-size:12px;
  display:flex;align-items:center;justify-content:center}
/* Already in the project, said rather than left to guess. */
.ptile.here{outline:2px solid var(--firm);outline-offset:-2px}
.phere{position:absolute;left:0;right:0;bottom:0;padding:3px 5px;
  background:rgba(0,0,0,.58);color:#fff;font-family:var(--f-s);font-size:9.5px;
  letter-spacing:.02em;text-align:center;pointer-events:none}
/* Two selects and a count. It was one select and a count, so the row never had
   to wrap; adding the album menu pushed "60 of 94 photos" off the right edge of
   a phone, where it was clipped rather than wrapped. */
.pkbar{display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px;margin:0 0 10px}
.pksort{flex:0 1 auto;width:auto;max-width:100%;min-height:38px;padding:0 10px;
  font-size:13px}
/* The count takes the rest of the row, and the whole row when the selects fill
   it. `min-width:0` is what lets it shrink instead of forcing the overflow. */
.pkbar .hint{margin:0;flex:1 1 auto;min-width:0;text-align:right}
@media (max-width:460px){ .pkbar .hint{flex-basis:100%;text-align:left} }
.pkmorewrap{margin:12px 0 4px;text-align:center}
.pkmorewrap .tb{min-height:44px;padding:0 20px}
.pkfoot{flex:none;padding-top:12px}
.pkfoot .btn{width:100%}
.pkfoot .btn[disabled]{opacity:.45;cursor:default}
@media (min-width:700px){ .pkgrid{grid-template-columns:repeat(5,1fr)} }
@media (min-width:1100px){
  .picker{padding:28px max(28px,calc(50vw - 520px))}
  .pkgrid{grid-template-columns:repeat(7,1fr)}
  .pkfoot .btn{width:auto;min-width:220px}
}

/* Send feedback — the screenshot tray. Everything else on that screen is
   .form / .choice / .opt, so only the tray needs its own rules. */
.shotdrop{display:flex;flex-wrap:wrap;align-items:center;gap:9px;
  border:1px dashed var(--firm);border-radius:11px;padding:13px;
  background:var(--sunk);transition:border-color .15s,background .15s}
.shotdrop.lit{border-color:var(--accent);background:var(--lift)}
.shotdrop:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.shotdrop .hint{margin:0}
.shots{display:flex;flex-direction:column;gap:7px;margin:9px 0 0}
.shots:empty{display:none}
.shot{display:flex;align-items:center;gap:11px;
  border:1px solid var(--line);border-radius:10px;padding:8px 9px;background:var(--raised)}
.shot.bad{border-color:var(--stop)}
.shot img,.shotph{width:46px;height:46px;flex:0 0 auto;border-radius:7px;
  object-fit:cover;background:var(--sunk);border:1px solid var(--line)}
.shotmeta{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1 1 auto}
.shotmeta b{font-weight:600;font-size:14px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.shotmeta em{font-style:normal;font-size:12.5px;color:var(--muted);font-weight:300}
.shot.bad .shotmeta em{color:var(--stop)}
.shotbar{display:block;margin-top:5px}

/* ------------------------------------------------ sheets
   A sheet from the bottom on a phone, a centered dialog on a desktop. Used by
   Redecorate and by Start a project, and by anything else that needs to ask a
   question without losing the page behind it.

   This exists because the alternative was window.prompt(), which iOS can
   refuse outright — a button that does nothing, with no error and nothing in
   the console to explain it. */
.sheet{position:fixed;inset:0;z-index:60;display:flex;align-items:flex-end;
  justify-content:center}
.sheetback{position:absolute;inset:0;background:rgba(0,0,0,.42)}
.sheetpanel{position:relative;width:100%;max-height:88vh;overflow:auto;
  background:var(--ground);color:var(--ink);
  border-radius:16px 16px 0 0;border-top:1px solid var(--line);
  padding:16px 20px calc(22px + env(safe-area-inset-bottom,0px));
  box-shadow:0 -8px 40px rgba(0,0,0,.24)}
body.sheeton{overflow:hidden}
#look-h:focus-visible{outline:none}
/* The one sheet header (Round 4, from the approved mockup): Cancel / title /
   Save, or "Done" alone on the left when nothing saves. Built by sheetHead()
   in app/ui.js; nothing else draws a sheet header, so there is one rule set.

   The buttons can never be the thing that gives way. As a flex row the title
   refused to shrink past its longest word, and a long one (askOne uses the
   whole question as its heading) pushed the row wider than the panel; since
   .sheetpanel scrolls, the way out went off the side of the phone. A grid
   settles it by construction: the side columns are `minmax(max-content,1fr)`,
   never narrower than their word and equal otherwise so a short title still
   sits dead center, and the middle `minmax(0,auto)` may shrink to nothing. The
   buttons also refuse to wrap (`.tb` breaks anywhere, which once squeezed
   Cancel to "Ca/nc/el"); the title is the one that truncates, with an
   ellipsis. A disabled right button is gray, the sheet's "nothing to save yet". */
.sheet-head{display:grid;grid-template-columns:minmax(max-content,1fr) minmax(0,auto) minmax(max-content,1fr);
  align-items:center;gap:8px;margin:-6px -6px 14px;min-height:44px}
.sheet-head h2{margin:0;min-width:0;font:600 17px/1.25 var(--f-s);color:var(--ink);text-align:center;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;overflow-wrap:normal}
.sheet-head h2:focus{outline:none}
.sheet-head button{appearance:none;flex:none;min-height:44px;padding:0 6px;border:0;background:none;
  font:400 17px var(--f-s);color:var(--accent);cursor:pointer;
  white-space:nowrap;overflow-wrap:normal;word-break:normal;max-width:none}
.sheet-head .l{justify-self:start}
.sheet-head .r{justify-self:end;font-weight:700}
.sheet-head .r:disabled{color:var(--faint);font-weight:600;cursor:default}
/* The palette sheet's own list is in settings.css. */

/* Light, dark, or the device. Three states, so a two-state switch will not do. */
.schemepick{margin:16px 0 0}
.schemepick .lbl{display:block;font-family:var(--f-s);font-size:12px;
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted);margin:0 0 7px}

.lookmonths{display:flex;flex-direction:column;gap:8px;margin:12px 0 0}
.sheetacts{display:flex;flex-wrap:wrap;gap:9px;align-items:center;margin:18px 0 0}
.fldwrap{display:block;margin:14px 0 0}
.tzin{width:100%;font-family:var(--f-m);font-size:14px;color:var(--ink);
  background:var(--sunk);border:1px solid var(--line);border-radius:9px;padding:10px 12px}
.tzin:focus{border-color:var(--accent);outline:none}

.looktoast{position:fixed;left:50%;transform:translateX(-50%);
  bottom:calc(104px + env(safe-area-inset-bottom,0px));z-index:120;margin:0;
  max-width:min(92vw,420px);padding:11px 16px;border-radius:11px;
  background:var(--raised);color:var(--ink);border:1px solid var(--firm);
  font-family:var(--f-s);font-size:13.5px;line-height:1.5;
  box-shadow:0 6px 26px rgba(0,0,0,.18)}
/* Something that went wrong (oops() in app/core.js): the same toast, led by a
   warning glyph in the destructive color. */
.looktoast.bad{display:flex;align-items:flex-start;gap:10px;text-align:left}
.looktoast-gl{flex:none;margin-top:1px;color:var(--destructive)}
.looktoast.bad .looktoast-t{flex:1 1 auto}
.looktoast-ref{display:block;margin-top:2px;font-size:12px;color:var(--muted)}
.looktoast.bad.with-act .btn{flex:none;align-self:center}

@media (min-width:760px){
  .sheet{align-items:center}
  .sheetpanel{max-width:660px;max-height:84vh;border-radius:16px;
    border:1px solid var(--line);padding:20px 24px 24px}
  .looktoast{bottom:28px}
}
/* 120 is above the whole overlay stack (100-118, see overlayOpen): a toast
   said from inside the photo viewer -- "Now the cover of ..." -- used to paint
   under it at 70. While the viewer is open it also sits clear of its dock. */
body:has(> .media-viewer) .looktoast{bottom:calc(92px + env(safe-area-inset-bottom,0px))}

/* A gallery is not a document. The 760px measure is right for something you
   read line by line and wrong for ninety-four photographs: on a desktop it
   left half the screen empty and made every picture postage-stamp sized.
   Only the grid itself widens — the heading, search and filters above it keep
   the measure, so the page still reads as one column. */
@media (min-width:900px){
  #view > .pgrid{max-width:1180px}
  #view > .pgrid.s-s{--ptile:128px}
  #view > .pgrid.s-m{--ptile:190px}
  #view > .pgrid.s-l{--ptile:320px}
  /* The toolbar governs the grid, so it spans the grid. Left at the 760px
     measure, the right-aligned size control sat 400px inside the right edge of
     the thing it was resizing. The search box keeps the measure — it is a
     field you read, not a control over the grid. */
  #view > .libhead, #view > .ptools, #view > .fchips, #view > .pcount{max-width:1180px}

  /* The tools directory is a rail plus cards, which does not read as one
     column and does not want the 760px measure. Same escape the gallery uses,
     for the same reason. */
  #view > .kitwrap{max-width:1200px}
}

/* Upload progress.
   Real bytes across, because on a phone a 40MB master is a long silence and a
   silence is where somebody presses the button a second time. The bar is not
   an animation on a timer — it only ever moves when bytes actually move. */
/* The AI answer, beside the files it is about. Small, plain, and reachable
   before anything is sent — the whole requirement is that it is a choice and
   not a race between the upload finishing and finding the switch. */
.upai{display:inline-flex;align-items:center;gap:5px;margin-left:auto;
  font-family:var(--f-s);font-size:11.5px;color:var(--muted);cursor:pointer}
.upaibatch{margin:12px 0 0;min-height:0}
.upaibatch b{font-weight:600}

.upprog{margin:10px 0 0}
/* THE spinner: one ring in three sizes (consistency audit 1.4). 12px in a
   chip (the header's mark), .spin-md 14px in a row, .spin-lg 34px alone on a
   page. .across turns it green, with the bar's meaning: everything is across
   and IndyHouse is filing it. Under reduced motion it does not turn; it
   breathes, slowly, so it still says "working" without spinning. */
.spin{display:inline-block;flex:none;width:12px;height:12px;border-radius:50%;
  border:2px solid var(--line);border-top-color:var(--accent);animation:spin-turn .9s linear infinite}
.spin-md{width:14px;height:14px}
.spin-lg{display:block;width:34px;height:34px;border-width:3px}
.spin.across{border-color:color-mix(in srgb, var(--good) 28%, transparent);border-top-color:var(--good)}
@keyframes spin-turn{to{transform:rotate(360deg)}}
@keyframes spin-breathe{to{opacity:.4}}
@media (prefers-reduced-motion:reduce){
  .spin{animation:spin-breathe 1.6s ease-in-out infinite alternate}}

/* THE progress bar: the only one in the app (consistency audit 1.4, October 4,
   2026), drawn by upbar() in app/ui.js. Block-level whatever the tag: a pasted
   link's row draws it as a <span>, and an inline span ignores its height.
   Three modifiers, and nothing else means anything:
     (none)   measuring -- the accent, filled to how far it has got
     .moving  the total is not known yet: a slide, never a 0% bar that looks stuck
     .across  green, and only this is green: every byte is across and IndyHouse
              is working on it (hashing, unpacking, filing), or it is done
     .held    dimmed: paused, held, not progressing */
.upbar{display:block;position:relative;height:6px;border-radius:3px;background:var(--sunk);
  border:1px solid var(--line);overflow:hidden}
.uplist .upbar{margin-top:6px}
.uplist li > span:has(> .upbar){flex:1;min-width:0}
/* The honest line under a link the drawer brings in: this door needs the app open. */
.uplist .upkeep{display:block;margin-top:6px;color:var(--faint);line-height:1.4}
.upbar i{display:block;height:100%;width:0;border-radius:inherit;background:var(--accent);
  transition:width .18s linear}
.upbar.across i{background:var(--good);transition:width .3s ease}
.upbar.moving i{width:34%;animation:upbar-slide 1.25s ease-in-out infinite}
@keyframes upbar-slide{from{transform:translateX(-100%)}to{transform:translateX(300%)}}
.upbar.held i{animation:none;opacity:.45}
.upbar.moving.held i{width:100%;opacity:.3}
.upprog .hint{margin:6px 0 0;font-variant-numeric:tabular-nums}
/* One file going up from a screen of its own, outside the drawer (app/bar.js
   sendWithBar): its line, then the bar, under the control that sent it. */
.upinline{display:flex;flex-direction:column;gap:6px;padding:2px 16px 12px}
.upinline small{font-size:13px;line-height:1.35;color:var(--muted);overflow-wrap:anywhere;
  font-variant-numeric:tabular-nums}
/* In a narrow cell (a House mark's slot) the holder takes the cell's width. */
.markslot .upinline{padding:6px 0 0}
@media (prefers-reduced-motion:reduce){
  .upbar i{transition:none}
  .upbar.moving i{animation:none;transform:none;width:100%;opacity:.55}}

/* Why a song is not one-stop.
   A full sentence, so it wraps and is allowed to take two lines. It was in a
   .tag — an uppercase pill with white-space:nowrap — which pushed the sentence
   straight off the side of the phone and took the page's width with it. */
.ownwhy{margin:0 0 4px;font-family:var(--f-s);font-size:12.5px;line-height:1.5;
  color:var(--warn);font-weight:400;overflow-wrap:anywhere}

/* Nothing in a tag is ever long enough to need this, but a tag that is handed
   something long should still not be able to widen the document. */
.tag{max-width:100%;overflow:hidden;text-overflow:ellipsis}

/* When a split will not save.
   Loud enough to notice, next to the thing that failed, and it stays until the
   next attempt — an error that fades after two seconds is an error nobody
   reads. These handlers used to fail completely silently. */
.splitsaid{margin:8px 0;padding:9px 12px;border-radius:9px;
  background:var(--lift);border:1px solid var(--stop);color:var(--stop);
  font-family:var(--f-s);font-size:13px;line-height:1.45}
[aria-busy="true"]{opacity:.6;pointer-events:none}

/* A project's own home, when it has one. */
.prlink{margin:10px 0 0}
.prlink .btn svg{transform:rotate(-45deg)}

/* ------------------------------------------------ the room
   Decoration belongs to the whole Home composition, not to the photograph.
   Two layers sit either side of the portrait: `sky` behind it, so a firework
   or a moon reads as distance, and `near` in front, so a cat or a candle is
   grounded in the same space she is.

   Everything here is inert: no pointer events, hidden from screen readers,
   and never above the content, the navigation or a dialog. */
/* The decoration's own wrapper is never part of the layout.
   It was a plain div inside .home, which on desktop is a two-column grid — so
   it took a grid cell and threw the greeting and the portrait into the wrong
   places. Out of flow entirely: it is a frame the composition hangs in, not a
   thing on the page. */
[data-decor]{position:absolute;inset:0;pointer-events:none}

/* The composition area, which is whatever shape Home actually is.
   On a phone that is the full-bleed band across the top — the same rectangle
   the portrait occupies, so a corner piece enters at the band's corner. On a
   desktop it is the entire panel, greeting and portrait together, which is how
   the concepts are drawn: a web comes in over the text, not just over her. */
.stage{position:absolute;top:-14px;left:50%;width:100vw;transform:translateX(-50%);
  height:330px;pointer-events:none;overflow:hidden}
/* -1 does the right thing in both shapes, which is why it is one value and not
   a media query. On a desktop the portrait is z-index 0 and only occupies the
   right half, so -1 puts the sky genuinely behind it and visible beside it. On
   a phone the portrait is z-index -2 and fills the whole band, so -1 puts the
   sky in FRONT of it — which is the only place it can be seen, and is where the
   concept draws it: fireworks over the photograph's own sky. */
.stage.sky{z-index:-1}
/* The light layer blends as a GROUP with the photograph beneath it. A blend
   mode on an individual motif would be trapped inside this stage's own
   stacking context and never reach the portrait at all. */
.stage.glow{z-index:1;mix-blend-mode:screen}
.stage.near{z-index:1}
/* The content and the portrait keep their own stacking above the sky. */
.home .homebody{position:relative;z-index:2}

/* On a desktop the composition is the whole panel — greeting and portrait
   together — which is how the concepts are drawn: a web comes in over the text,
   not only over her. This has to sit AFTER the base rule above; the earlier
   attempt put it in the layout's own media query further up the file, where the
   base rule simply overrode it and the stage stayed a 330px phone band. */
@media (min-width:900px){
  .stage{top:0;left:0;width:100%;transform:none;height:100%;border-radius:14px}
}

.dm{position:absolute;display:block;line-height:0;will-change:transform}
.dm img{width:100%;height:auto;display:block}

/* ---- how each element is composited, not merely placed ----
   The correction that matters most. Transparent objects laid over a photograph
   read as stickers however well they are positioned; light has to behave like
   light, solids have to be grounded, and things at different distances have to
   look like they are at different distances. */

/* Light. Feathered at its own edges so it dissolves into the sky rather than
   ending, and warmed slightly toward the look's own accent so it belongs to
   this room's color. */
.stage .dm.fx-light img{
  -webkit-mask-image:radial-gradient(closest-side, #000 52%, rgba(0,0,0,.35) 78%, transparent 100%);
  mask-image:radial-gradient(closest-side, #000 52%, rgba(0,0,0,.35) 78%, transparent 100%)}

/* Celestial. A moon, a star — something that is LIGHT in the scene rather than
   an object in front of it.
   Three things separate it from a sticker: its edge is feathered instead of
   razor-cut, it carries a halo the way any light in air does, and it lives in
   the blended layer so the sky's own tone comes through it. The first version
   was a hard-edged specular object with a drop shadow, and no amount of
   repositioning would have fixed that. */
.stage .dm.fx-celestial img{
  -webkit-mask-image:radial-gradient(closest-side, #000 62%, rgba(0,0,0,.72) 84%, transparent 100%);
  mask-image:radial-gradient(closest-side, #000 62%, rgba(0,0,0,.72) 84%, transparent 100%)}
/* The light a lit thing throws onto the air around it. The color is the
   motif's own — a prism does not spill candlelight — so it comes from a token
   the tone sets, defaulting to the champagne the first composition used. */
.halo{position:absolute;aspect-ratio:1;transform:translate(-50%,-50%);
  --halo:232,206,158;
  border-radius:50%;pointer-events:none;
  background:radial-gradient(closest-side,
    rgba(var(--halo),.38) 0%, rgba(var(--halo),.17) 32%,
    rgba(var(--halo),.06) 56%, transparent 78%)}
.t-prism .halo{--halo:196,186,255}
.stage .dm.fx-celestial.d-mid img{filter:blur(.4px) brightness(.86) saturate(.72)
  sepia(.2) hue-rotate(-6deg)}
.stage .dm.fx-celestial.d-far img{filter:blur(.9px) brightness(.6) saturate(.55)
  sepia(.3) hue-rotate(-6deg)}

/* Moonlit sanctuary — the second high-key room, and the harder one. The hero
   itself is lifted pale here (--herofx), so nothing can be seated by darkening
   it and the screen blend is useless: white screened over white is white. Every
   motif is therefore a NEAR object sitting a little lighter than the paper,
   with a lilac whisper for a contact shadow, and the crescent is the one thing
   allowed to go slightly darker and warmer so it reads against the sky at all. */
.stage .dm.t-veil img{filter:brightness(1.04) saturate(.86) contrast(.95)}
.stage .dm.t-veil.d-far img{filter:blur(1.2px) brightness(1.1) saturate(.68) contrast(.9)}
.stage .dm.t-veil.d-mid img{filter:blur(.4px) brightness(1.06) saturate(.8) contrast(.94)}
.stage .dm.t-veil.d-near img{filter:brightness(1) saturate(.92) contrast(.96)
  drop-shadow(0 10px 18px rgba(112,94,140,.22))}
.stage .dm.t-paleluna img,
.stage .dm.t-paleluna.d-mid img{filter:brightness(.96) saturate(.9) sepia(.18)
  drop-shadow(0 0 18px rgba(224,208,168,.5))}
.t-veil .halo, .t-paleluna .halo{--halo:232,220,244}
.a-veil{
  background:
    radial-gradient(48% 36% at 74% 4%, rgba(196,182,224,.3) 0%, transparent 74%),
    radial-gradient(52% 40% at 8% 96%, rgba(214,202,230,.28) 0%, transparent 76%)}

/* Emerald moon. Two grades, because the moon and the clover are lit by
   different things: the foliage is in the green dark and falls away with
   distance, while the moon IS the light source and stays near its own value.
   Both sit after the celestial rules on purpose — a tone has to be able to
   overrule the generic treatment, and equal specificity means source order. */
.stage .dm.t-emerald img{filter:brightness(.72) saturate(1) hue-rotate(6deg)}
.stage .dm.t-emerald.d-far img{filter:blur(1.4px) brightness(.5) saturate(.8) hue-rotate(8deg)}
.stage .dm.t-emerald.d-mid img{filter:blur(.5px) brightness(.64) saturate(.94) hue-rotate(6deg)}
.stage .dm.t-emerald.d-near img{filter:brightness(.84) saturate(1.05)
  drop-shadow(0 10px 20px rgba(0,18,10,.6))}
.stage .dm.t-moonglow img,
.stage .dm.t-moonglow.d-mid img{filter:brightness(.96) saturate(.72) hue-rotate(14deg)}
.stage .dm.t-moonglow.d-far img{filter:blur(.8px) brightness(.78) saturate(.6) hue-rotate(14deg)}
.t-moonglow .halo{--halo:214,228,178}
.a-emerald{
  background:
    radial-gradient(44% 34% at 6% 6%, rgba(60,140,86,.24) 0%, transparent 74%),
    radial-gradient(38% 30% at 84% 8%, rgba(206,224,168,.18) 0%, transparent 72%),
    radial-gradient(56% 40% at 74% 98%, rgba(40,110,72,.2) 0%, transparent 76%)}

/* In the spotlight. A wine-dark room lit from one side by stage lamps, so the
   bokeh stays warm and bright while the vinyl and the roses are pulled well
   down — a record is the darkest object in this whole system. */
.stage .dm.t-spot img{filter:brightness(.82) saturate(1.02)}
.stage .dm.t-spot.d-far img{filter:blur(1.5px) brightness(.58) saturate(.86)}
.stage .dm.t-spot.d-mid img{filter:blur(.5px) brightness(.74) saturate(.95)}
.stage .dm.t-spot.d-near img{filter:brightness(.9) saturate(1.06)
  drop-shadow(0 12px 24px rgba(26,2,12,.62))}
.t-spot .halo{--halo:255,206,150}
.a-spot{
  background:
    radial-gradient(44% 36% at 90% 10%, rgba(255,186,116,.2) 0%, transparent 72%),
    radial-gradient(56% 42% at 16% 94%, rgba(150,26,58,.2) 0%, transparent 76%)}

/* Midnight sparks. Everything here is a firework, so nothing is graded down to
   sit in the scene — a burst IS the brightest thing in the sky. Depth is how
   far away the shell went off, which is mostly softness and a loss of red. */
.stage .dm.t-spark img{filter:brightness(1) saturate(1.05)}
.stage .dm.t-spark.d-far img{filter:blur(1.2px) brightness(.6) saturate(.76)}
.stage .dm.t-spark.d-mid img{filter:blur(.4px) brightness(.86) saturate(.95)}
.stage .dm.t-spark.d-near img{filter:brightness(1.06) saturate(1.1)}
.t-spark .halo{--halo:255,196,178}
.a-spark{
  background:
    radial-gradient(50% 34% at 82% 4%, rgba(226,98,110,.2) 0%, transparent 74%),
    radial-gradient(46% 32% at 14% 10%, rgba(112,150,232,.18) 0%, transparent 74%)}

/* Prism after dark. The refraction is light and stays bright; the crystal is
   a solid object in a purple room, so it is cooled rather than warmed and its
   caustic is allowed to stay the brightest thing in the frame. */
.stage .dm.t-prism img{filter:brightness(.92) saturate(1.06)}
.stage .dm.t-prism.d-far img{filter:blur(1.6px) brightness(.66) saturate(.86)}
.stage .dm.t-prism.d-mid img{filter:blur(.5px) brightness(.84) saturate(1)}
.stage .dm.t-prism.d-near img{filter:brightness(1) saturate(1.12)
  drop-shadow(0 12px 24px rgba(24,4,44,.66))}
.a-prism{
  background:
    radial-gradient(46% 38% at 12% 8%, rgba(178,120,255,.3) 0%, transparent 72%),
    radial-gradient(52% 40% at 88% 86%, rgba(96,196,255,.24) 0%, transparent 74%),
    radial-gradient(60% 46% at 50% 104%, rgba(226,112,208,.2) 0%, transparent 76%)}

/* Deep evergreen under warm lights. The fir is pushed green-cool and darkened
   so it sits behind her rather than in front, and the velvet bow keeps its
   cranberry — it is the one saturated thing the concept allows. */
.stage .dm.t-pine img{filter:brightness(.6) saturate(.92) hue-rotate(8deg)}
/* Depth here runs the other way to instinct: the night is dark, so the piece
   NEAREST the lens is the brightest thing and everything behind it falls off.
   The fir carries its own bokeh, which survives the grade; the velvet does
   not, which is why an ungraded bow read as a sticker in the first pass. */
.stage .dm.t-pine.d-far img{filter:blur(1.4px) brightness(.42) saturate(.78) hue-rotate(10deg)}
.stage .dm.t-pine.d-mid img{filter:blur(.5px) brightness(.5) saturate(.88) hue-rotate(8deg)}
.stage .dm.t-pine.d-near img{filter:brightness(.6) saturate(.94) contrast(.94)
  drop-shadow(0 10px 20px rgba(0,0,0,.6))}
.a-pine{
  background:
    radial-gradient(34% 30% at 90% 88%, rgba(232,186,120,.2) 0%, transparent 74%),
    radial-gradient(70% 30% at 50% -6%, rgba(60,110,80,.22) 0%, transparent 74%)}

/* Cocoa and oxblood, lit low and warm. Foliage pushed toward copper so it
   belongs to the same autumn as the photograph rather than reading green. */
.stage .dm.t-amber img{filter:brightness(.82) saturate(1.05) sepia(.3) hue-rotate(-12deg)}
.stage .dm.t-amber.d-far img{filter:blur(1px) brightness(.72) saturate(.9)
  sepia(.36) hue-rotate(-12deg)}
.stage .dm.t-amber.d-mid img{filter:blur(.4px) brightness(.8) saturate(1)
  sepia(.32) hue-rotate(-12deg)}
.stage .dm.t-amber.d-near img{filter:brightness(.9) saturate(1.08) sepia(.26)
  hue-rotate(-12deg)}
.a-amber{
  background:
    radial-gradient(34% 32% at 92% 90%, rgba(226,150,86,.24) 0%,
                    rgba(226,150,86,.08) 46%, transparent 76%),
    radial-gradient(58% 32% at 22% -4%, rgba(150,80,60,.18) 0%, transparent 72%)}

/* A high-key room. On ivory, decoration has to be lighter and softer than the
   ground to read at all, and the contact shadow that grounds an object at
   night reads as dirt at noon — so it is a whisper rather than a weight. */
.stage .dm.t-bloom img{filter:brightness(1.06) saturate(.9) contrast(.94)}
.stage .dm.t-bloom.d-mid img{filter:blur(.35px) brightness(1.06) saturate(.9) contrast(.94)}
.stage .dm.t-bloom.d-far img{filter:blur(1px) brightness(1.1) saturate(.8) contrast(.9)}
.stage .dm.t-bloom.fx-object.d-near img{filter:brightness(1.02) saturate(.94)
  drop-shadow(0 6px 16px rgba(90,70,110,.22))}
.a-bloom{
  background:
    radial-gradient(46% 40% at 88% 6%, rgba(255,252,255,.5) 0%,
                    rgba(236,226,246,.2) 44%, transparent 76%),
    radial-gradient(60% 34% at 20% -4%, rgba(255,252,255,.34) 0%, transparent 70%)}

/* Candlelit: warm, and never the brightest thing in the frame. A lit taper as
   generated is a studio-white highlight; in a night photograph lit by one
   flame it has to sit under her skin tones, not over them. */
.stage .dm.t-candle.d-near img{filter:brightness(.88) saturate(.9) sepia(.2)
  hue-rotate(-8deg) drop-shadow(0 8px 18px rgba(0,0,0,.6))}
.stage .dm.t-candle.d-mid img{filter:blur(.4px) brightness(.8) saturate(.84)
  sepia(.22) hue-rotate(-8deg)}
.stage .dm.t-candle.fx-growth img{filter:blur(.6px) brightness(.82) saturate(.88)
  sepia(.14)}

/* Solid things. Crisp, and grounded by a contact shadow — the single cue that
   separates an object standing in a scene from a cut-out lying on it. */
.stage .dm.fx-object img{filter:drop-shadow(0 6px 14px rgba(0,0,0,.55))
  drop-shadow(0 1px 2px rgba(0,0,0,.6))}

/* Things that grow in from an edge: solid where they enter, dissolving as they
   reach inward, so the frame looks like it continues past the panel. */
.stage .dm.fx-growth img{-webkit-mask-image:var(--grow);mask-image:var(--grow)}
.grow-tl{--grow:linear-gradient(135deg, #000 34%, rgba(0,0,0,.5) 68%, transparent 96%)}
.grow-tr{--grow:linear-gradient(225deg, #000 34%, rgba(0,0,0,.5) 68%, transparent 96%)}
.grow-bl{--grow:linear-gradient(45deg,  #000 34%, rgba(0,0,0,.5) 68%, transparent 96%)}
.grow-br{--grow:linear-gradient(315deg, #000 34%, rgba(0,0,0,.5) 68%, transparent 96%)}

/* Atmospheric perspective. Distance is softness and a little less color. */
.stage .dm.d-far img{filter:blur(1.1px) saturate(.82) brightness(.92)}
.stage .dm.d-mid img{filter:blur(.35px) saturate(.94)}

/* ---- matching the light to the photograph ----
   The artwork as generated is brighter and more saturated than anything in a
   night scene lit by a single candle. Left alone it reads as a cut-out however
   well it is placed, because its exposure does not belong to the picture. These
   bring it down to the photograph's own values and warm it to champagne. */
.stage .dm.t-champagne.d-mid img{filter:blur(.5px) brightness(.8) saturate(.68)
  sepia(.26) hue-rotate(-6deg)}
.stage .dm.t-champagne.d-far img{filter:blur(1.3px) brightness(.66) saturate(.55)
  sepia(.32) hue-rotate(-6deg)}
.stage .dm.t-champagne.fx-object.d-near img{filter:brightness(.86) saturate(.8) sepia(.12)
  drop-shadow(0 8px 20px rgba(0,0,0,.65)) drop-shadow(0 1px 3px rgba(0,0,0,.7))}
.stage .dm.fx-object.d-far img{filter:blur(1.1px) saturate(.82) drop-shadow(0 5px 12px rgba(0,0,0,.5))}
.stage .dm.fx-object.d-mid img{filter:blur(.3px) drop-shadow(0 6px 14px rgba(0,0,0,.55))}
.stage .dm.fx-object.d-near img{filter:drop-shadow(0 8px 18px rgba(0,0,0,.6))
  drop-shadow(0 1px 2px rgba(0,0,0,.65))}

/* Atmosphere. A wash of the look's own light across the whole panel, which is
   what makes the concepts feel like a room rather than a page with things on
   it. Deliberately weak — it is air, not a filter. */
.air{position:absolute;inset:-10%;
  background:
    radial-gradient(58% 42% at 16% 6%, var(--accent) 0%, transparent 68%),
    radial-gradient(52% 38% at 88% 10%, var(--accent) 0%, transparent 70%),
    radial-gradient(72% 52% at 56% 106%, var(--accent) 0%, transparent 66%);
  opacity:.13;mix-blend-mode:screen}
/* The atmosphere that connects the elements.
   Not a wash over everything — a soft champagne bloom around the primary burst
   that falls away long before it reaches her face or the greeting, so the
   sky, the firework and the crescent read as one lit space rather than three
   separate pictures. Feathered hard: every stop ends in full transparency. */
.stage.glow .air{inset:0;opacity:1;mix-blend-mode:normal;background:none}
/* Candlelight: one warm source low on the right, and the cold plum of the sky
   above it. Not a wash over everything — a room lit by two things. */
.a-candle{
  background:
    radial-gradient(30% 30% at 94% 92%, rgba(232,178,120,.26) 0%,
                    rgba(232,178,120,.08) 46%, transparent 76%),
    radial-gradient(60% 34% at 26% -4%, rgba(150,108,150,.16) 0%, transparent 72%)}
.a-champagne{
  background:
    radial-gradient(38% 44% at 92% 4%, rgba(232,206,158,.30) 0%,
                    rgba(232,206,158,.12) 42%, transparent 76%),
    radial-gradient(52% 30% at 70% -6%, rgba(232,206,158,.16) 0%, transparent 70%),
    radial-gradient(30% 26% at 8% 96%, rgba(232,206,158,.10) 0%, transparent 74%)}

/* The portrait's film is the PORTRAIT's. It used to reach every decorative
   image through the broad `.hero img` rule, tinting artwork that was never
   meant to be tinted and cropping it with the portrait's focal point.
   Every treatment below is scoped under .stage too, so this reset cannot
   out-specify them — which is exactly what it did on the first attempt, and
   why the champagne grade silently did nothing. */
.stage .dm img{filter:none;object-fit:fill;object-position:50% 50%}

/* ------------------------------------------------ Home photos
   The rotation, and where each picture is anchored when it is cropped into a
   wide hero. The focal point is the reason this is a screen and not a list: a
   portrait cropped to a letterbox puts a face wherever the crop lands, and on
   a phone that is often directly under the greeting. */
.homepool{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));
  gap:14px;margin:14px 0 0}
.hp{margin:0;display:flex;flex-direction:column;gap:7px}
.hpshot{position:relative;display:block;aspect-ratio:16/9;border-radius:10px;
  overflow:hidden;background:var(--sunk);border:1px solid var(--line);
  cursor:crosshair;touch-action:none}
.hpshot img{width:100%;height:100%;object-fit:cover;display:block}
/* Where the crop is anchored. Deliberately conspicuous — it is a control, and
   a control you cannot find is not one. */
.hpdot{position:absolute;width:20px;height:20px;margin:-10px 0 0 -10px;padding:0;
  border-radius:50%;border:2px solid #FBF6F1;background:rgba(0,0,0,.35);
  box-shadow:0 0 0 1px rgba(0,0,0,.5),0 2px 8px rgba(0,0,0,.45);cursor:grab}
.hpshot:focus-within .hpdot,.hpdot:focus-visible{outline:2px solid var(--accent);
  outline-offset:2px}
.hp figcaption{display:flex;flex-direction:column;gap:2px;min-width:0}
.hp figcaption b{font-size:13.5px;font-weight:600;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.hp figcaption small{font-size:11.5px;color:var(--muted);font-weight:300}
.hpacts{margin:4px 0 0}

/* The lightbox saying what just happened — it lives in the lightbox's own
   fixed dark room, so it takes that room's ink rather than the page's. */
.lbsay{margin:8px 0 0;font-family:var(--f-s);font-size:12.5px;line-height:1.45;
  color:var(--muted)}
.lbsay.bad{color:var(--stop)}
/* A picture already on Home. */
.lbacts .btn.on{background:rgba(251,246,241,.18);border-color:#FBF6F1;color:#FBF6F1}


/* ------------------------------------------------------ the tools directory

   A directory, not an integrations dashboard: recognize the tool, understand
   its job, open it. Everything here is a name, a sentence and an address —
   nothing on this page ever claims an account is connected.

   Sizing follows the handoff: 1200px measure, 190–210px rail, 12px card gaps,
   16–20px card padding, 44px targets, 16px search text. */
#view > .crumb{font-family:var(--f-s);font-size:12.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--faint);margin:0 0 6px}
#view > .crumb a{color:var(--muted);text-decoration:none}
#view > .crumb a:hover{color:var(--accent)}
/* 16px, which the handoff asks for and iOS enforces: Safari zooms the whole
   page when a focused input is smaller, and the page never zooms back. The
   shared `.find` rule is 15px and is left alone — changing it would move every
   other search box in HQ, including ones already signed off. */
.kitfind .find{font-size:16px}
.kitfind{margin:14px 0 6px}

/* On a small phone the header is the whole first screen.
   Measured at 320x568 — an iPhone SE — the title, subtitle, search, hint,
   category dropdown, shelf and count came to 534px of a 568px viewport, so the
   first tool was a sliver at the bottom. A directory whose first screen shows
   no tools is not a directory yet. The words are the handoff's, unchanged;
   only their size and rhythm move. */
@media (max-width:400px){
  .kittitle{font-size:34px;line-height:1.05;margin:0 0 2px}
  .kitlede{font-size:16px;line-height:1.35;margin:0 0 4px}
  .kitfind{margin:10px 0 4px}
  .kittry{margin:0 0 10px}
  .kitcat{margin:0 0 10px}
  .kith{margin-top:14px}
}
.kittry{margin:0 0 16px}

/* A button that reads as a link, for "clear filters" and "show all tools".
   Inline inside a sentence, so it cannot be a .tb. */
.linkish{background:none;border:0;padding:0;font:inherit;color:var(--accent);
  text-decoration:underline;text-underline-offset:2px;cursor:pointer}
.linkish:hover{color:var(--ink)}
.linkish:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:3px}

.kitwrap{display:block}
.kitrail{display:none}
.kitcat{width:100%;margin:0 0 14px}

.kith{font-family:var(--f-l);font-size:19px;font-weight:400;line-height:1.2;
  display:flex;align-items:center;gap:8px;margin:22px 0 2px;color:var(--ink)}
.kith svg{color:var(--mauve);flex:none}
.kitwhat{margin:0 0 10px}
.kitcount{margin:4px 0 10px}
/* One quiet line, not a tall dashed box.
   An empty shelf is the state Brooklyn sees on her first visit, and as a
   bordered panel it spent about 150px saying that nothing is there — which at
   320x568 put every single tool below the fold. It says the same sentence. */
.kitempty{margin:2px 0 2px;font-style:italic}
/* The shelf heading and the search hint carry the header; neither needs the
   full 22px rhythm above a phone's first card. */
.kitfav{margin-top:2px}
.kitsec:first-child .kith{margin-top:14px}

.kitgrid{display:grid;grid-template-columns:1fr;gap:12px}

/* One card. The logo zone is WIDE rather than square: DocuSign, Webfile and
   Bandsintown are wordmarks, and squeezing a lockup into an icon slot is how a
   real logo turns into an unofficial one. */
.kitcard{display:grid;grid-template-columns:auto 1fr auto;gap:14px;align-items:start;
  border:1px solid var(--line);border-radius:14px;padding:16px;background:var(--raised)}
.kitcard:hover{border-color:var(--firm)}
.kitlogo{width:56px;min-width:56px;height:44px;display:flex;align-items:center;
  justify-content:center;border-radius:8px;overflow:hidden}
.kitlogo img{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;
  display:block}
/* Plates, never CSS recoloring. A white BMI wordmark needs something dark
   behind it; a dark mark on a transparent background needs something light.
   Inverting the file itself would be inventing a logo variant. */
.kitlogo.onDark{background:#231A28;padding:5px 6px}
.kitlogo.onLight{background:#FFFFFF;padding:5px 6px}
/* An app icon already carries its own background and corner radius. */
.kitlogo.app{border-radius:11px;background:#fff}
.kitlogo.app img{width:100%;height:100%}

/* After dark, a mark drawn in black needs something behind it.
   Feature.fm is #000000 on transparent, DocuSign is a black wordmark with two
   colored glyphs: on the near-black page they all but disappear. This is a
   PLATE, not a recoloring — the artwork's own bytes are untouched and its
   colors and geometry are exactly what the provider published. Marks that
   already carry a background (`.app`) or are white-on-dark by design
   (`.onDark`) are left alone, because giving those a light plate is how a white
   wordmark becomes invisible in the other direction. */
html[data-theme="dark"] .kitlogo:not(.app):not(.onDark){
  background:#F4EFEA;padding:5px 6px}
html[data-theme="dark"] .kitcard[data-wide] .kitlogo:not(.app):not(.onDark){
  padding:5px 8px}

.kitbody{min-width:0}
.kitname{display:inline-flex;align-items:center;gap:6px;font-family:var(--f-b);
  font-size:16px;font-weight:500;color:var(--ink);text-decoration:none;
  line-height:1.25;
  /* `anywhere` broke "Feature.fm" into "Featur / e.fm" and "Musixmatch" into
     "Musix / match". A product name split mid-word is the clipped name the
     handoff forbids, wearing a different hat. Break at spaces only. */
  overflow-wrap:break-word;hyphens:none}
.kitname:hover{color:var(--accent)}
.kitname:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:4px}
.kitout{color:var(--faint);flex:none;line-height:0}
/* The one card that is not a link out. Same weight and size as the others so
   the directory reads evenly, but no external glyph, because nothing leaves. */
.kitname.kitin{background:none;border:0;padding:0;cursor:pointer;text-align:left}
.kitname:hover .kitout{color:var(--accent)}
.kitsay{font-family:var(--f-s);font-size:14px;line-height:1.5;color:var(--muted);
  margin:4px 0 0}
/* 44px, not 34px behind a `pointer:coarse` query.
   The media-query version left the button at 34px anywhere the pointer is not
   reported as coarse — which includes a real iPad in some modes and every
   headless check — so the target was short exactly where nobody would notice.
   A tap target is a tap target; the couple of extra pixels cost nothing. */
.kitprep{margin:9px 0 0;background:none;border:1px solid var(--firm);border-radius:8px;
  color:var(--muted);font-family:var(--f-s);font-size:13px;padding:7px 14px;
  min-height:44px;cursor:pointer}
.kitprep:hover{border-color:var(--accent);color:var(--accent)}

.kitstar{width:44px;min-width:44px;height:44px;display:grid;place-items:center;
  border:0;border-radius:10px;background:none;color:var(--faint);cursor:pointer;
  margin:-4px -4px 0 0}
.kitstar:hover{color:var(--mauve)}
.kitstar[aria-pressed="true"]{color:var(--mauve)}
.kitstar:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.kitstar[disabled]{opacity:.5;cursor:default}

/* Editing stays beside each shortcut, with the same touch-sized controls as Media. */
.kitheading{display:flex;flex-wrap:wrap;align-items:center;gap:10px 18px;max-width:1200px}
.kitheading .kittitle{margin:0;flex:1 1 auto}
.kitmanage{display:flex;align-items:center;gap:6px}
.kitmanage[hidden]{display:none}
.kitmanage .tb,.kitsheet .tb{display:inline-flex;align-items:center;justify-content:center;gap:7px;min-height:44px}
.kiticon{display:inline-grid;place-items:center;width:44px;min-width:44px;height:44px;
  padding:0;border:0;border-radius:10px;background:none;color:var(--muted);cursor:pointer}
.kiticon:hover{background:var(--sunk);color:var(--accent)}
.kiticon:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.kitcardacts{display:flex;flex-direction:column;align-items:center;margin:-4px -4px 0 0}
.kitcardacts .kitstar{margin:0}
.kitcard[data-wide] .kitcardacts{grid-area:star;flex-direction:row}
.kitcardacts .kiticon{color:var(--faint)}
.kitlogo:has(>svg){color:var(--accent);background:var(--sunk)}
.kitsheet .sheetpanel{padding:0;max-height:90vh;max-height:90dvh;display:flex;flex-direction:column;overflow:hidden}
.kitsheet .sheet-head{padding:6px 14px;margin:0;border-bottom:1px solid var(--line);flex:none}
.kitsheet .sheetpanel > .hint{margin:12px 20px 0}
.kitform{overflow-y:auto;padding:12px 20px 0;overscroll-behavior:contain}
.kitform label{display:block;font-family:var(--f-s);font-size:14px;color:var(--ink);margin:16px 0 6px}
.kitform > label:first-child{margin-top:0}
.kitform .in{width:100%;font-size:16px;min-height:44px}
.kitform textarea{resize:vertical;line-height:1.5}
.kitassist{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:10px}
.kitassist .hint{margin:0;flex:1 1 180px}
.kitsuggestion{margin-top:12px;padding:14px;border:1px solid var(--line);border-radius:12px;background:var(--sunk)}
.kitsuggestion p{margin:0 0 10px;overflow-wrap:anywhere}
.kitsuggestion p:last-child{margin-bottom:0}
.kitsuggestion .jayi-said{display:flex;align-items:center;gap:7px;color:var(--accent)}
.kitfieldpair{display:grid;grid-template-columns:minmax(0,1fr);gap:0 16px}
.kitremove{margin-top:22px;border-top:1px solid var(--line);padding-top:14px}
.kitremove p{font-size:14px;line-height:1.5}
.kitremove > button{color:var(--muted)}
.kitremove .danger{color:var(--accent)}
#kit-hidden-list{overflow-y:auto;overscroll-behavior:contain;padding:8px 20px 24px}
.kithiddenrow{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:12px;align-items:center;
  padding:16px 0;border-bottom:1px solid var(--line)}
.kithiddenrow p{margin:4px 0 0;overflow-wrap:anywhere}
#kit-hidden-error{padding:0 20px}
@media(min-width:600px){.kitfieldpair{grid-template-columns:1fr 1fr}}
@media(max-width:400px){
  .kitheading{gap:6px}
  .kitheading .kittitle{font-size:30px}
  .kitmanage .tb{padding:0 9px;font-size:13px}
  .kitmanage{gap:0}
  .kitcard{gap:10px;padding:12px}
  .kitlogo{width:44px;min-width:44px}
}

/* A wordmark needs width, not a square. Measured from the artwork at build
   time (scripts/build_tools_catalog.mjs) rather than listed by hand: Webfile is
   8.75:1, Musixmatch 5.94:1, DocuSign 4.67:1. The handoff asks for at least
   52px for DocuSign and roughly 180–220px for Webfile; this gives every wide
   mark a 96px slot and lets the widest ones run to the full card on a phone,
   which is the only place there is room for 8.75:1 to be legible. */
/* A wide mark gets its own row rather than a wider column.
   Widening the left column to 96px worked for the logo and ruined the card:
   measured at the 1200px layout, a wide card's text column fell to 62px and
   the description wrapped one word per line. The wordmark sits above the name
   instead, so it can run to 200px — the handoff asks roughly 180–220px for
   Webfile at 8.75:1 — while the name and sentence get the whole card. */
.kitcard[data-wide]{grid-template-columns:minmax(0,1fr) auto;
  grid-template-areas:"logo star" "body body";row-gap:10px}
.kitcard[data-wide] .kitlogo{grid-area:logo;width:auto;min-width:0;max-width:200px;
  height:38px;justify-content:flex-start}
.kitcard[data-wide] .kitlogo img{max-height:38px}
.kitcard[data-wide] .kitstar{grid-area:star}
.kitcard[data-wide] .kitbody{grid-area:body}
/* A plate around a left-aligned wordmark needs to hug it, not stretch. */
.kitcard[data-wide] .kitlogo.onDark,
.kitcard[data-wide] .kitlogo.onLight{padding:5px 8px}

@media (min-width:560px){
  /* Two up as soon as a card can hold its sentence without wrapping to four
     lines. Favorites stay a 2-column shelf at this width too. */
  .kitgrid{grid-template-columns:repeat(2,minmax(240px,1fr))}
}

@media (min-width:900px){
  /* The rail replaces the dropdown. Nothing is duplicated: one of the two is
     always display:none, so there is never a second control reporting a
     different category from the one in the URL. */
  .kitwrap{display:grid;grid-template-columns:200px minmax(0,1fr);gap:28px;
    align-items:start;max-width:1200px}
  .kitcat{display:none}
  .kitrail{display:flex;flex-direction:column;gap:2px;position:sticky;top:96px}
  .kitcat1{display:flex;align-items:center;gap:9px;width:100%;text-align:left;
    background:none;border:0;border-radius:9px;padding:9px 10px;min-height:40px;
    cursor:pointer;color:var(--muted);font-family:var(--f-s);font-size:14px}
  .kitcat1 svg{color:var(--faint);flex:none}
  .kitcat1 span{flex:1;min-width:0}
  .kitcat1 b{font-weight:400;font-variant-numeric:tabular-nums;color:var(--faint);
    font-size:12.5px}
  .kitcat1:hover{background:var(--sunk);color:var(--ink)}
  .kitcat1.on{background:var(--tint);color:var(--accent)}
  .kitcat1.on svg, .kitcat1.on b{color:var(--accent)}
  .kitsec:first-child .kith{margin-top:0}
}

/* Two columns, and not three.
   The handoff allows a third "only when each card remains at least 240px
   wide", and inside the 1200px measure minus a 200px rail a third column
   leaves 316px per card — which passes that floor and still fails the rule it
   serves. A 316px card spends 56px on the logo and 44px on the star, leaving
   the name about 188px: "Feature.fm" wrapped mid-word at exactly that width.
   240px is a floor for the CARD, not for the name inside it. So: two. */



/* ================================================================ upcoming releases
   Home's quiet reminder of what is coming. Deliberately not a second hero: the
   large countdown lives on the song and the release page, and repeating it here
   would make the calmest screen in the app the loudest.

   One link per release, cover included — Jay's decision is that the cover opens
   the full release page, and one control is how a cover and a row reach the
   same place without a button nested inside a link. */
.urelh{display:flex;align-items:baseline;gap:12px;font-family:var(--f-l);font-size:19px;
  color:var(--ink);margin:30px 0 10px}
.urelall{margin-left:auto;font-family:var(--f-s);font-size:13.5px;color:var(--muted);
  text-decoration:none;white-space:nowrap}
.urelall:hover{color:var(--accent);text-decoration:underline}

.urels{display:flex;flex-direction:column}
.urel{display:flex;align-items:center;gap:13px;padding:11px 4px;min-height:64px;
  border-top:1px solid var(--line);text-decoration:none;color:inherit}
.urels .urel:last-child{border-bottom:1px solid var(--line)}
.urel:hover{background:var(--tint)}
.urel:focus-visible{outline:2px solid var(--focus,var(--accent));outline-offset:-2px;
  border-radius:8px}

/* A stable crop, so a portrait cover and a square one sit on the same line. */
.urelart{flex:none;width:58px;height:58px;border-radius:8px;overflow:hidden;
  background:var(--raised);display:flex;align-items:center;justify-content:center}
.urelart img{width:100%;height:100%;object-fit:cover;display:block}
.urelart.none{color:var(--faint)}
.urelart.none img{display:none}

.ureltx{flex:1;min-width:0}
.ureltx b{display:block;font-family:var(--f-l);font-weight:400;font-size:18px;
  line-height:1.25;color:var(--ink);overflow-wrap:anywhere}
.ureltx small{display:block;font-family:var(--f-s);font-size:13px;color:var(--muted);
  line-height:1.45;margin-top:2px}

/* Amber says "look at this", not "this is broken". Never the only signal: the
   same fact is in the row's accessible name and in the title attribute. */
/* Amber is filled with a halo; green is a ring. The difference is a shape, not
   only a hue, so the two do not depend on color vision to tell apart — and
   each carries its own words in the title and the accessible name. */
.urelflag{flex:none;width:9px;height:9px;border-radius:50%}

/* A past-date release awaiting her word (Round 5, Phase 4, Oct 4, 2026): the
   open area is the link with its chevron; "It's out" sits beside it. */
.urelconf{gap:10px}
.urelopen{flex:1;min-width:0;display:flex;align-items:center;gap:13px;color:inherit;text-decoration:none;
  min-height:44px}
.urelout{flex:none;min-height:44px}
.urelflag.late{background:var(--warn);box-shadow:0 0 0 3px rgba(var(--amber),.16)}
.urelflag.ontrack{background:transparent;border:2px solid var(--good)}


/* ================================================================ release planning admin
   The team's timeline. Days are the stored unit and the only number shown,
   because "6" meaning weeks in one field and days in the next is exactly the
   ambiguity that puts a delivery three weeks late. Weeks are an aside and a
   shortcut, never a second input competing with the first. */
.plrules{display:flex;flex-direction:column;margin:14px 0 0}
.plrule{padding:16px 2px;border-top:1px solid var(--line)}
.plrules .plrule:last-child{border-bottom:1px solid var(--line)}
.pltx b{display:block;font-family:var(--f-l);font-weight:400;font-size:19px;
  line-height:1.25;color:var(--ink)}
.pltx small{display:block;font-family:var(--f-s);font-size:13px;color:var(--muted);
  line-height:1.5;margin-top:2px}
.plset{display:flex;align-items:center;flex-wrap:wrap;gap:9px 12px;margin:11px 0 0}
.plnum{flex:none}
.plnum .in{width:88px;min-height:44px;text-align:center;
  font-variant-numeric:lining-nums tabular-nums}
.plunit{font-family:var(--f-s);font-size:14px;color:var(--muted)}
.plquick{display:inline-flex;gap:6px;flex-wrap:wrap;margin-left:auto}
.plsrc{margin:9px 0 0;font-family:var(--f-s);font-size:12.5px;color:var(--faint);
  display:flex;align-items:center;gap:6px}

@media (max-width:520px){
  .plquick{margin-left:0;width:100%}
}

/* The Releases filter. A pressed chip and a truthful count, so "Upcoming 3"
   is a fact rather than a heading that implies the list was narrowed. */
.relfilter{display:flex;gap:7px;flex-wrap:wrap;margin:14px 0 4px}

/* ---------------------------------------------------------------- people
   What a contact is attached to, said as a list rather than a warning. The
   one with a sign-in is marked, because that is a different kind of link and
   the sentence next to it is the one people miss. */
.deplist{list-style:none;margin:10px 0;padding:0;display:flex;flex-direction:column;
  gap:9px}
.deplist li{display:flex;flex-direction:column;gap:2px;padding-left:12px;
  border-left:2px solid var(--line)}
.deplist li b{font-family:var(--f-s);font-size:14px;font-weight:600;color:var(--ink)}
.deplist li span{font-family:var(--f-s);font-size:13px;color:var(--muted);
  line-height:1.5;overflow-wrap:anywhere}
.deplist li.dep-access{border-left-color:var(--mauve)}

.pacts{margin:30px 0 0;padding-top:18px;border-top:1px solid var(--line);
  display:flex;flex-direction:column;gap:10px;align-items:flex-start}
.pacts .act{width:100%}
.row.person.archived .ti{color:var(--muted)}
.row.person.archived .avatar{opacity:.6}

/* Contacts that might be one contact. Offered, never acted on. */
.dupbar{margin:18px 0 6px;padding:14px;border:1px solid var(--firm);border-radius:12px;
  background:var(--tint)}
.dupt{font-family:var(--f-s);font-size:14px;font-weight:600;color:var(--ink);margin:0}
.duplist{display:flex;flex-direction:column;gap:7px;margin:10px 0 8px}
.dupp{display:flex;flex-direction:column;gap:2px;text-align:left;width:100%;
  padding:9px 11px;border:1px solid var(--line);border-radius:9px;
  background:var(--paper,transparent);cursor:pointer;color:inherit}
.dupp:hover{border-color:var(--firm)}
.dupp span{font-family:var(--f-s);font-size:14px;color:var(--ink)}
.dupp small{font-family:var(--f-s);font-size:12px;color:var(--muted)}

/* The merge comparison. Stacked on a phone, two columns where there is room. */
.mgpair{display:grid;grid-template-columns:1fr;gap:10px;margin:6px 0 2px}
.mgcol{padding:11px 13px;border:1px solid var(--line);border-radius:10px}
.mgcol.mgkeep{border-color:var(--firm);background:var(--tint)}
.mglab{font-family:var(--f-s);font-size:11px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--faint);margin:0}
.mgname{font-family:var(--f-l);font-size:21px;line-height:1.2;color:var(--ink);
  margin:3px 0 0;overflow-wrap:anywhere}
.mgsub{font-family:var(--f-s);font-size:13px;color:var(--muted);margin:3px 0 0}
.mgfields{display:flex;flex-direction:column;gap:14px;margin:14px 0 0}
.mgrow{padding-top:12px;border-top:1px solid var(--line)}
.mgf{font-family:var(--f-s);font-size:13px;font-weight:600;color:var(--ink);margin:0 0 7px}
.mgopts{display:flex;flex-wrap:wrap;gap:7px}
.mgopts .choice{flex-direction:column;align-items:flex-start;gap:1px;
  max-width:100%;overflow-wrap:anywhere;text-align:left;white-space:normal;padding-top:6px;padding-bottom:6px}
.mgconflict .mgf{color:var(--mauve)}
@media (min-width:700px){
  .mgpair{grid-template-columns:1fr 1fr}
}

/* ------------------------------------------------------- review imports
   Five queues and a count each, because "what is left" and "what I dealt
   with" are different questions. Horizontally scrollable on a phone rather
   than wrapping into a wall. */
.impq{margin:16px 0 8px;padding:4px 0}

.impfil{display:flex;flex-wrap:wrap;align-items:center;gap:9px;margin:14px 0 6px}
.impsel{flex:1 1 150px;min-width:0}
.impsel .in{width:100%}
.impcount{flex:1 1 100%;font-family:var(--f-s);font-size:12px;color:var(--faint);
  margin:0;font-variant-numeric:tabular-nums}

.impitems{display:flex;flex-direction:column;gap:14px;margin:16px 0 0}
.impc{padding:15px;border:1px solid var(--line);border-radius:13px;
  display:flex;flex-direction:column;gap:9px}
.impc.impdone{opacity:.72}
.impch{display:flex;flex-direction:column;gap:2px}
.impct{margin:0;font-family:var(--f-s);font-size:15px;color:var(--ink);
  display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
/* A filename is often longer than the card. It stays readable and stays
   inside, rather than pushing the page sideways. */
.impct b{font-weight:600;overflow-wrap:anywhere;min-width:0}
.impcs{margin:0;font-family:var(--f-s);font-size:13px;color:var(--muted)}
.impprev{border-radius:9px;overflow:hidden;background:var(--raised);max-height:190px;
  display:flex;align-items:center;justify-content:center}
.impprev img{max-width:100%;max-height:190px;object-fit:contain;display:block}
.impprev audio{width:100%}
.impprev.nopreview{padding:16px}
.impwhy{display:flex;flex-direction:column;gap:2px}
.impe{margin:0;font-family:var(--f-s);font-size:13px;color:var(--soft);line-height:1.55}
.impsrc{margin:0;font-family:var(--f-s);font-size:12px;color:var(--faint);
  overflow-wrap:anywhere}
.impcmp{display:grid;grid-template-columns:1fr;gap:9px}
.impcmp>div{padding:9px 11px;border:1px solid var(--line);border-radius:9px;min-width:0}
.impk{margin:0;font-family:var(--f-s);font-size:11px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--faint)}
.impv{margin:2px 0 0;font-family:var(--f-s);font-size:15px;color:var(--ink);
  overflow-wrap:anywhere}
.impv .none{color:var(--faint)}
.impfile{margin:0;display:flex;gap:9px;align-items:baseline;flex-wrap:wrap}
.impname{font-family:var(--f-b);font-size:13px;color:var(--soft);overflow-wrap:anywhere;
  min-width:0}
.impbytes{font-family:var(--f-s);font-size:12px;color:var(--faint);
  font-variant-numeric:tabular-nums;flex:none}
.impprog{margin:0;font-family:var(--f-s);font-size:12px;color:var(--muted)}
.impdid{margin:0;font-family:var(--f-s);font-size:13px;color:var(--ink)}
.impsay{margin:0;font-family:var(--f-s);font-size:13px;color:var(--muted)}
.impsay.bad{color:var(--stop)}
/* Bring in files (R7): the run's bar and words, the not-brought-in list, and
   each found file's state in the delivery tones (tones.js), as the drawer. */
.ib-prog{margin:12px 0 4px;display:grid;gap:6px}
.ib-words{margin:0;font-family:var(--f-s);font-size:13px;color:var(--ink)}
.ib-prog .hint{margin:0}
.ib-failed{margin:16px 0}
.ib-failed .slab{color:var(--stop)}
.ib-failed .deplist{margin-bottom:10px}
.tag.state{background:color-mix(in srgb, var(--stage-on) 15%, transparent);color:var(--stage-on)}
.impacts{display:flex;flex-wrap:wrap;gap:8px;margin-top:2px}
.impacts .act,.impacts .tb{min-height:44px}
.imppage{display:flex;align-items:center;justify-content:center;gap:14px;margin:20px 0 0;
  font-family:var(--f-s);font-size:13px;color:var(--muted)}
@media (min-width:700px){
  .impcmp{grid-template-columns:1fr 1fr}
}

/* The resolver. One answer per row, and the typing survives a failed save. */
.rsopts{display:flex;flex-direction:column;gap:7px;margin:12px 0 0}
.rsopt{display:flex;flex-direction:column;align-items:flex-start;gap:1px;
  padding:11px 13px;border:1px solid var(--line);border-radius:10px;
  background:transparent;cursor:pointer;text-align:left;color:inherit;min-height:44px}
.rsopt b{font-family:var(--f-s);font-size:14px;font-weight:600;color:var(--ink)}
.rsopt small{font-family:var(--f-s);font-size:12px;color:var(--muted);
  overflow-wrap:anywhere}
.rsopt.on{border-color:var(--accent);background:var(--tint)}
.rsentry{display:block;margin:11px 0 0}
.rsmore{margin:14px 0 0}
.rsmore summary{font-family:var(--f-s);font-size:13px;color:var(--muted);cursor:pointer;
  padding:6px 0;min-height:32px}
.rsshares{margin:12px 0 0}
.rsrow{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin:8px 0}
.rsrow select{flex:1 1 150px;min-width:0}
.rspc{width:74px;flex:none;text-align:right}
.rspcs{font-family:var(--f-s);font-size:13px;color:var(--muted)}
.rsrow .drop{flex:none}
.rstotal{margin:8px 0 0;font-family:var(--f-s);font-size:13px;color:var(--muted);
  font-variant-numeric:tabular-nums;text-align:right}
.fudup{padding:12px 13px;border:1px solid var(--firm);border-radius:11px;
  background:var(--tint);margin:6px 0}

/* ------------------------------------------------------------------ Jay-I
   One mark, everywhere she is helped.

   Two colors and both are tokens: the J and the i take the color of the text
   they sit beside, and the spark takes her accent. Nothing about Brooklyn is in
   the shape, so another artist's House changes tokens rather than artwork.

   The source file this came from also ships a cobalt-and-citron badge. That is
   IndyHouse's own color, and putting it inside her House would be another
   company's brand on her screen. */
.jayi{display:inline-block;vertical-align:-0.18em;flex:none;color:var(--ji-ink,inherit)}
/* Ji in a sentence or a label (app/ji-mark.js): the mark at the size of the
   words around it, sitting on their line, never breaking from the next word. */
.ji-mark{display:inline-block;white-space:nowrap;line-height:1}
.ji-mark .jayi{width:1.15em;height:1.15em;vertical-align:-0.2em}
.jayi .jayi-spark{fill:var(--ji-spark,var(--mauve));stroke:var(--ji-edge,none);stroke-width:1;stroke-linejoin:round}
/* Only IndyHouse's look sets the --ji-* colors. On a filled, pressed or
   disabled control the mark takes the control's own ink, in every look. */
:is(.btn.primary,.tb.solid,.mbtn.primary,.wr-btn-primary,.ih-action.ih-primary,.sl-btn.keep,
    .ok.solid,.act.solid,.rc-primary,.choice[aria-pressed="true"],:disabled,[disabled]) .jayi{
  --ji-ink:initial;--ji-spark:initial;--ji-edge:initial}
/* On a filled control the spark would vanish into the fill, so it borrows the
   same ink as the rest of the mark and keeps its shape instead of its color. */
.act.solid .jayi .jayi-spark{fill:currentColor;opacity:.75}

.jayi-act{display:inline-flex;align-items:center;gap:7px;min-height:44px}
.jayi-act span{line-height:1}

/* Working. A slow pulse on the spark only: the mark stays legible and still
   says what it is, which a spinner replacing it would not. Meaning is never
   carried by the animation alone — the words beside it change too. */
@keyframes jayi-think{0%,100%{opacity:.35;transform:scale(.86)}50%{opacity:1;transform:scale(1.06)}}
.jayi-busy .jayi-spark{transform-origin:17.7px 6.1px;animation:jayi-think 1.4s ease-in-out infinite}
@media (prefers-reduced-motion:reduce){
  .jayi-busy .jayi-spark{animation:none;opacity:.9}
}

/* A line Jay-I wrote or proposed, marked as such. */
.jayi-by{display:flex;align-items:flex-start;gap:7px;font-family:var(--f-s);
  font-size:12px;color:var(--faint);margin:6px 0 0}
.jayi-by .jayi{margin-top:1px;color:var(--ji-ink,var(--mauve))}

/* Small sizes have to stay recognizable: at 15px the spark is four points and
   three pixels, so it keeps a touch more weight than the J beside it. */
.jayi[width="15"] .jayi-spark,
.jayi[width="14"] .jayi-spark{transform:scale(1.08);transform-origin:17.7px 6.1px}

/* ----------------------------------------------------- where files come from
   A connection and an authorization read as two different things because they
   are: the row says what has been read, not just what is plugged in. */
.srcrow{display:flex;flex-wrap:wrap;gap:12px;align-items:flex-start;
  padding:15px 2px;border-top:1px solid var(--line)}
.rows .srcrow:last-child{border-bottom:1px solid var(--line)}
.srctx{flex:1 1 220px;min-width:0}
/* Its two lines. The row reused .ts, which is also the checklist step's class
   (a flex row with a rule above it), so First's "Which take goes" rows drew a
   line between a song and its take, in the system's blue (Simulator, Sep 29). */
.srctx .ti{margin:0;font-size:15px;line-height:1.3;color:var(--ink)}
.srctx .ts{display:block;padding:0;border-top:0;margin:2px 0 0;
  font:400 12.5px/1.4 var(--f-s);color:var(--muted)}
.srcacts{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.srcacts .tb,.srcacts .act{min-height:44px}

/* A row with more than one take is the tappable-row-plus-chevron pattern
   (§10): the whole row opens the take picker, not a separate "Change" link. */
.srcrow-drop{width:100%;border:0;border-top:1px solid var(--line);background:none;
  text-align:left;cursor:pointer;align-items:center;min-height:44px;color:inherit;font:inherit}
.srcrow-drop:hover{background:var(--sunk)}
.srcrow-drop .mdrop-chev{align-self:center}

/* One level at a time. Walking the tree to show it would be the full-drive
   read this is built to avoid, done under a friendlier name. */
.fstrail{font-family:var(--f-s);font-size:12px;color:var(--faint);margin:10px 0 2px;
  overflow-wrap:anywhere}
.fsrow{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:10px 2px;border-top:1px solid var(--line)}
.fsname{flex:1 1 160px;min-width:0;text-align:left;background:none;border:0;
  padding:0;color:var(--ink);font-family:var(--f-s);font-size:15px;cursor:pointer;
  overflow-wrap:anywhere;min-height:44px}
.fspick{display:flex;align-items:center;gap:7px;font-family:var(--f-s);
  font-size:13px;color:var(--muted);cursor:pointer;flex:none;min-height:44px}

/* --------------------------------------------------------- release steps
   A row that can say six things instead of one. The tick stays for the common
   case; everything else is behind its own control rather than a second list. */
.ev.going .nm2{color:var(--ink)}
.ev.off{opacity:.6}
.ev.off .nm2{text-decoration:line-through;text-decoration-color:var(--faint)}
.ev.bad .nm2{color:var(--mauve)}
.evstate{display:block;font-family:var(--f-s);font-size:12px;color:var(--muted);
  margin-top:2px;overflow-wrap:anywhere}
.evown,.evdue,.evmore{background:none;border:0;padding:0 4px;color:var(--muted);
  font-family:var(--f-s);font-size:12px;cursor:pointer;min-height:44px;
  display:inline-flex;align-items:center;white-space:nowrap}
.evown{max-width:8ch;overflow:hidden;text-overflow:ellipsis;display:inline-block;
  line-height:44px;text-align:right}
/* On a narrow phone the name gets the whole first line and the three controls
   sit under it, rather than squeezing the title to two characters. */
@media (max-width:400px){
  .ev{grid-template-columns:auto minmax(0,1fr) auto auto}
  .ev .body{grid-column:2 / -1}
  .evown{grid-column:2;justify-self:start;text-align:left;max-width:14ch}
  .evdue{grid-column:3}
  .evmore{grid-column:4}
}
.evown .none{color:var(--faint)}
.evdue.set{color:var(--ink);text-decoration:underline;text-decoration-style:dotted;
  text-underline-offset:3px}
.evmore{letter-spacing:.08em}
.evown:focus-visible,.evdue:focus-visible,.evmore:focus-visible{
  outline:2px solid var(--focus,var(--accent));outline-offset:2px;border-radius:6px}

/* Preferences: what this House has decided, not how it looks to you. */
.prefsec{margin:26px 0 0}
.prefrow{margin:14px 0}
/* The House's web address, its Copy beside the label so the address keeps the
   whole line (Preferences, E5). */
.pf-web .prefl{display:flex;align-items:center;justify-content:space-between;gap:12px}
.pf-web .tb{flex:none;text-transform:none;letter-spacing:0}
.pf-web .pf-addr{overflow-wrap:anywhere}
.prefl{display:block;font-family:var(--f-s);font-size:12px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--faint);margin:0 0 5px}
.prefrow .in{width:100%}
.prefscopes{margin:10px 0 0}
/* A name, what it means underneath, and a switch on the right. The same shape
   as .srow, which is what this was written against and never given. */
.nmrow{display:grid;grid-template-columns:1fr auto;gap:14px;align-items:center;
  padding:13px 0;border-bottom:1px solid var(--line)}
.nmrow:last-child{border-bottom:0}
.nmrow .nm{font-size:15px;color:var(--ink);margin:0}
.nmrow .nm span{display:block;font-size:12.5px;color:var(--muted);font-weight:300;
  line-height:1.4;margin-top:2px}
/* An extra switched off in Preferences but already on for this release. The
   record of what was actually made does not vanish because a default changed. */
.scopekept{display:block;flex-basis:100%;font-family:var(--f-s);font-size:12px;
  color:var(--faint);margin-top:4px}

/* Two jobs inside one provider's card.
   They were two cards, each opening with the same Spotify wordmark, which read
   as two Spotifys rather than as two things she can do with one. A rule and a
   little air separate them; neither is required and doing one says nothing
   about the other. */
.toolpart{margin:18px 0 0;padding-top:16px;border-top:1px solid var(--line)}
.toolpart:first-of-type{margin-top:14px}
.toolparth{display:flex;align-items:baseline;justify-content:space-between;
  gap:10px;flex-wrap:wrap;margin:0 0 3px}
.toolparth b{font-family:var(--f-l);font-weight:400;font-size:19px;color:var(--ink)}

/* A project that lives somewhere else opens there; what HQ holds is the
   second, quieter action. Landing on HQ's page about a production and tapping
   again to reach the production is two taps to do nothing. */
.projside{display:block;margin:6px 2px 0;font-family:var(--f-s);font-size:12px;
  color:var(--muted);text-decoration:none;min-height:34px;line-height:34px}
.projside:hover{color:var(--ink)}

/* The guided steps. A rail she can jump around in, not a wizard that locks
   step four until step three is finished — a video gets started from a location
   somebody found before anybody has written a word of story. */
.steprail{display:flex;gap:6px;overflow-x:auto;margin:16px 0 6px;padding-bottom:4px;
  -webkit-overflow-scrolling:touch;scrollbar-width:none}
.steprail::-webkit-scrollbar{display:none}
.stepb{flex:none;display:flex;align-items:center;gap:7px;padding:8px 13px;
  border:1px solid var(--line);border-radius:999px;background:transparent;
  font-family:var(--f-s);font-size:13px;color:var(--muted);cursor:pointer;
  white-space:nowrap;min-height:40px}
.stepb.on{border-color:var(--accent);color:var(--ink);background:var(--tint)}
.stepb .tick2{width:7px;height:7px;border-radius:50%;background:var(--good);flex:none}
.stepbody{margin:16px 0 0}
.prlinks{display:flex;flex-direction:column;gap:8px;margin:12px 0}
.prlinkrow{display:flex;align-items:center;gap:9px;padding:10px 12px;
  border:1px solid var(--line);border-radius:10px;min-width:0}
.prlinkrow a{flex:1 1 auto;min-width:0;overflow-wrap:anywhere;color:var(--ink);
  font-family:var(--f-s);font-size:14px}
.prlinkrow .tag{flex:none}

/* ------------------------------------------------- the guided conversation
   One question at a time. A wall of eight is a form, and she came here to
   talk about her song. */
.qcard{margin:18px 0;padding:18px 16px;border:1px solid var(--firm);
  border-radius:14px;background:var(--tint)}
.qcount{margin:0;font-family:var(--f-s);font-size:11px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--faint)}
.qask{margin:6px 0 12px;font-family:var(--f-l);font-weight:400;font-size:22px;
  line-height:1.25;color:var(--ink);text-wrap:balance}
.qown{display:block;margin:10px 0 0}
.qown .in{width:100%}
.qskip{margin:12px 0 0}
/* Her lyric stays on screen while she answers about it. Asking what she sees
   and hiding the words is asking her to remember. */
.qlyric{margin:0 0 14px;padding:12px 14px;border-radius:10px;background:var(--raised);
  font-family:var(--f-s);font-size:15px;line-height:1.6;color:var(--soft);
  white-space:pre-wrap;overflow-wrap:anywhere}
.qlyric.small{font-size:13px;padding:9px 11px;margin:6px 0 8px}

/* The direction. A proposal with a version on it, never a decision. */
.dircard{margin:18px 0;padding:18px 16px;border:1px solid var(--line);border-radius:14px}
.dirhead{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin:0}
.dirhead b{font-family:var(--f-l);font-weight:400;font-size:21px;color:var(--ink)}
.dirfields{margin:14px 0 0}
.dirfields .in{width:100%}
.swatches{display:flex;flex-wrap:wrap;gap:10px;margin:14px 0}
.swatch{display:flex;flex-direction:column;align-items:center;gap:5px;width:62px}
.swatch i{display:block;width:46px;height:46px;border-radius:10px;
  border:1px solid var(--line)}
.swatch em{font-style:normal;font-family:var(--f-s);font-size:11px;color:var(--muted);
  text-align:center;line-height:1.3;overflow-wrap:anywhere}

/* The board. Cards she can move, not a table she has to read. */
.scenes{display:flex;flex-direction:column;gap:12px;margin:12px 0}
.scene{padding:14px;border:1px solid var(--line);border-radius:13px}
.scene.ok{border-color:var(--firm);background:var(--tint)}
.sceneh{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  flex-wrap:wrap;margin:0 0 6px}
.scenen{margin:0;font-family:var(--f-s);font-size:15px;font-weight:600;color:var(--ink);
  overflow-wrap:anywhere;min-width:0}
.scenew{margin:0;font-family:var(--f-s);font-size:14px;color:var(--soft);line-height:1.55}
.sceneacts{display:flex;gap:7px;flex-wrap:wrap;margin:10px 0 0}
.sceneacts .tb{min-height:44px;min-width:44px}

/* The composer's filters sit on one line where there is room and stack where
   there is not. `wide` is for the one that is a single question. */
.impsel.wide{flex:1 1 100%}
.impsel.wide .in{width:100%}

/* Upload: what it is, before the picker.
   Hints rather than categories — each one narrows the file picker and rides
   along as a note, and none of them rejects anything. */
.uphint{font-family:var(--f-s);font-size:12px;color:var(--faint);margin:14px 0 8px}
/* Two across on a phone, three on anything wider. It was four, and four
   made "Contracts and legal" a column of broken words: at that width the
   label is narrower than the phrase, so overflow-wrap split it mid-word. A
   heading somebody cannot read at a glance is not a heading. */
.upkinds{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin:0 0 4px}
.upkind{display:flex;align-items:center;gap:9px;padding:12px 13px;min-height:54px;
  border:1px solid var(--line);border-radius:11px;background:transparent;
  cursor:pointer;text-align:left;color:var(--ink);font-family:var(--f-s);font-size:13px}
.upkind .upkico{flex:none;display:flex;color:var(--muted)}
.upkind .upkt{min-width:0;overflow-wrap:break-word;hyphens:none;line-height:1.3}
.upkind.on{border-color:var(--accent);background:var(--tint)}
.upkind.on .upkico{color:var(--accent)}
.upkind:focus-visible{outline:2px solid var(--focus,var(--accent));outline-offset:2px}
@media (min-width:560px){ .upkinds{grid-template-columns:repeat(3,minmax(0,1fr))} }

/* ------------------------------------------------------------------ Radar
   A press mention: outlet, headline, date, the quote Ji chose, and the three
   things she can do about it. The headline reads first. */
.rditems{display:flex;flex-direction:column;gap:12px;margin:16px 0 4px}
.rdit{border:1px solid var(--line);border-radius:13px;padding:14px 15px;
  background:var(--card,transparent);transition:opacity .18s ease}
.rdit.gone{opacity:0}
.rdsub{font-family:var(--f-s);font-size:11px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--faint);margin:0 0 5px;
  display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.rdh{font-size:17px;font-weight:400;line-height:1.3;margin:0 0 5px;text-wrap:balance}
.rdh a{color:var(--ink);text-decoration:none}
.rdh a:hover{text-decoration:underline}
.rdwhen{font-family:var(--f-s);font-size:12px;color:var(--muted);margin:0 0 8px}
.rdsaid{display:flex;align-items:flex-start;gap:7px;font-size:14px;line-height:1.5;
  color:var(--muted);margin:0 0 8px}
.rdacts{display:flex;flex-wrap:wrap;gap:7px}
/* `.tb` carries no horizontal padding of its own — a <button> gets some from
   the browser and an <a> gets none, which put "Open" hard against its border.
   Stated here so both read as the same control. */
.rdacts .tb{display:inline-flex;align-items:center;justify-content:center;
  min-height:38px;padding:0 12px;text-decoration:none;white-space:nowrap}

/* Setup. Subject rows reuse the connection-row shape so a watched subject and
   a connected service read as the same kind of thing: something switched on. */
/* `.act` is HQ's full-width primary button. That is right on a phone and
   wasteful on a desktop, where two of them stack down the page for no reason
   and a single one becomes a pink bar the width of the article. */
@media (min-width:560px){
  .rdadd .act{width:auto;min-width:210px;padding-left:22px;padding-right:22px}
}
.rdsubrow.paused .ti{color:var(--muted)}
.rdsubrow .srctx p{margin:0 0 2px}
.rdsubrow .srcacts .tb{display:inline-flex;align-items:center;justify-content:center;
  padding:0 12px;min-height:38px;text-decoration:none}
.rdadd{margin-top:12px}

/* Home. Deliberately the quietest thing on the page: one line of identity, one
   count, at most two headlines. It must not compete with the greeting. */
.rdcard{display:flex;flex-direction:column;gap:4px;margin:20px 0 0;padding:13px 15px;
  border:1px solid var(--line);border-radius:13px;text-decoration:none;color:inherit}
.rdctop{display:flex;align-items:center;justify-content:space-between;gap:10px}
.rdctop b{font-weight:400;font-size:14px;flex:1;min-width:0}
.rdctop em{font-family:var(--f-s);font-size:11.5px;font-style:normal;color:var(--faint);
  letter-spacing:.04em;text-transform:uppercase;white-space:nowrap}
/* The Radar mark. Its own glyph rather than the Jay-I mark, which means the
   creative guide everywhere else, or a music note, which means a song. */
.rdcic{flex:none;color:var(--soft);display:inline-flex;align-items:center;
  margin-right:1px}
.rdcard:hover .rdcic{color:var(--accent)}
.rdchead{font-size:13.5px;line-height:1.4;color:var(--muted);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
/* What is actually going on, in her words. Never a status code and never a
   provider's name — those go to the operational view. */
.rdcsays{font-family:var(--f-s);font-size:12.5px;color:var(--muted);line-height:1.45}
/* A sweep that could not look is marked, quietly. Not red: nothing is broken
   and nothing has been lost — a source was busy. */
.rdcard.rdiffy{border-color:var(--firm)}
.rdcard.rdbad{border-color:var(--firm);background:var(--sunk)}
.rdcard.rdbad .rdcic, .rdcard.rdiffy .rdcic{color:var(--mauve)}
.rdctrouble{font-family:var(--f-s);font-size:12px;color:var(--muted);line-height:1.4}
.rdcwhen{font-family:var(--f-s);font-size:11.5px;color:var(--faint);margin-top:3px}

/* ------------------------------------------------- versions: what each one is
   The row has to stay scannable with nine takes on it, so the descriptors sit
   under the name in the quiet size and the actions hold the right edge. */
.vrow .vn{min-width:0}
.vwords{display:block;font-family:var(--f-s);font-size:11.5px;line-height:1.35;
  color:var(--faint);margin-top:2px;overflow-wrap:anywhere}
.vacts{display:flex;align-items:center;gap:6px;flex:none}
.vacts .tb{min-height:34px;min-width:34px;padding:0 9px;font-size:13px;
  display:inline-flex;align-items:center;justify-content:center}
.vacts .tb.ab[aria-pressed="true"]{border-color:var(--accent);color:var(--accent);
  background:var(--tint)}
.vabhint{margin:8px 0 0}
.vtraits{display:grid;grid-template-columns:1fr;gap:7px;margin:6px 0 4px}
.vtraits .upkind{flex-direction:column;align-items:flex-start;gap:2px}
.vtraits .upkind small{color:var(--faint);font-size:11.5px;line-height:1.35}
@media (min-width:560px){ .vtraits{grid-template-columns:repeat(2,minmax(0,1fr))} }

/* A against B. The two takes are the page; the transport is one line under
   them, because the decision is which one sounds better and everything else is
   in the way of hearing it. */
.absides{display:grid;grid-template-columns:1fr;gap:9px;margin:12px 0}
.abside{display:flex;align-items:center;gap:11px;padding:13px 14px;min-height:56px;
  border:1px solid var(--line);border-radius:12px;background:transparent;
  cursor:pointer;text-align:left;color:var(--ink);width:100%}
.abside[aria-pressed="true"]{border-color:var(--accent);background:var(--tint)}
/* A take that cannot go on a link yet (no listening copy): listed, not offered. */
.abside:disabled{cursor:default;opacity:.55}
.abkey{flex:none;width:30px;height:30px;border-radius:50%;display:flex;
  align-items:center;justify-content:center;border:1px solid var(--firm);
  font-family:var(--f-s);font-size:12px;letter-spacing:.04em}
.abside[aria-pressed="true"] .abkey{border-color:var(--accent);color:var(--accent)}
.abtx{min-width:0}
.abtx b{display:block;font-weight:400;font-size:15px;line-height:1.25}
.abtx small{display:block;font-family:var(--f-s);font-size:11.5px;color:var(--faint);
  line-height:1.4;margin-top:2px;overflow-wrap:anywhere}
.abbar{display:flex;align-items:center;gap:11px;margin:4px 0 2px}
.abbar .btn{flex:none;min-width:96px}
.abtime{font-family:var(--f-m);font-size:12px;color:var(--muted);
  font-variant-numeric:tabular-nums;flex:none}
.abseek{flex:1;height:4px;border-radius:2px;background:var(--sunk);overflow:hidden}
.abseek i{display:block;height:100%;width:0;background:var(--accent);
  transition:width .2s linear}
@media (min-width:560px){ .absides{grid-template-columns:repeat(2,minmax(0,1fr))} }

/* ================================================== the person, and their menu
   The control in the corner is a person now rather than a door into Admin, so
   it shows their picture or their initials at the same 36px the upload mark
   uses. A photograph fills the circle; initials sit in it. */
.prof{overflow:hidden;font-size:0}
.profpic{width:100%;height:100%;object-fit:cover;display:block}
.profin{font-family:var(--f-s);font-size:12.5px;font-weight:500;letter-spacing:.02em;
  color:var(--soft);line-height:1}
.prof .profin{font-size:12.5px}
.profin.big{width:72px;height:72px;border-radius:50%;background:var(--sunk);
  border:1px solid var(--firm);display:inline-flex;align-items:center;
  justify-content:center;font-size:23px;color:var(--soft)}
.profpic.big{width:72px;height:72px;border-radius:50%;object-fit:cover;display:block}

/* THE OWNER'S CROWN (Phase 3 §3.3). Small, gold in every look, sitting on the
   top-right edge of the owner's avatar wherever it appears: the header button
   and the account sheet. The button clips its picture to a circle, so a
   crowned one clips an inner face instead and lets the crown sit over the
   edge. Only the owner of the House being looked at ever gets one. */
.prof.crowned{overflow:visible;position:relative}
.profface{width:100%;height:100%;border-radius:50%;overflow:hidden;
  display:flex;align-items:center;justify-content:center}
.owner-crown{position:absolute;top:-7px;right:-6px;width:17px;height:14px;
  transform:rotate(18deg);pointer-events:none;
  filter:drop-shadow(0 1px 1px rgba(0,0,0,.28))}
.owner-crown path{fill:#F5B81C;stroke:#A8740A;stroke-width:1.2;stroke-linejoin:round}
.owner-crown circle{fill:#FFE38A}

/* ================================================================ my account */
.card{background:var(--raised);border:1px solid var(--line);border-radius:16px;
  padding:16px 16px 14px;margin:16px 0}
.card > .homeh:first-child{margin-top:0}
.vis-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

.avrow{display:flex;gap:16px;align-items:flex-start;flex-wrap:wrap}
.avnow{flex:none}
.avnow img{width:72px;height:72px;border-radius:50%;object-fit:cover;display:block}
.avacts{min-width:180px;flex:1;display:flex;flex-wrap:wrap;gap:8px;align-items:center}
/* A <label> standing in for a file button has to look and reach like one.
   `.tb` is a <button> rule and carries no display or horizontal padding —
   which a button does not need and a block-level <label> very much does: the
   text ran edge to edge and was clipped by its own border. */
label.tb{display:inline-flex;align-items:center;justify-content:center;
  padding:0 14px;cursor:pointer;line-height:1;white-space:nowrap}
.avacts .hint{flex-basis:100%;margin:2px 0 0}

/* One notification, its honest note about delivery, and its switch. */
.nlist{margin-top:4px}
.nm-t{min-width:0}
.nm-t b{display:block;font-size:15px;color:var(--ink);font-weight:450;
  /* An address (Send to HQ's own row) is one long unbroken word. Left to wrap
     normally it never breaks, so the row -- and the whole page, on a phone --
     widened to fit it instead. */
  overflow-wrap:anywhere}
.nm-t small{display:block;font-family:var(--f-s);font-size:12.5px;color:var(--muted);
  line-height:1.4;margin-top:2px}
.nm-note{display:block;font-family:var(--f-s);font-size:12px;color:var(--faint);
  font-style:normal;margin-top:4px}
/* Email to your House: the address as two whole lines, the token and then
   @domain, never broken inside either (app/sendtohq.js). Mono so the token
   reads as one thing to copy; if a very narrow screen cannot hold a line, it
   scrolls sideways rather than breaking. Two ids, so the app's row type
   (app-shell.css) does not set it back to a sentence. */
#view #send-to-hq .nm-t b.sth-addr{font-family:var(--f-m);font-size:13.5px;line-height:1.45;
  letter-spacing:-.01em;color:var(--ink);overflow-x:auto;scrollbar-width:none}
#view #send-to-hq .nm-t b.sth-addr::-webkit-scrollbar{display:none}
#view #send-to-hq .nm-t b.sth-addr > span{display:block;white-space:nowrap}
/* What the address is for, under it at the row's full width rather than
   squeezed into the column beside Copy. */
#send-to-hq .sth-row > .sth-about{grid-column:1/-1;margin-top:-6px;font-family:var(--f-s);
  font-size:13px;line-height:1.4;color:var(--muted)}
.nm-note.warn{color:var(--warn)}
/* A switch HQ cannot deliver yet: the words say so, the switch sits dimmed and
   cannot be moved (Settings, "Coming soon"). */
.nmrow.soon .tgl{opacity:.45;cursor:default}
.nm-note.nm-soon{color:var(--muted)}
.nmrow.fixed .tgl{opacity:.55}
/* A switch with its words: label, an optional line under it, the switch. One
   row wherever the same setting appears (First's share screen, Music's share
   panel), so the two cannot drift apart. */
.tglrow{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:64px;padding:10px 0}
.tglrow-k{flex:1;min-width:0;font:400 16px/1.3 var(--f-s);color:var(--ink)}
.tglrow-k small{display:block;margin-top:2px;font:400 13px/1.35 var(--f-s);color:var(--muted)}

/* A House in the list, with its initials where a mark would go. */
.rowlink.house .rl-ic{width:38px}
.hinit{width:34px;height:34px;border-radius:9px;background:var(--sunk);
  border:1px solid var(--firm);display:inline-flex;align-items:center;
  justify-content:center;font-family:var(--f-s);font-size:12.5px;font-weight:500;
  color:var(--soft)}
.hmark{width:34px;height:34px;border-radius:9px;object-fit:contain;display:block}
/* The House's face: its artist's photograph, with the owner's crown. */
.hface{position:relative}
.hphoto{width:34px;height:34px;border-radius:50%;object-fit:cover;display:block}
.hinit{width:34px;height:34px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  background:var(--tint);color:var(--accent);font:600 13px/1 var(--f-s);letter-spacing:.02em}
.hface .owner-crown{top:-6px;right:-3px}

/* A fact on one line: what it is, and what it says (Billing, My Account).
   The installed app draws these as grouped rows (app-shell.css). */
.frow{display:flex;align-items:center;justify-content:space-between;gap:12px;
  margin:0;padding:9px 0;min-height:40px;font-family:var(--f-s);font-size:14.5px;
  color:var(--ink);text-decoration:none}
.frow + .frow{border-top:1px solid var(--line)}
.frow > span{min-width:0}
.frow > b{font-weight:500;text-align:right;overflow-wrap:anywhere}
.frow small{display:block;font-size:12.5px;color:var(--muted);margin-top:2px;font-weight:400}
.frow .planname{font-weight:600}
.frow.nav{color:var(--accent)}
.frow.bad{color:var(--destructive)}
/* A row that is a button (Your account's Delete account): a row, not a box. */
button.frow{width:100%;background:none;border:0;cursor:pointer;text-align:left;font:inherit;font-family:var(--f-s);font-size:14.5px}
/* After Delete account: the one page left, centered, then Done signs out. */
.acdel-done{min-height:70vh;display:grid;place-content:center;gap:14px;padding:32px 24px;text-align:center}
.acdel-done h1{margin:0;font-family:var(--f-d);font-size:34px;line-height:1.1}
.acdel-done p{margin:0 auto 10px;max-width:30ch;color:var(--ink2);font-size:16px;line-height:1.5}
.acdel-done .btn{justify-self:center}
html.acdel-gone .topbar, html.acdel-gone nav.tabs{display:none !important}
/* My Account saves a field when it is left: "kept." is a toast, and this line
   under the fields shows only a failure (audit 2.17, Round R9). */
.acct .sheetacts:has(#ac-say:not(.bad)){display:none}
.frow .none{color:var(--muted)}
.frow .current{display:inline;margin:0 0 0 6px;color:var(--good);font-weight:600}
/* A plan's price stays whole beside what the plan includes (Plan and billing). */
.frow.tier > b{flex:none;white-space:nowrap}
.avname{display:none}
.billfoot{margin:18px 0 0}

/* A heading with its mark in front of it. The glyph sits on the text's own
   baseline rather than floating above it, and it is decorative: the words are
   the accessible name. */
.withmark{display:flex;align-items:center;gap:10px;flex-wrap:nowrap}
.radarmark{flex:none;display:inline-flex;align-items:center;color:var(--soft)}

/* ======================================================= brand & appearance
   The House's own identity, which is a different screen from Redecorate and
   has to look like one: this one is about what everybody sees. */
.brandnow{display:flex;gap:16px;align-items:flex-start;flex-wrap:wrap;margin-top:12px}
.brandmark{flex:none;padding:10px 14px;border:1px solid var(--line);border-radius:12px;
  background:var(--sunk)}
.bmk{display:block;height:34px;width:auto;max-width:200px;object-fit:contain}
[data-room="dark"] .bmk{filter:invert(1) brightness(1.6)}
.brandbits{min-width:200px;flex:1}
.brandchips{display:flex;align-items:center;gap:5px;margin-bottom:6px}
.brandchips em{font-family:var(--f-s);font-size:11px;color:var(--faint);
  font-style:normal;letter-spacing:.05em;text-transform:uppercase;margin-left:4px}
/* Scoped to where the swatch is actually drawn. Unscoped, this width reached
   every filter pill too. The swatch is its own class now (it was a `.chip`,
   the pill's name, which is retired) and only ever an <i> inside .brandchips. */
.brandchips .brand-swatch{width:18px;height:18px;border-radius:5px;border:1px solid var(--firm);
  display:inline-block}
/* The one sentence that must never be missable. */
.draftflag{font-family:var(--f-s);font-size:13px;line-height:1.5;margin:12px 0 0;
  padding:10px 12px;border-radius:10px;background:var(--tint);color:var(--ink)}

.schemeset{margin:14px 0 0;padding-top:12px;border-top:1px solid var(--line)}
.schemeset:first-of-type{border-top:0;padding-top:0}
.swrow{display:grid;grid-template-columns:1fr auto;gap:12px;align-items:center;
  padding:9px 0;border-bottom:1px solid var(--line)}
.swrow:last-child{border-bottom:0}
.swname{min-width:0}
.swname b{display:block;font-size:14.5px;font-weight:450;color:var(--ink)}
.swname small{display:block;font-family:var(--f-s);font-size:12px;color:var(--muted);
  line-height:1.4;margin-top:1px}
.swpick{display:flex;align-items:center;gap:8px;flex:none}
.swdab{width:40px;height:40px;padding:0;border:1px solid var(--firm);border-radius:9px;
  background:none;cursor:pointer}
.swhex{width:104px;font-family:var(--f-m);font-size:12.5px;text-transform:uppercase}

.markgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));
  gap:12px;margin:14px 0 10px}
.markslot{border:1px solid var(--line);border-radius:12px;padding:10px;
  display:flex;flex-direction:column;gap:8px;align-items:flex-start}
.mklabel{font-family:var(--f-s);font-size:11.5px;letter-spacing:.05em;
  text-transform:uppercase;color:var(--faint)}
.mkbox{width:100%;min-height:58px;border-radius:9px;background:var(--sunk);
  display:flex;align-items:center;justify-content:center;padding:8px;box-sizing:border-box}
.mkbox img{max-width:100%;max-height:52px;object-fit:contain}
/* A wordmark or icon is LIGHT-GROUND artwork — Brooklyn's is pure black on a
   transparent field, 94% of it transparent — so on the panel's own dark color
   it is there, loaded, and completely invisible. The slot looked empty and read
   as "never uploaded". The card further up escapes this because its <img> is
   inverted in a dark room; these previews are not, and inverting is the wrong
   answer for a slot whose whole job is to show the file as it actually is.
   So the two light-ground slots get a light plate to sit on, which is what any
   logo preview does. The two "on dark" slots hold the opposite kind of artwork
   and keep the dark panel, for the same reason. */
#mk-wordmark,#mk-icon{background:#FFFFFF}
.mknone{font-family:var(--f-s);font-size:12px;color:var(--faint);font-style:normal}

/* Two panes, each wearing its own scheme's tokens inline so the preview cannot
   leak onto the page around it. A preview that repainted HQ is a publication. */
.bpreview{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
  gap:12px;margin:12px 0}
.bpane{border:1px solid var(--firm);border-radius:14px;overflow:hidden;
  background:var(--ground);color:var(--ink)}
.bpanel{display:block;font-family:var(--f-s);font-size:11px;letter-spacing:.06em;
  text-transform:uppercase;padding:8px 12px;color:var(--faint);
  border-bottom:1px solid var(--line)}
.bp-card{margin:12px;padding:14px;border-radius:12px;background:var(--raised);
  border:1px solid var(--line)}
.bp-h{font-family:var(--f-d);font-size:21px;margin:0 0 6px;color:var(--ink)}
.bp-b{font-size:13.5px;margin:0 0 8px;color:var(--muted);line-height:1.5}
.bp-f{font-family:var(--f-m);font-size:11.5px;margin:0 0 12px;color:var(--faint)}
.bp-acts{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:0 0 12px}
.bp-cta{background:var(--cta);color:var(--oncta);border-radius:999px;
  padding:7px 14px;font-family:var(--f-s);font-size:12.5px}
.bp-link{color:var(--link);font-size:12.5px;text-decoration:underline}
.bp-sem{display:flex;gap:8px;flex-wrap:wrap;margin:0}
.bp-sem span{font-family:var(--f-s);font-size:11px;padding:3px 8px;border-radius:999px}
.bp-good{color:var(--good);border:1px solid var(--good)}
.bp-warn{color:var(--warn);border:1px solid var(--warn)}
.bp-stop{background:var(--stop);color:var(--onsem)}

.rowlink.hist{display:flex;align-items:center;gap:12px;justify-content:space-between}
.hnote{display:block;font-family:var(--f-s);font-size:11.5px;color:var(--faint);
  line-height:1.4;margin-top:3px}
.tb.mini{flex:none}

/* ================================================= the photograph behind a page
   Home's treatment, at the shallower depth every other page needs. A page with
   a table, a form or a player has to have its own ground under the content: a
   full-bleed portrait behind an editable field is unreadable, and unreadable is
   worse than plain.

   Everything here is decoration and nothing in it is interactive, so it sits
   behind the content, ignores the pointer, and is hidden from assistive
   technology by the aria-hidden the renderer sets. */
.pagewash{position:absolute;top:-14px;left:50%;width:100vw;transform:translateX(-50%);
  height:330px;z-index:-2;overflow:hidden;pointer-events:none;
  -webkit-mask-image:linear-gradient(180deg,#000 0%,#000 88%,transparent 100%);
  mask-image:linear-gradient(180deg,#000 0%,#000 88%,transparent 100%)}
.pagewash img{width:100%;height:100%;object-fit:cover;display:block;
  object-position:var(--focal-x,50%) var(--focal-y,36%);filter:var(--herofx)}
/* The same two washes Home uses: one flattens the photograph into the page, one
   feathers its lower edge so there is no line above the heading. */
.pagewashveil{position:absolute;inset:0;background:
  linear-gradient(180deg, rgba(var(--veil),var(--veil-a)) 0%,
                  rgba(var(--veil),var(--veil-b)) 34%,
                  rgba(var(--veil),var(--veil-a)) 58%,
                  rgba(var(--veil),var(--veil-c)) 80%,
                  rgba(var(--veil),.99) 94%, var(--ground) 100%)}
/* #view is the positioning context, and the heading needs room to clear the
   band. Applied only when there is actually a photograph, so a page with none
   keeps the spacing it has always had. */
#view{position:relative}
/* Room for the band, so the photograph is seen rather than mostly covered.
   Home pads 208px under a 330px band; this is the same band. */
#view.haswash{padding-top:196px}

/* From 1200px, the composition Jay actually asked for.
   A band behind a heading is not Home's treatment. Home puts the photograph
   beside the content — a tall, feathered picture holding the right-hand side
   of the page — and that is the thing he liked. The first version of this gave
   every other page a shallow strip, which in a dark room reads as nothing at
   all.
   The content column is already capped at 760px, so on a wide screen there is
   an empty right-hand region the same shape as Home's. The photograph goes
   there: no layout moves, nothing is written over, and the page reads the way
   Home does. */
@media (min-width:1200px){
  #view.haswash{padding-top:0}
  /* The panel is pinned right and the text column beside it is capped at 760px,
     but nothing ever made the two add up. The content box is 1160px (body's
     1240 less its 40px padding), so a 600px panel and a 760px column overlap by
     200px and the last words of every paragraph slid under the photograph.
     calc() is what actually fixes it — it keeps a 20px gap at any width this
     media query covers — and the two caps hold the panel to a sensible size on
     a very wide screen. */
  .pagewash{top:-18px;left:auto;right:0;transform:none;
    width:min(30vw,400px,calc(100% - 780px));height:min(100%,560px);min-height:360px;
    border-radius:14px 0 0 14px;
    /* Zero, not -2, which is where the first attempt at this went wrong.
       A negative z-index paints the panel behind the page's own ground, so it
       was there, the right size, with its image loaded, and completely
       invisible — the most confusing possible way to be broken. Home's hero
       does exactly this: -2 for the phone band, 0 for the side composition.
       Nothing is written over: the panel is prepended, so every later sibling
       paints above it, and pointer-events:none keeps it out of the way. */
    z-index:0;
    /* Feathered on every edge, like Home's: a rectangle with hard sides reads
       as a photograph pasted onto a page. The left fade is the deepest,
       because that is where it meets the words. */
    -webkit-mask-image:
      linear-gradient(90deg, transparent 0%, #000 26%, #000 94%, rgba(0,0,0,.6) 100%),
      linear-gradient(180deg, transparent 0%, #000 12%, #000 84%, transparent 100%);
    mask-image:
      linear-gradient(90deg, transparent 0%, #000 26%, #000 94%, rgba(0,0,0,.6) 100%),
      linear-gradient(180deg, transparent 0%, #000 12%, #000 84%, transparent 100%);
    -webkit-mask-composite:source-in;mask-composite:intersect}
  .pagewash img{object-position:var(--focal-x,52%) var(--focal-y,26%)}
  /* Dissolving leftward into the words rather than sitting in a frame. */
  .pagewashveil{background:
    linear-gradient(90deg, rgba(var(--veil),.97) 0%,
                    rgba(var(--veil),var(--veil-b)) 34%,
                    rgba(var(--veil),calc(var(--veil-b) * .7)) 100%)}
}
/* Nothing animates. A background that moves is a background somebody notices,
   and reduced-motion should not have to be the thing that switches it off. */

/* Choosing them, in Admin: settings.css. */

/* ------------------------------------- artwork for one listening link
   The upload sits in the row with the covers, because it is the same decision:
   which picture goes on this link. */
.cand.upl{display:flex;align-items:center;justify-content:center;cursor:pointer;
  border:1px dashed var(--firm);background:var(--sunk);overflow:hidden}
.cand.upl:hover{border-color:var(--accent)}
.cand.upl:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.cand.upl img{width:100%;height:100%;object-fit:cover;display:block}
.uplmk{display:flex;flex-direction:column;align-items:center;gap:3px;
  color:var(--soft);pointer-events:none}
.uplmk em{font-family:var(--f-s);font-size:10.5px;font-style:normal;
  letter-spacing:.04em;text-transform:uppercase}
.cand.none{display:flex;align-items:center;justify-content:center;
  background:var(--sunk);border:1px solid var(--firm)}
.nomk{font-family:var(--f-s);font-size:11px;color:var(--faint);
  letter-spacing:.04em;text-transform:uppercase}

/* ================================================================ the plan
   A list of facts, half of which are "nobody has said". The unknowns are
   styled as what they are rather than left to look like empty fields. */
.planhead{font-family:var(--f-d);font-size:22px;margin:0 0 6px;color:var(--ink)}
.planhead.quiet{color:var(--muted);font-size:18px}
.plandl{display:grid;grid-template-columns:minmax(120px,auto) 1fr;gap:8px 16px;
  margin:12px 0 0}
.plandl dt{font-family:var(--f-s);font-size:12.5px;color:var(--muted);
  padding-top:2px}
.plandl dd{margin:0;font-size:14.5px;color:var(--ink);min-width:0;
  overflow-wrap:anywhere}
.plandl dd b{font-weight:500}
.plandl dd .hint{margin:3px 0 0}
.unknown{font-family:var(--f-s);font-size:13px;color:var(--faint);font-style:normal;
  line-height:1.45;display:block}
.plantable{width:100%;border-collapse:collapse;margin-top:10px;font-size:13.5px}
.plantable th{text-align:left;font-family:var(--f-s);font-size:11.5px;
  letter-spacing:.05em;text-transform:uppercase;color:var(--faint);
  padding:0 10px 6px 0;font-weight:400}
.plantable td{padding:7px 10px 7px 0;border-top:1px solid var(--line)}
.ownlist{margin:8px 0 10px;padding-left:18px}
.ownlist li{font-family:var(--f-m);font-size:12.5px;color:var(--muted);
  line-height:1.6;overflow-wrap:anywhere}

/* =============================================================== Your fans
   The Laylo / Feature.fm / MyKey replacement lives inside HQ rather than
   borrowing any vendor's dashboard language.  It is the broad operational
   workspace in this app, so it uses the desktop shell while preserving the
   same paper, plum, serif, line and button system already used everywhere
   else.  Every selector is namespaced: the existing music, release and project
   rooms keep their exact behavior. */
#view > .direct{max-width:1180px;width:100%;margin-inline:auto;padding:8px 0 70px}
.direct{--direct-wash:color-mix(in srgb,var(--rose) 18%,var(--raised));
  --direct-green:color-mix(in srgb,var(--sage) 16%,var(--raised));
  --direct-blue:color-mix(in srgb,var(--blue) 11%,var(--raised));position:relative}
.direct-mast{display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:5px 0 15px;border-bottom:1px solid var(--line)}
.direct-name{display:block;font:400 25px/1.05 var(--f-d);letter-spacing:-.02em;
  color:var(--ink);text-decoration:none;margin-top:3px}
.direct-mast-actions{display:flex;align-items:center;gap:10px}
.direct-preview{display:inline-flex;align-items:center;gap:7px;font:500 11.5px/1 var(--f-s);
  color:var(--muted);padding:8px 11px;border:1px solid var(--firm);border-radius:999px}
.direct-preview i{width:7px;height:7px;border-radius:50%;background:var(--warn);box-shadow:0 0 0 3px color-mix(in srgb,var(--warn) 13%,transparent)}
.direct-setup{display:inline-flex;align-items:center;justify-content:center;width:42px;height:42px;
  border:1px solid var(--firm);border-radius:50%;color:var(--muted);background:var(--raised)}
.direct-setup:hover{color:var(--accent);border-color:var(--accent)}
.direct-safety{display:flex;gap:5px;align-items:baseline;margin:12px 0 0;color:var(--muted);
  font:400 12px/1.45 var(--f-s)}
.direct-safety b{font-weight:600;color:var(--warn)}
.direct-shell{display:grid;grid-template-columns:178px minmax(0,1fr);gap:34px;align-items:start;margin-top:20px}
.direct-nav{position:sticky;top:12px;display:flex;flex-direction:column;padding:8px 0;
  border-top:1px solid var(--line)}
.direct-nav-link{display:flex;align-items:center;gap:11px;min-height:47px;padding:8px 10px;
  border-bottom:1px solid var(--line);color:var(--muted);text-decoration:none;
  font:500 14px/1.2 var(--f-s);position:relative}
.direct-nav-link svg{flex:none}.direct-nav-link:hover{color:var(--ink);background:var(--sunk)}
.direct-nav-link.on{color:var(--ink);background:var(--tint)}
.direct-nav-link.on::before{content:"";position:absolute;left:0;top:10px;bottom:10px;width:2px;
  border-radius:2px;background:var(--accent)}
.direct-body{min-width:0}.direct-head{margin:7px 0 26px}.direct-back{display:inline-flex;
  min-height:38px;align-items:center;margin:0 0 9px;color:var(--muted);font:500 13px/1 var(--f-s);
  text-decoration:none}.direct-back:hover{color:var(--accent)}
.direct-head-line{display:flex;justify-content:space-between;align-items:flex-end;gap:26px}
.direct-head h1{font-size:clamp(35px,4.4vw,52px);max-width:780px;margin:7px 0 8px}
.direct-lede{font:400 clamp(17px,1.8vw,20px)/1.45 var(--f-l);color:var(--muted);
  max-width:720px;margin:0;text-wrap:pretty}
.direct-head-action{flex:none;white-space:nowrap;min-width:142px;max-width:220px;padding-inline:18px}
.direct-kicker,.direct-step,.direct-preview-label{display:block;font:600 10.5px/1.25 var(--f-s);
  letter-spacing:.13em;text-transform:uppercase;color:var(--muted)}
.direct-state{display:inline-flex;align-items:center;width:max-content;min-height:27px;padding:4px 9px;
  border-radius:999px;font:600 10.5px/1.15 var(--f-s);letter-spacing:.06em;text-transform:uppercase;
  border:1px solid var(--firm);color:var(--muted);background:var(--raised)}
.direct-state.draft{color:var(--muted);border-style:dashed}.direct-state.needs{color:var(--warn);
  border-color:color-mix(in srgb,var(--warn) 55%,var(--line));background:color-mix(in srgb,var(--warn) 7%,var(--raised))}
.direct-state.live{color:var(--good);border-color:color-mix(in srgb,var(--good) 55%,var(--line));background:color-mix(in srgb,var(--good) 7%,var(--raised))}
.direct-state.migrate{color:var(--accent);border-color:color-mix(in srgb,var(--accent) 45%,var(--line));background:var(--tint)}
.direct-state.example{color:var(--blue);border-color:color-mix(in srgb,var(--blue) 50%,var(--line));background:var(--direct-blue)}
.direct-status-row{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:11px 0 15px;margin:-10px 0 23px;border-bottom:1px solid var(--line);
  font:400 12.5px/1.4 var(--f-s);color:var(--muted)}
.direct-url{font:400 11.5px/1.4 var(--f-m);color:var(--muted);overflow-wrap:anywhere}
.direct-panel{border:1px solid var(--line);border-radius:17px;background:var(--raised);
  padding:22px;margin:0;box-shadow:0 12px 35px rgba(56,36,47,.025)}
.direct-panel h2,.direct-section h2,.direct-feature h2,.direct-proof-hero h2{font:400 26px/1.12 var(--f-d);
  letter-spacing:-.018em;color:var(--ink);margin:7px 0 9px;text-wrap:balance}
.direct-panel > p{font:400 14px/1.58 var(--f-s);color:var(--muted);margin:8px 0 0}
.direct-grid{display:grid;gap:16px}.direct-grid.two{grid-template-columns:repeat(2,minmax(0,1fr))}
.direct-section{margin:34px 0 0}.direct-section-head{display:flex;align-items:flex-end;
  justify-content:space-between;gap:16px;margin:0 0 14px}.direct-section-head h2{margin:4px 0 0}
.direct-actions{display:flex;flex-wrap:wrap;gap:9px;margin:18px 0 0}.direct-actions .btn{flex:0 1 auto;padding-inline:17px}
.direct-text-link,.direct-row-link{display:inline-flex;align-items:center;gap:7px;color:var(--accent);
  font:500 13px/1.4 var(--f-s);text-decoration:none;border:0;background:none;padding:10px 0;
  min-height:44px;cursor:pointer}.direct-text-link:hover,.direct-row-link:hover{text-decoration:underline}
.direct-source{font:400 10.5px/1.5 var(--f-m);color:var(--faint);margin:8px 2px 0}
.direct-source b{font-family:var(--f-s);font-weight:600;color:var(--muted)}

/* Overview */
.direct-feature{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(230px,.75fr);gap:30px;
  align-items:center;min-height:330px;padding:34px 36px;border-radius:22px;overflow:hidden;
  background:linear-gradient(135deg,var(--direct-wash),var(--sunk) 66%,var(--direct-blue));
  border:1px solid var(--line);position:relative}.direct-feature::after{content:"";position:absolute;
  width:220px;height:220px;border:1px solid color-mix(in srgb,var(--accent) 14%,transparent);
  border-radius:50%;right:-80px;top:-110px}.direct-feature-copy{position:relative;z-index:1}
.direct-feature h2{font-size:clamp(29px,3.4vw,43px);max-width:630px;margin:9px 0 12px}
.direct-feature-copy > p{font:400 16px/1.55 var(--f-s);color:var(--muted);max-width:570px;margin:0}
.direct-cover-stack{position:relative;width:min(100%,250px);aspect-ratio:4/5;justify-self:center;z-index:1}
.direct-cover-stack img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:14px;
  filter:saturate(.82) contrast(1.02);box-shadow:0 24px 55px rgba(33,15,29,.23)}
.direct-cover-shadow{position:absolute;inset:11px -9px -9px 11px;border:1px solid var(--firm);
  border-radius:14px;background:var(--raised);transform:rotate(4deg)}
.direct-cover-shadow.two{transform:rotate(-3deg);inset:7px 9px -7px -9px;background:var(--tile)}
.direct-cover-label{position:absolute;left:12px;right:12px;bottom:12px;padding:10px 11px;border-radius:10px;
  background:rgba(23,16,25,.78);backdrop-filter:blur(8px);color:#fff;display:flex;flex-direction:column}
.direct-cover-label b{font:400 17px/1.2 var(--f-d)}.direct-cover-label small{font:500 9.5px/1.3 var(--f-s);text-transform:uppercase;letter-spacing:.1em;opacity:.75;margin-top:2px}
.direct-metrics{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1px;border:1px solid var(--line);
  border-radius:16px;overflow:hidden;background:var(--line);margin:18px 0 0}.direct-metrics article{padding:18px 20px;background:var(--raised);display:flex;flex-direction:column}
.direct-metrics span{font:500 11.5px/1.3 var(--f-s);color:var(--muted)}.direct-metrics b{font:400 29px/1.15 var(--f-d);color:var(--ink);margin:5px 0 1px}
.direct-metrics small{font:400 11px/1.4 var(--f-s);color:var(--faint)}.direct-metrics.compact{margin-top:0}
.direct-checklist{list-style:none;padding:0;margin:16px 0 5px}.direct-checklist li{position:relative;padding:10px 0 10px 29px;
  border-top:1px solid var(--line);font:400 13.5px/1.4 var(--f-s);color:var(--ink)}
.direct-checklist li::before{content:"";position:absolute;left:1px;top:12px;width:15px;height:15px;border:1px solid var(--firm);border-radius:50%}
.direct-checklist li.done{color:var(--muted)}.direct-checklist li.done::before{background:var(--good);border-color:var(--good)}
.direct-checklist li.done::after{content:"";position:absolute;left:6px;top:15px;width:4px;height:7px;border:solid var(--oncta);
  border-width:0 1.5px 1.5px 0;transform:rotate(45deg)}
.direct-journey{display:grid;grid-template-columns:repeat(2,1fr);gap:1px;margin-top:17px;border:1px solid var(--line);border-radius:12px;overflow:hidden;background:var(--line)}
.direct-journey > span{display:grid;grid-template-columns:27px 1fr;column-gap:9px;padding:14px;background:var(--sunk)}
.direct-journey i{grid-row:1/3;width:27px;height:27px;display:flex;align-items:center;justify-content:center;border-radius:50%;background:var(--raised);border:1px solid var(--firm);
  color:var(--accent);font:500 11px/1 var(--f-m);font-style:normal}.direct-journey b{font:600 13px/1.3 var(--f-s)}.direct-journey small{font:400 11.5px/1.35 var(--f-s);color:var(--muted)}
.direct-work-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}
.direct-work-grid a{display:grid;grid-template-columns:auto 1fr;gap:9px 11px;padding:17px;border:1px solid var(--line);border-radius:14px;color:var(--ink);text-decoration:none;background:var(--raised)}
.direct-work-grid a:hover{border-color:var(--accent);transform:translateY(-1px)}.direct-work-grid svg{grid-row:1/3;color:var(--accent)}
.direct-work-grid b{font:600 14px/1.3 var(--f-s)}.direct-work-grid small{font:400 12px/1.4 var(--f-s);color:var(--muted)}
.direct-work-grid em{grid-column:1/-1;font:500 9.5px/1.2 var(--f-s);letter-spacing:.08em;text-transform:uppercase;color:var(--faint);font-style:normal;margin-top:5px}

/* Shared editor and public previews */
.direct-editor-layout,.direct-composer-layout{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(290px,.85fr);gap:22px;align-items:start}
.direct-editor{display:flex;flex-direction:column;gap:14px}.direct-editor .direct-panel{padding:21px}
.direct-step{color:var(--accent);margin-bottom:16px}.direct-field{display:flex;flex-direction:column;gap:7px;
  font:600 12px/1.3 var(--f-s);color:var(--ink);margin-top:13px}
.direct-field input,.direct-field textarea,.direct-field select,.direct-map-table select{width:100%;border:1px solid var(--firm);border-radius:10px;
  background:var(--ground);color:var(--ink);font:400 14.5px/1.45 var(--f-s);padding:11px 12px;min-height:46px;resize:vertical}
.direct-field input:focus,.direct-field textarea:focus,.direct-field select:focus,.direct-map-table select:focus{border-color:var(--accent);outline:2px solid color-mix(in srgb,var(--accent) 18%,transparent);outline-offset:1px}
.direct-field-help{font:400 11.5px/1.5 var(--f-s)!important;color:var(--faint)!important;margin:7px 0 0!important}
.direct-field-help.top{margin:-5px 0 12px!important}.direct-input-prefix{display:grid;grid-template-columns:auto minmax(100px,1fr);align-items:center;border:1px solid var(--firm);border-radius:10px;overflow:hidden;background:var(--ground)}
.direct-input-prefix i{font:400 11px/1 var(--f-m);font-style:normal;color:var(--faint);padding-left:12px;white-space:nowrap}.direct-input-prefix input{border:0;border-radius:0;min-width:80px;padding-left:2px}
.direct-block-list{display:flex;flex-direction:column;border-top:1px solid var(--line)}
.direct-block-list > button{display:grid;grid-template-columns:auto 1fr auto;gap:11px;align-items:center;border:0;border-bottom:1px solid var(--line);background:none;color:var(--ink);text-align:left;padding:12px 2px;min-height:58px;cursor:pointer}
.direct-block-list > button:hover{background:var(--sunk)}.direct-block-list b,.direct-block-list small{display:block;font-family:var(--f-s)}
.direct-block-list b{font-size:13.5px}.direct-block-list small{font-size:11.5px;color:var(--muted);margin-top:2px}.direct-block-list em{font:600 10px/1 var(--f-s);font-style:normal;color:var(--good);text-transform:uppercase;letter-spacing:.08em}
.direct-drag{color:var(--faint);letter-spacing:-1px;transform:rotate(90deg)}.direct-add{border:0;background:none;color:var(--accent);font:600 12.5px/1.3 var(--f-s);min-height:44px;padding:10px 0;cursor:pointer}
.direct-preview-wrap{position:sticky;top:14px;min-width:0}.direct-device-switch{display:flex;justify-content:center;gap:2px;margin:0 auto 10px;padding:3px;border-radius:999px;background:var(--sunk);width:max-content;border:1px solid var(--line)}
.direct-device-switch button,.direct-choice button,.direct-segments button{border:0;border-radius:999px;background:none;color:var(--muted);font:500 11.5px/1 var(--f-s);padding:9px 12px;min-height:36px;cursor:pointer}
.direct-device-switch button[aria-pressed="true"],.direct-choice button[aria-pressed="true"],.direct-segments button[aria-pressed="true"]{background:var(--raised);color:var(--ink);box-shadow:0 1px 5px rgba(40,20,33,.08)}
.direct-public{width:min(100%,344px);margin:auto;border:8px solid var(--ink);border-radius:34px;background:#171019;color:#f7edf2;overflow:hidden;box-shadow:0 24px 60px rgba(34,17,30,.18)}
.direct-public.wide{width:100%;max-width:470px;border-radius:20px}.direct-public-photo{height:210px;position:relative}.direct-public-photo::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,transparent 42%,#171019 100%)}
.direct-public-photo img{width:100%;height:100%;object-fit:cover;filter:saturate(.82);display:block}.direct-public-copy{padding:0 18px 22px;margin-top:-24px;position:relative}
.direct-public-copy > p:first-child{font:600 9px/1 var(--f-s);letter-spacing:.18em;text-transform:uppercase;color:#d9afc1;margin:0 0 5px}.direct-public-copy h2{font:400 31px/1 var(--f-d);margin:0 0 9px;color:#fff}
.direct-public-note{font:400 13px/1.45 var(--f-s);color:#cbbac4;margin:0 0 15px}.direct-public-copy > button,.direct-public-copy > a{display:flex;width:100%;align-items:center;justify-content:space-between;min-height:45px;border-radius:10px;padding:0 13px;margin:8px 0;
  font:600 12.5px/1 var(--f-s);text-decoration:none;cursor:pointer}.direct-public-copy > button{border:0;background:#e1a5b5;color:#1b1020}.direct-public-copy > a{border:1px solid #60495a;background:#241729;color:#f7edf2}
.direct-join{margin-top:17px;padding:15px 0 0;border-top:1px solid #3b2936}.direct-join b,.direct-join small{display:block}.direct-join b{font:400 19px/1.2 var(--f-d)}.direct-join small{font:400 11px/1.4 var(--f-s);color:#bba8b3;margin-top:2px}
.direct-join > span{display:flex;align-items:center;justify-content:space-between;border:1px solid #60495a;border-radius:9px;min-height:41px;margin-top:10px;padding:0 5px 0 11px}.direct-join i{font:400 11px/1 var(--f-s);font-style:normal;color:#907d89}.direct-join em{font:600 10px/1 var(--f-s);font-style:normal;background:#e1a5b5;color:#1b1020;padding:9px 11px;border-radius:7px}
.direct-public-trust{display:block;text-align:center;color:#8f7d87!important;font:400 9.5px/1.3 var(--f-s)!important;margin-top:10px!important}

/* Links and pre-save */
.direct-release-row{display:grid;grid-template-columns:116px minmax(0,1fr) auto;gap:20px;align-items:center;padding:18px;border:1px solid var(--line);border-radius:16px;background:var(--raised)}
.direct-release-row > img,.direct-art-fallback{width:116px;height:116px;object-fit:cover;border-radius:11px;display:flex;align-items:center;justify-content:center;background:var(--tile);color:var(--accent);font:400 25px/1 var(--f-d)}
.direct-release-row h3,.direct-message-row h3,.direct-setup-list h3{font:600 16px/1.25 var(--f-s);margin:8px 0 3px}.direct-release-row p{margin:3px 0;color:var(--muted);font:400 12px/1.5 var(--f-s)}
.direct-mini-stats{display:flex;flex-wrap:wrap;gap:8px 18px;margin-top:10px}.direct-mini-stats span{font:400 11px/1.3 var(--f-s);color:var(--muted)}.direct-mini-stats b{font:600 13px/1 var(--f-s);color:var(--ink)}
.direct-row-actions{display:flex;flex-direction:column;gap:8px;min-width:142px}.direct-row-actions .btn{min-height:42px;white-space:nowrap;padding:0 12px;font-size:12.5px}
.direct-release-row.simple{grid-template-columns:76px minmax(0,1fr) auto}.direct-release-row.simple .direct-art-fallback{width:76px;height:76px;font-size:18px}
.direct-explain{margin-top:32px;background:linear-gradient(140deg,var(--raised),var(--sunk))}.direct-explain-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;margin-top:19px}
.direct-explain-grid p{margin:0;padding-top:13px;border-top:1px solid var(--firm)}.direct-explain-grid b,.direct-explain-grid small{display:block;font-family:var(--f-s)}.direct-explain-grid b{font-size:13.5px}.direct-explain-grid small{font-size:11.5px;line-height:1.5;color:var(--muted);margin-top:4px}
.direct-platforms{border-top:1px solid var(--line)}.direct-platform{display:grid;grid-template-columns:auto 1fr auto auto;gap:10px;align-items:center;min-height:55px;padding:8px 0;border-bottom:1px solid var(--line)}
.direct-service-icon{width:30px;height:30px;border-radius:9px;display:flex;align-items:center;justify-content:center;background:var(--sunk);border:1px solid var(--line);font:600 11px/1 var(--f-s);color:var(--accent)}
.direct-platform b{font:600 13px/1.3 var(--f-s)}.direct-platform > em{font:500 9.5px/1 var(--f-s);font-style:normal;text-transform:uppercase;letter-spacing:.07em;color:var(--good)}
.direct-move{display:flex;gap:3px}.direct-move button{width:34px;height:34px;border-radius:8px;border:1px solid var(--line);background:var(--raised);color:var(--muted);display:flex;align-items:center;justify-content:center;cursor:pointer}.direct-move button:disabled{opacity:.3;cursor:default}
/* Direct's switches are the one .tgl in a .tglrow; the preview only draws the divider. */
.direct-panel .tglrow,.direct-import-toggle{border-top:1px solid var(--line)}
.direct-preview-label{color:var(--faint);margin:0 0 9px;text-align:center}.direct-music-preview{width:min(100%,348px);margin:auto;background:#f8f3ee;color:#38242f;border-radius:26px;overflow:hidden;border:1px solid #e4d9d2;box-shadow:0 25px 60px rgba(44,23,38,.15);padding:13px}
.direct-music-preview > img{width:100%;aspect-ratio:1.08;object-fit:cover;border-radius:18px;display:block;filter:saturate(.82)}.direct-music-preview > div{padding:15px 5px 8px}.direct-music-preview p{font:600 9px/1 var(--f-s);letter-spacing:.16em;text-transform:uppercase;color:#755b69;margin:0 0 6px}
.direct-music-preview h2{font:400 30px/1 var(--f-d);color:#38242f;margin:0 0 5px}.direct-music-preview h2 + small{font:400 12px/1.4 var(--f-s);color:#755b69;display:block;margin-bottom:14px}
.direct-music-preview button{width:100%;min-height:45px;margin:7px 0;display:flex;align-items:center;justify-content:space-between;border:1px solid #ded1cb;border-radius:10px;background:#fff;color:#38242f;padding:0 12px;font:600 12.5px/1 var(--f-s)}
.direct-music-preview button:first-of-type{background:#4b263b;color:#fff;border-color:#4b263b}.direct-music-preview button em{font-style:normal;font-size:10px;text-transform:uppercase;letter-spacing:.08em}.direct-music-preview a{display:block;text-align:center;color:#4b263b;font:600 11.5px/1.4 var(--f-s);padding:13px 0 2px;text-decoration:none}
.direct-preview-note{max-width:348px;margin:13px auto 0;padding:13px 15px;border-left:2px solid var(--rose);background:var(--sunk)}.direct-preview-note b{font:600 12px/1.3 var(--f-s)}.direct-preview-note p{font:400 11.5px/1.5 var(--f-s);color:var(--muted);margin:4px 0 0}
.pre-save-grid{grid-template-columns:minmax(0,.82fr) minmax(0,1.18fr)}.direct-release-summary{display:grid;grid-template-columns:112px 1fr;gap:17px}.direct-release-summary > img{width:112px;height:112px;object-fit:cover;border-radius:11px}.direct-release-summary h2{margin:5px 0 1px}.direct-release-summary p{margin:0!important}.direct-release-summary dl{grid-column:1/-1;margin:6px 0 0}.direct-release-summary dl div{display:flex;justify-content:space-between;gap:15px;padding:9px 0;border-top:1px solid var(--line);font:400 12px/1.4 var(--f-s)}
.direct-release-summary dt{color:var(--muted)}.direct-release-summary dd{margin:0;color:var(--ink);text-align:right}.direct-steps-list{list-style:none;padding:0;margin:14px 0 0}.direct-steps-list li{display:grid;grid-template-columns:31px 1fr auto;gap:11px;align-items:start;padding:13px 0;border-top:1px solid var(--line)}
.direct-steps-list i{width:29px;height:29px;border-radius:50%;border:1px solid var(--firm);display:flex;align-items:center;justify-content:center;font:500 11px/1 var(--f-m);font-style:normal;color:var(--muted)}
.direct-steps-list li.current i{background:var(--accent);border-color:var(--accent);color:var(--onacc)}.direct-steps-list b,.direct-steps-list small{display:block;font-family:var(--f-s)}.direct-steps-list b{font-size:13.5px}.direct-steps-list small{font-size:11.5px;line-height:1.45;color:var(--muted);margin-top:2px}.direct-steps-list em{font:600 9.5px/1 var(--f-s);font-style:normal;color:var(--faint);text-transform:uppercase;letter-spacing:.08em;margin-top:9px}
.direct-permission-card{display:grid;grid-template-columns:.8fr 1.2fr;gap:28px;margin-top:16px}.direct-consent-preview{border:1px solid var(--line);border-radius:13px;overflow:hidden;background:var(--sunk)}.direct-consent-preview p{display:grid;grid-template-columns:23px 1fr auto;gap:9px;align-items:center;margin:0;padding:11px 12px;border-top:1px solid var(--line)}.direct-consent-preview p:first-child{border-top:0}
.direct-consent-preview p > span{width:19px;height:19px;border-radius:5px;border:1px solid var(--firm);display:flex;align-items:center;justify-content:center;color:var(--oncta)}.direct-consent-preview p:first-child > span{background:var(--good);border-color:var(--good)}.direct-consent-preview b{font:500 12.5px/1.35 var(--f-s)}.direct-consent-preview em{font:500 9.5px/1 var(--f-s);font-style:normal;text-transform:uppercase;letter-spacing:.06em;color:var(--faint)}
.direct-callout{display:grid;grid-template-columns:auto 1fr auto;gap:13px;align-items:center;margin:20px 0 0;padding:16px 18px;border:1px solid var(--line);border-radius:14px;background:var(--sunk)}
.direct-callout > div{color:var(--accent)}.direct-callout p{margin:0}.direct-callout b,.direct-callout small{display:block;font-family:var(--f-s)}.direct-callout b{font-size:13.5px}.direct-callout small{font-size:11.5px;color:var(--muted);line-height:1.45;margin-top:2px}.direct-callout > a{font:600 11.5px/1.3 var(--f-s);color:var(--accent);white-space:nowrap;text-decoration:none}

/* Drops */
.direct-provider-note{display:grid;grid-template-columns:auto 1fr auto;gap:12px;align-items:center;padding:13px 15px;margin:0 0 16px;border-radius:12px;border:1px solid color-mix(in srgb,var(--warn) 38%,var(--line));background:color-mix(in srgb,var(--warn) 6%,var(--raised));color:var(--warn)}
.direct-provider-note.good{border-color:color-mix(in srgb,var(--good) 38%,var(--line));background:color-mix(in srgb,var(--good) 6%,var(--raised));color:var(--good)}
.direct-provider-note p{margin:0}.direct-provider-note b,.direct-provider-note small{display:block;font-family:var(--f-s)}.direct-provider-note b{font-size:12.5px}.direct-provider-note small{font-size:11px;line-height:1.4;color:var(--muted);margin-top:2px}.direct-provider-note a{font:600 11.5px/1 var(--f-s);color:currentColor;text-decoration:none}
.direct-message-row{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:14px;align-items:center;padding:15px 4px;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.direct-message-row.muted{color:var(--muted)}.direct-channel{width:51px;height:51px;border-radius:50%;display:flex;align-items:center;justify-content:center;font:600 9.5px/1 var(--f-s);letter-spacing:.08em;text-transform:uppercase;background:var(--tile);color:var(--accent);border:1px solid var(--line)}
.direct-channel.email{background:var(--direct-green);color:var(--good)}.direct-message-row h3{margin:0 0 3px}.direct-message-row p,.direct-message-row small{display:block;font-family:var(--f-s);color:var(--muted);margin:0}.direct-message-row p{font-size:12.5px}.direct-message-row small{font-size:10.5px;margin-top:3px;color:var(--faint)}
.direct-composer-layout{grid-template-columns:minmax(0,1.12fr) minmax(290px,.88fr)}.direct-choice{display:flex;gap:3px;padding:3px;width:max-content;max-width:100%;border:1px solid var(--line);border-radius:999px;background:var(--sunk)}
.direct-choice button{min-width:82px}.direct-audience-list{display:flex;flex-direction:column;border-top:1px solid var(--line)}.direct-audience-list button{display:grid;grid-template-columns:1fr auto;gap:12px;align-items:center;padding:12px 3px;border:0;border-bottom:1px solid var(--line);background:none;color:var(--ink);text-align:left;cursor:pointer;min-height:57px}
.direct-audience-list button[aria-checked="true"]{background:var(--tint);padding-inline:10px}.direct-audience-list b,.direct-audience-list small{display:block;font-family:var(--f-s)}.direct-audience-list b{font-size:13.5px}.direct-audience-list small{font-size:11.5px;color:var(--muted);margin-top:2px}.direct-audience-list em{font:400 17px/1 var(--f-d);font-style:normal;color:var(--ink)}
.direct-message-meta{display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-top:8px;color:var(--faint);font:400 10.5px/1.4 var(--f-m)}
.direct-jayi{display:grid;grid-template-columns:auto 1fr auto;gap:10px;align-items:center;padding:12px;margin-top:14px;border-radius:12px;background:var(--sunk);border:1px solid var(--line)}
.direct-jayi img{width:26px;height:26px;object-fit:contain}.direct-jayi p{margin:0}.direct-jayi b,.direct-jayi small{display:block;font-family:var(--f-s)}.direct-jayi b{font-size:12px}.direct-jayi small{font-size:10.5px;line-height:1.4;color:var(--muted);margin-top:2px}.direct-jayi button{min-height:36px;border:1px solid var(--firm);border-radius:8px;background:var(--raised);color:var(--accent);font:600 11px/1 var(--f-s);padding:0 10px;cursor:pointer}
.direct-review-side{position:sticky;top:14px;display:flex;flex-direction:column;gap:14px}.direct-phone-message{width:min(100%,330px);margin:auto;padding:18px 14px 16px;border:7px solid var(--ink);border-radius:30px;background:#f3f3f5;color:#1c1820;box-shadow:0 22px 50px rgba(33,18,29,.16)}
.direct-phone-top{display:grid;grid-template-columns:auto 1fr auto;gap:8px;align-items:center;border-bottom:1px solid #ddd8df;padding:0 2px 10px}.direct-phone-top i{width:26px;height:26px;border-radius:50%;background:#4b263b}.direct-phone-top b{font:600 12px/1 var(--f-s)}.direct-phone-top small{font:500 9px/1 var(--f-s);color:#746c76}
.direct-phone-message > p{max-width:88%;margin:18px 0 7px;padding:10px 12px;border-radius:15px 15px 15px 4px;background:#fff;font:400 12px/1.5 var(--f-s);overflow-wrap:anywhere}.direct-phone-message > small{display:block;font:400 8.5px/1.35 var(--f-s);color:#77717a;margin-left:4px}
.direct-send-summary{padding:18px;border:1px solid var(--line);border-radius:15px;background:var(--raised)}.direct-send-summary .direct-preview-label{text-align:left}.direct-send-summary dl{margin:8px 0 14px}.direct-send-summary dl div{display:flex;justify-content:space-between;gap:12px;padding:8px 0;border-top:1px solid var(--line);font:400 11.5px/1.4 var(--f-s)}
.direct-send-summary dt{color:var(--muted)}.direct-send-summary dd{margin:0;text-align:right;color:var(--ink);font-weight:600}.direct-send-summary .btn{width:100%;margin-top:7px;min-height:43px}.direct-approval{padding:18px;border-radius:15px;border:1px solid color-mix(in srgb,var(--warn) 42%,var(--line));background:color-mix(in srgb,var(--warn) 5%,var(--raised))}.direct-approval h2{font:400 22px/1.15 var(--f-d);margin:9px 0}.direct-approval ul{list-style:none;padding:0;margin:10px 0}.direct-approval li{position:relative;padding:7px 0 7px 23px;border-top:1px solid var(--line);font:400 11.5px/1.4 var(--f-s);color:var(--muted)}
.direct-approval li::before{content:"×";position:absolute;left:3px;color:var(--warn);font-weight:700}.direct-approval li.done::before{content:"✓";color:var(--good)}.direct-approval button{width:100%;min-height:44px;border:0;border-radius:10px;background:var(--off);color:var(--raised);font:600 12px/1 var(--f-s)}.direct-approval p{font:400 10.5px/1.4 var(--f-s);color:var(--faint);text-align:center;margin:8px 0 0}
.direct-bars{margin-top:20px}.direct-bars p{margin:12px 0}.direct-bars p > span{display:flex;justify-content:space-between;font:400 11.5px/1.4 var(--f-s)}.direct-bars em{font-style:normal;color:var(--muted)}.direct-bars p > i{display:block;height:7px;border-radius:999px;background:var(--lift);margin-top:6px;overflow:hidden}.direct-bars p > i::after{content:"";display:block;width:var(--bar);height:100%;border-radius:inherit;background:var(--accent)}
.direct-donut-row{display:grid;grid-template-columns:130px 1fr;gap:22px;align-items:center;margin-top:18px}.direct-donut{width:130px;height:130px;border-radius:50%;background:conic-gradient(var(--accent) 0 62%,var(--rose) 62% 83%,var(--firm) 83%);position:relative}.direct-donut::after{content:"386 actions";position:absolute;inset:28px;border-radius:50%;display:flex;align-items:center;justify-content:center;text-align:center;background:var(--raised);font:500 10px/1.3 var(--f-s);color:var(--muted)}
.direct-donut-row dl{margin:0}.direct-donut-row dl div{display:flex;justify-content:space-between;gap:12px;padding:9px 0;border-top:1px solid var(--line);font:400 11.5px/1.4 var(--f-s)}.direct-donut-row dd{margin:0;font-weight:600}.direct-donut-row dt i{display:inline-block;width:7px;height:7px;border-radius:50%;margin-right:7px;background:var(--accent)}.direct-donut-row dt i.apple{background:var(--rose)}.direct-donut-row dt i.other{background:var(--firm)}
.direct-truth-panel{margin-top:16px}.direct-result-table{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--line);border:1px solid var(--line);border-radius:12px;overflow:hidden;margin-top:17px}.direct-result-table > div{background:var(--sunk);padding:14px;display:flex;flex-direction:column}.direct-result-table span{font:500 10.5px/1.3 var(--f-s);color:var(--muted)}.direct-result-table b{font:400 23px/1.2 var(--f-d);margin:4px 0;color:var(--ink)}.direct-result-table small{font:400 10.5px/1.4 var(--f-s);color:var(--faint)}

/* ============================================================ release work
   The release workspace owns its own composition.

   What it replaces, and why none of it is a global change: `.room` was built
   for the song page -- a 445px text column with an absolutely-positioned
   sleeve and a photograph bled across the rest. Pointed at a release it
   produced a hero 937px tall whose content was 445px wide, with a portrait
   holding the empty right side. Restyling `.room` itself would drag every
   other screen along with it, so this is a parallel composition scoped to
   these routes and nothing else reads it.

   Colors are tokens, never literals. The reference's cream and plum are
   Brooklyn's palette, and an artist's palette is derived at runtime from their
   own brand record -- baking hex into a stylesheet is what makes a House
   themeable only by editing the build. --ground/--raised/--ink/--accent/--line
   already carry the reference's intent and are defined for every theme, so the
   dark equivalents come free instead of being invented here. */

.relwork{padding:0 0 64px}
/* Out of the 760px body column, into a 1160px one.
   body is capped at 760px and this workspace needs roughly 1120-1200, or the
   result is the thing the review called out: a narrow working column floating
   in a mostly empty page. `.room` already solves this with a full-bleed escape
   and the same arithmetic is reused here, then padded back to a centered
   1160 -- which also lets the photograph reach the right edge of the window
   instead of stopping at an invisible column boundary. */
@media (min-width:900px){
  .relwork{width:100vw;margin-left:calc(50% - 50vw);margin-right:calc(50% - 50vw);
    padding-left:max(22px,calc(50vw - 580px));
    padding-right:max(22px,calc(50vw - 580px));
    overflow-x:clip}
}

/* The hero: a photograph, a small tilted Polaroid, and a confident left column.
   The upright artwork column that briefly lived here was structurally correct
   and lost the personality the House actually has -- a recognizable photograph
   feathered into warm cream with a framed print sitting over it at a slight
   angle. This keeps the new hierarchy (title, countdown, one action, player
   beneath) and puts that treatment back.

   The feathering technique is the song page's, reused rather than reinvented:
   a mask that fades the image at its OWN bottom edge so a taller hero never
   ends in a hard horizontal line, plus a two-direction wash that protects the
   text without dimming the whole interface. Every value is a theme token, so
   a dark House gets a dark veil instead of daylight cream over a dark photo. */
.rw-hero{position:relative;isolation:isolate;padding:26px 0 20px;min-height:300px}
.rw-back{position:absolute;top:-26px;right:-6%;width:62%;height:calc(100% + 26px);
  z-index:-3;pointer-events:none;object-fit:cover;object-position:50% 38%;
  /* Fades at its own bottom AND its own left edge. The bottom mask alone left
     a hard vertical seam where the photograph began -- the wash softens the
     tone across it but cannot hide a straight boundary. Two masks intersected
     means the picture has no edge anywhere it meets the page. */
  -webkit-mask-image:linear-gradient(0deg,transparent 0%,#000 30%),
                     linear-gradient(90deg,transparent 0%,#000 46%);
  -webkit-mask-composite:source-in;
  mask-image:linear-gradient(0deg,transparent 0%,#000 30%),
             linear-gradient(90deg,transparent 0%,#000 46%);
  mask-composite:intersect}
.rw-wash{position:absolute;top:-26px;right:-6%;bottom:0;left:0;z-index:-2;
  pointer-events:none;
  background:
    linear-gradient(90deg,rgba(var(--veil),.97) 0%,rgba(var(--veil),.86) 34%,
      rgba(var(--veil),.34) 66%,rgba(var(--veil),.06) 100%),
    linear-gradient(0deg,var(--ground) 0%,var(--ground) 12%,
      rgba(var(--veil),.62) 52%,rgba(var(--veil),.1) 100%)}
/* No photograph: the intentional warm fallback, never a broken image. */
.rw-hero.noart .rw-wash{background:
  radial-gradient(120% 86% at 88% 2%,var(--lift) 0%,transparent 60%),
  linear-gradient(0deg,var(--ground) 0%,var(--ground) 26%,rgba(var(--veil),.6) 74%)}

.rw-id{position:relative;z-index:1;min-width:0;max-width:min(620px,60%)}
.rw-eyebrow{font-family:var(--f-l);font-size:11px;letter-spacing:.26em;
  text-transform:uppercase;color:var(--faint);margin:0 0 8px}
.rw-title{font-family:var(--f-d);font-weight:400;line-height:1;margin:0 0 10px;
  font-size:clamp(34px,5vw,62px);color:var(--ink);overflow-wrap:break-word}
.rw-flags{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 16px;padding:0;list-style:none}
.rw-flag{font-family:var(--f-l);font-size:11px;letter-spacing:.1em;
  text-transform:uppercase;padding:5px 9px;border-radius:999px;
  border:1px solid var(--firm);color:var(--soft);
  background:color-mix(in srgb,var(--raised) 78%,transparent);
  /* A pill, not a run of text: inline, a flag long enough to wrap -- "7 things
     before this can go out" at 320px -- broke across two lines with its
     padding only at the two ends, and the words sat on the border. */
  display:inline-block;max-width:100%;line-height:1.35}
.rw-flag.warn{border-color:var(--warn);color:var(--warn)}

/* Countdown and date, tied together rather than stacked with air between. */
.rw-when{display:flex;align-items:baseline;gap:16px;flex-wrap:wrap;margin:0 0 16px}
.rw-count{font-family:var(--f-d);font-weight:400;line-height:.86;color:var(--ink);
  font-size:clamp(54px,7.4vw,92px);margin:0}
.rw-count.none{font-size:clamp(26px,3.6vw,38px)}
.rw-whenlab{font-family:var(--f-l);font-size:12px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--faint);margin:0 0 3px}
.rw-date{font-size:16px;color:var(--soft);margin:0}
.rw-tz{font-family:var(--f-m);font-size:12px;color:var(--faint)}

.rw-next{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin:0}
.rw-cta{display:inline-flex;align-items:center;gap:8px;min-height:44px;
  padding:11px 18px;border-radius:11px;background:var(--accent);color:var(--raised);
  font-family:var(--f-l);font-size:14px;text-decoration:none;border:1px solid var(--accent)}
.rw-cta:hover{filter:brightness(1.08)}
.rw-nextwho{font-size:13px;color:var(--muted)}

/* The Polaroid: a print, not a thumbnail. Deeper lower lip, soft shadow, a few
   degrees off true. Its corners must stay inside the page -- a rotated box is
   wider than its width, which is how this kind of object causes sideways
   scrolling on a phone. */
.rw-pola{position:absolute;margin:0;z-index:1;width:98px;right:4px;top:10px;
  transform:rotate(2.5deg);transform-origin:50% 50%}
.rw-polaframe{padding:7px 7px 18px;background:var(--raised);
  box-shadow:0 12px 26px rgba(0,0,0,.16);border:1px solid var(--line)}
.rw-pola img{display:block;width:100%;aspect-ratio:1;object-fit:cover}
.rw-pola figcaption{font-family:var(--f-l);font-size:11px;line-height:1.3;
  text-align:center;color:var(--muted);margin-top:8px}
.rw-pola figcaption a{color:var(--accent)}
.rw-pola.cand .rw-polaframe{border-color:var(--mauve)}

@media (min-width:700px){
  .rw-pola{width:170px;right:28px;top:52px;transform:rotate(3deg)}
  .rw-polaframe{padding:9px 9px 24px}
  .rw-pola figcaption{font-size:12.5px;margin-top:10px}
}
@media (min-width:1000px){
  .rw-hero{padding:34px 0 24px;min-height:360px}
  .rw-pola{width:205px;right:54px;top:64px}
  .rw-polaframe{padding:10px 10px 28px}
}
/* Phone: the print tucks beside the title and the tilt eases off, so nothing
   reaches past the edge. */
@media (max-width:699px){
  .rw-id{max-width:none;padding-right:124px}
  .rw-title{font-size:clamp(30px,8vw,40px)}
  .rw-when{gap:12px}
}
/* 320px: the print gives way to the words.
   Reserving 124px for it left 152px for a title -- the smallest screen got the
   narrowest headline, which is backwards. The print shrinks, the tilt eases so
   its corners need less room, and the title gets the space back. */
@media (max-width:360px){
  .rw-pola{width:88px;right:2px;top:8px;transform:rotate(1.5deg)}
  .rw-polaframe{padding:5px 5px 14px}
  .rw-pola figcaption{font-size:10px;margin-top:6px}
  .rw-id{padding-right:98px}
}

/* The music, full width, directly under the hero. */
.rw-music{margin:18px 0 0;padding:16px 18px;border:1px solid var(--line);
  border-radius:12px;background:var(--raised)}
.rw-muhead{display:flex;flex-wrap:wrap;gap:10px;align-items:baseline;
  justify-content:space-between;margin:0 0 10px}
.rw-muwhat{font-family:var(--f-l);font-size:13px;color:var(--ink)}
.rw-muspec{font-family:var(--f-m);font-size:12px;color:var(--faint)}
.rw-mustate{font-family:var(--f-l);font-size:12px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted)}
.rw-mustate.ok{color:var(--good)}
.rw-mustate.warn{color:var(--warn)}
.rw-music.empty{display:flex;flex-wrap:wrap;gap:12px;align-items:center;
  justify-content:space-between;color:var(--muted);font-size:15px}
.rw-tracks{display:flex;flex-wrap:wrap;gap:6px;margin:10px 0 0;padding:0;list-style:none}
.rw-track{font-family:var(--f-l);font-size:12px;padding:7px 11px;min-height:36px;
  border-radius:9px;border:1px solid var(--line);background:var(--ground);
  color:var(--soft);cursor:pointer}
.rw-track[aria-current="true"]{border-color:var(--accent);color:var(--ink)}

/* One attention line, with somewhere to go. Not three headlines. */
.rw-attn{display:flex;flex-wrap:wrap;gap:12px;align-items:center;
  justify-content:space-between;margin:16px 0 0;padding:13px 16px;
  border:1px solid var(--firm);border-left:3px solid var(--mauve);
  border-radius:11px;background:var(--sunk)}
.rw-attn p{margin:0;font-size:15px;color:var(--ink)}
.rw-attn .rw-cta{background:none;color:var(--accent);border-color:var(--firm)}

/* The work: mine on the left, the team's on the right. */
.rw-work{display:grid;grid-template-columns:1fr;gap:18px;margin:22px 0 0}
@media (min-width:1000px){.rw-work{grid-template-columns:minmax(0,1.9fr) minmax(0,1fr);gap:26px}}
.rw-colhead{font-family:var(--f-d);font-weight:400;font-size:22px;margin:0 0 4px;color:var(--ink)}
.rw-colsub{font-size:13px;color:var(--muted);margin:0 0 14px}
.rw-cards{display:grid;grid-template-columns:1fr;gap:14px;padding:0;margin:0;list-style:none}
@media (min-width:700px){.rw-cards{grid-template-columns:1fr 1fr}}
.rw-card{border:1px solid var(--line);border-radius:12px;background:var(--raised);
  padding:14px;display:flex;flex-direction:column;gap:9px}
.rw-card h4{margin:0;font-family:var(--f-b);font-weight:600;font-size:15px;color:var(--ink)}
.rw-cmeta{font-size:13px;color:var(--muted);margin:0}
.rw-cthumb{width:100%;aspect-ratio:1/1;max-height:132px;object-fit:cover;
  border-radius:9px;border:1px solid var(--line)}
.rw-cwin{font-family:var(--f-d);font-size:30px;color:var(--ink);line-height:1;
  padding:14px;border-radius:9px;background:var(--sunk);text-align:center}
.rw-cwin span{display:block;font-family:var(--f-l);font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--faint);margin-top:6px}
.rw-team{padding:0;margin:0;list-style:none;display:flex;flex-direction:column;gap:2px}
.rw-team li{padding:12px 0;border-bottom:1px solid var(--line)}
.rw-team li:last-child{border-bottom:0}
.rw-tname{font-size:15px;color:var(--ink);margin:0 0 3px}
.rw-tmeta{font-size:13px;color:var(--muted);margin:0}
.rw-none{font-size:15px;color:var(--muted);margin:0;padding:14px;
  border:1px dashed var(--firm);border-radius:11px;background:var(--sunk)}

/* The trail: horizontal on desktop, wrapping on a phone, and AFTER the work. */
.rw-trail{display:flex;flex-wrap:wrap;gap:8px;margin:26px 0 0;padding:16px 0 0;
  border-top:1px solid var(--line);list-style:none}
.rw-step{flex:1 1 150px;min-width:140px}
.rw-stepname{font-family:var(--f-l);font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--faint);margin:0 0 4px}
.rw-stepstate{font-size:14px;color:var(--soft);margin:0}
.rw-step.done .rw-stepstate{color:var(--good)}
.rw-step.now .rw-stepname{color:var(--accent)}

/* Team plan keeps the release, compactly. No second cinematic hero. */
.rw-strip{display:flex;flex-wrap:wrap;gap:14px;align-items:center;
  padding:12px 0;border-bottom:1px solid var(--line);margin:0 0 16px}
.rw-strip img{width:52px;height:52px;border-radius:9px;object-fit:cover;
  border:1px solid var(--line)}
.rw-stripid{min-width:0;flex:1 1 auto}
.rw-stripid b{display:block;font-family:var(--f-d);font-weight:400;font-size:21px;
  color:var(--ink);line-height:1.1}
.rw-stripid span{font-size:13px;color:var(--muted)}

/* The stage trail, inside the release workspace only.
   Globally `.trail` is a vertical list and that is right where it lives. Here
   it sits after the reader's own work and must not be a tall column of
   "Unknown" pushing the page down -- the review measured that as one of the
   reasons the next action was unreachable. Horizontal on desktop, wrapping on
   a phone, same markup and same evidence. */
.relwork .trail{margin:26px 0 0;padding-top:16px;border-top:1px solid var(--line)}
.relwork .trail-l{display:flex;flex-wrap:wrap;gap:10px}
.relwork .ts{flex:1 1 120px;min-width:118px;border-top:0;padding:0;
  flex-direction:column;gap:6px}
.relwork .ts-t{font-size:13.5px}
.relwork .ts-t small{font-size:12px}
@media (max-width:699px){
  .relwork .ts{flex:1 1 44%;min-width:130px}
}

/* The view strip scrolls, and now says so.
   Four destinations do not fit 390px, so `.relviews` has always scrolled --
   silently. "Files & details" sat at x=480 on a 390px screen with nothing to
   suggest it existed. The mask fades the strip's own right edge, and because a
   mask paints on the element rather than its content it stays at the edge
   while the tabs move under it: the fade is present exactly while there is
   something further along, and gone once you reach the end. */
.relviews{scroll-snap-type:x proximity;-webkit-overflow-scrolling:touch}
.relviews > *{scroll-snap-align:start}
@media (max-width:820px){
  .relviews{-webkit-mask-image:linear-gradient(90deg,#000 86%,transparent 100%);
    mask-image:linear-gradient(90deg,#000 86%,transparent 100%)}
}

/* Team plan: identity, then work. Settings are not the opening experience. */
.rw-striplisten{margin-left:auto;font-family:var(--f-l);font-size:13px;
  color:var(--accent);text-decoration:none;min-height:44px;display:inline-flex;
  align-items:center;padding:0 12px;border:1px solid var(--firm);border-radius:10px}
.planhead{display:flex;flex-wrap:wrap;gap:12px;align-items:center;
  justify-content:space-between;margin:18px 0 2px}
.planhead .slab{margin:0}
.plansettings{margin:0}
.plansettings > summary{cursor:pointer;list-style:none;font-family:var(--f-l);
  font-size:13px;color:var(--accent);border:1px solid var(--firm);border-radius:10px;
  padding:10px 14px;min-height:44px;display:inline-flex;align-items:center}
.plansettings > summary::-webkit-details-marker{display:none}
.plansetbody{margin:12px 0 0;padding:14px;border:1px solid var(--line);
  border-radius:12px;background:var(--raised)}
.slab2{font-family:var(--f-l);font-size:12px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--faint);margin:0 0 10px}
.scopesum{font-size:13px;color:var(--muted);margin:2px 0 14px}
.phase{margin:20px 0 0}
.phasehint{font-size:13px;color:var(--muted);margin:-4px 0 10px}
.phasedone{margin:22px 0 0;border-top:1px solid var(--line);padding-top:12px}
.phasedone > summary{cursor:pointer;font-family:var(--f-l);font-size:13px;
  color:var(--muted);min-height:44px;display:flex;align-items:center}
/* Unassigned is a state somebody can act on, not a faint dash nobody reads. */
/* "Unassigned" is 10 characters and the owner button caps at 8ch, so it
   rendered as "Unassig…" -- which is worse than the faint dash it replaced.
   The word is the point: it names a gap somebody can close. */
.evown.unassigned{color:var(--mauve);border:1px dashed var(--firm);border-radius:8px;
  max-width:none;padding:0 9px;line-height:42px;font-size:13px}
/* The two short-form windows, under the one row that used to imply one job. */
.evkids{display:grid;gap:8px;margin:2px 0 10px 34px}
@media (min-width:700px){.evkids{grid-template-columns:1fr 1fr}}
.evkid{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:9px 12px;border:1px solid var(--line);border-radius:10px;background:var(--sunk)}
.evkid-n{font-size:13.5px;color:var(--ink)}
.evkid-s{font-family:var(--f-l);font-size:11px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--mauve)}
.evkid-s.ok{color:var(--good)}
.evkid-a{margin-left:auto;font-size:13px;color:var(--accent);min-height:44px;
  display:inline-flex;align-items:center}

/* ================================================================= intake
   Three stages instead of six stacked fieldsets.

   The old page put cover ideas above the date and gave no sense of how long
   the form was. The date -- the thing people arrive wanting to know -- sat
   near the bottom, and on a phone its section began around y=1361. */
.intakewrap{max-width:980px;margin:0 auto}
.istagebar{display:flex;flex-wrap:wrap;gap:8px;list-style:none;margin:6px 0 22px;padding:0}
.istagedot{display:flex;align-items:center;gap:8px;cursor:pointer;
  font-family:var(--f-l);font-size:13px;color:var(--faint);
  padding:9px 13px;min-height:44px;border-radius:999px;border:1px solid var(--line)}
.istagedot span{display:grid;place-items:center;width:20px;height:20px;border-radius:50%;
  background:var(--sunk);color:var(--faint);font-size:11px}
.istagedot.on{color:var(--ink);border-color:var(--firm)}
.istagedot.on span{background:var(--accent);color:var(--raised)}
.ihead{font-family:var(--f-d);font-weight:400;font-size:clamp(28px,4.2vw,44px);
  line-height:1.06;margin:0 0 6px;color:var(--ink);outline:none}
.isub{font-size:17px;color:var(--muted);margin:0 0 22px;max-width:52ch}

/* Song on the left, the date coach on the right -- reachable before anything
   has been typed, because "when could this come out" is the question people
   turn up with. */
.istagesplit{display:grid;grid-template-columns:1fr;gap:22px}
@media (min-width:860px){
  .istagesplit{grid-template-columns:minmax(0,57fr) minmax(0,43fr);gap:30px;align-items:start}
}
.istagemain{min-width:0}
.istageside{min-width:0;display:grid;gap:14px;align-content:start}
.datecard,.needcard{border:1px solid var(--line);border-radius:12px;
  background:var(--raised);padding:16px}
.datecard{border-color:var(--firm)}
.datecard-h{font-family:var(--f-d);font-size:21px;margin:0 0 6px;color:var(--ink)}
.datecard-b{font-size:14.5px;color:var(--muted);margin:0 0 14px}
.needcard-h{font-family:var(--f-l);font-size:12px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--faint);margin:0 0 10px}
.needcard ul{margin:0 0 10px;padding-left:18px;font-size:14.5px;color:var(--soft)}
.needcard li{margin:0 0 5px}
.go2{min-height:44px;padding:11px 16px;border-radius:11px;border:1px solid var(--accent);
  background:var(--accent);color:var(--raised);font-family:var(--f-l);font-size:14px;
  cursor:pointer}
.back2{min-height:44px;padding:11px 16px;border-radius:11px;border:1px solid var(--firm);
  background:none;color:var(--accent);font-family:var(--f-l);font-size:14px;cursor:pointer}

/* Grouping by space, not a border round every field. */
.ifg{border:0;padding:0;margin:0 0 26px}
.ilegend{font-family:var(--f-l);font-size:12px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--faint);margin:0 0 10px}
.ilegend .opt{text-transform:none;letter-spacing:0;font-size:12px;color:var(--faint)}
.iextras{margin:0 0 24px;border-top:1px solid var(--line);padding-top:12px}
.iextras > summary{cursor:pointer;font-family:var(--f-l);font-size:13.5px;
  color:var(--accent);min-height:44px;display:flex;align-items:center}
.iextrasbody{padding:10px 0 0}
.pickset.wide{margin-bottom:18px}
.istagenav{display:flex;flex-wrap:wrap;gap:10px;align-items:center;
  margin:26px 0 0;padding-top:18px;border-top:1px solid var(--line)}

/* The review: what we have, before anything is created. */
.ireview{border:1px solid var(--line);border-radius:12px;background:var(--raised);
  padding:4px 16px;margin:0 0 24px}
.irow{display:flex;flex-wrap:wrap;gap:10px;justify-content:space-between;
  padding:13px 0;border-bottom:1px solid var(--line)}
.irow:last-child{border-bottom:0}
.irk{font-family:var(--f-l);font-size:12px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--faint)}
.irv{font-size:15px;color:var(--ink);text-align:right}
.irv.warn{color:var(--warn)}
.orgline{font-size:16px;color:var(--ink);margin:0 0 4px}

/* §12 "Plan a release": the whole surface is the .ireview group above, made
   tappable. Each row opens a sheet; the value reads as an offer (italic,
   accent) whether it names what was chosen or invites adding it. The ⓘ sits
   beside the row's own label, not the value -- it explains the row, not the
   answer. */
.irow.tap{cursor:pointer}
.irow.tap:active{background:var(--sunk)}
.irk{display:inline-flex;align-items:center;gap:3px}
.irright{display:flex;align-items:center;gap:6px;min-width:0}
.irv.offer{font-style:italic;color:var(--accent);font-weight:400}
.irinfo{position:relative;flex:none;display:inline-flex;align-items:center;
  justify-content:center;width:16px;height:16px;margin:0;padding:0;border:0;
  background:none;color:var(--faint);cursor:pointer}
.irinfo::after{content:'';position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%);width:44px;height:44px}
.relplan-cta{display:block;width:100%;text-align:center;margin:24px 0 8px}

/* A row that opens in place (Jay, September 27): its controls appear right
   under it, inside the same card, and the chevron turns down while it is open.
   The choices are full-size touch targets here, not the compact chips. */
.irgo svg{transition:transform .18s ease}
.irow.open .irgo svg{transform:rotate(90deg)}
.irow.open{border-bottom:0}
.irpanel{padding:2px 0 16px;border-bottom:1px solid var(--line)}
.irpanel:last-child{border-bottom:0}
.irpanel .pickset{display:flex;margin:0 0 12px}
.irpanel .pickset.wide{margin-bottom:12px}
.irpanel > :last-child{margin-bottom:0}
.irpanel .in{margin:6px 0 0}
.irpanel .lbl{margin:10px 0 0}
.irpanel .lbl.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
.irpanel .coach{margin:12px 0 0}
.irpanel .toolacts{margin:10px 0 0}
.rprec-k{margin:0;font-family:var(--f-l);font-size:11px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--faint)}
.rprec-date{margin:4px 0 0;font:400 20px/1.3 var(--f-d);color:var(--ink)}
.rprec-why{margin:6px 0 0;font:400 13.5px/1.5 var(--f-s);color:var(--muted)}

/* §12 review: Single/EP/Album, a segmented control per docs/ui-conventions.md
   §6. Reuses .choices.joined as-is; only the spacing around it is this
   surface's own. A TRACKS row's "Add a song" reads like the other rows'
   offers, left-aligned since it has no separate value column. */
.relkind{margin:0 0 22px}
.irv.offer.add{text-align:left}
.relplan .ilegend{margin:22px 0 10px}
.relplan .ireview + .ilegend{margin-top:24px}

/* Phone: 16px inputs so nothing zooms, and the coach sits near the top. */
@media (max-width:859px){
  .istageside{order:-1}
  .intake .in,.intake .ta{font-size:16px}
}

/* Touch targets, without redrawing anything.
   An audit at 390px found the choice pills at 29px, the plan's tick boxes at
   20px, the filter chips at 38px and the scope switches at 26px. A pseudo
   element centered on each one takes the press without changing what is drawn,
   so the design is untouched and a thumb still lands. Scoped to these routes:
   the same classes appear on screens this work order does not cover.
   The tick's target is ::before because its ::after is the check mark. On
   ::after, a done row's mark became this 44px box with the check's right and
   bottom border: a line through the first letter of every completed task,
   and no check (Jay, October 12). */
.relwork .pf,.relwork .tick,
.intakewrap .istagedot{position:relative}
.relwork .pf::after,.relwork .tick::before{content:'';position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%);width:max(100%,44px);height:44px}
/* An inline text link inside the work columns is a real destination, not
   decoration, so it gets a thumb-sized target too. */
.relwork .rw-work .linky{display:inline-flex;align-items:center;min-height:44px}

/* ---------------------------------------------------- short-form sounds
   One player, two quiet rows. Everything a sound needs -- placing it, hearing
   it, saving it, approving it and seeing who did -- lives in its own row.

   UNBOXED, deliberately. The previous attempt gave each row an outlined
   container and a large duration tile; two quiet decisions became two cards
   competing inside a panel that is already a card. Rows are separated by a
   hairline and nothing else. */
.rw-lanes{margin:14px 0 0;padding:13px 0 0;border-top:1px solid var(--line)}
.sl-head{display:flex;align-items:center;justify-content:space-between;gap:12px;
  flex-wrap:wrap;margin:0 0 4px}
.sl-head h4{margin:0;display:flex;align-items:center;gap:8px;font-family:var(--f-b);
  font-weight:600;font-size:14.5px;color:var(--ink)}
/* The platform's own mark, at its own proportions. It never carries state --
   recoloring a brand to mean "approved" is both wrong and unreadable. */
.sl-mark{border-radius:4px;display:block;flex:none}
.sl-head span{font-size:12.5px;color:var(--faint)}

.sl{padding:11px 0 9px}
.sl + .sl{border-top:1px solid var(--line)}
.sl-main{display:grid;grid-template-columns:46px minmax(0,1fr) auto auto auto;
  gap:12px;align-items:center}
.sl-dur{font-family:var(--f-l);font-size:13px;color:var(--soft);line-height:1.15}
.sl-dur i{font-style:normal;font-size:11px;color:var(--faint)}

.sl-track{position:relative;height:26px;border-radius:13px;background:var(--sunk);
  border:1px solid var(--line);touch-action:pan-y}
.sl-band{position:absolute;top:-1px;bottom:-1px;border-radius:13px;cursor:grab;
  background:color-mix(in srgb,var(--accent) 24%,transparent);
  border:1px solid var(--accent);display:grid;place-items:center;
  touch-action:none;min-width:16px}
.sl-band:active{cursor:grabbing}
.sl-band.draft{background:color-mix(in srgb,var(--muted) 12%,transparent);
  border-style:dashed;border-color:var(--firm)}
.sl-band:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
/* A 26px row reads right and a 26px target does not. The grip carries a 44px
   press area without changing the drawing. */
.sl-grip{width:13px;height:13px;border-radius:3px;background:var(--accent);
  opacity:.9;position:relative}
.sl-band.draft .sl-grip{background:var(--firm)}
.sl-grip::after{content:'';position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%);width:44px;height:44px}

.sl-time{font-family:var(--f-m);font-size:12.5px;color:var(--soft);white-space:nowrap}
.sl-time.none{color:var(--faint)}
.sl-hear{width:30px;height:30px;border-radius:50%;border:1px solid var(--firm);
  background:var(--raised);color:var(--accent);display:grid;place-items:center;
  cursor:pointer;position:relative;flex:none}
.sl-hear::after{content:'';position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%);width:44px;height:44px}
.sl-hear:disabled{opacity:.45;cursor:default}
.sl-hear.on{background:var(--accent);color:var(--raised);border-color:var(--accent)}

/* One action, changing in place: Save choice -> Approve -> Edit. */
.sl-act{display:flex;align-items:center;gap:8px;white-space:nowrap}
.sl-btn{padding:0 12px}
.sl-num{width:68px;min-height:44px;padding:0 9px;border-radius:9px;
  border:1px solid var(--firm);background:var(--ground);color:var(--ink);
  font-family:var(--f-m);font-size:13px}

/* The stoplight. Always a glyph AND words -- color alone is not a state. */
.sl-state{margin:5px 0 0 58px;font-size:12.5px;display:flex;align-items:baseline;
  gap:7px;flex-wrap:wrap;color:var(--muted);border:0}
/* A reason can be a sentence; it wraps under the label rather than running off
   the end of the row. */
.sl-state .sl-why{color:var(--faint);font-family:inherit;font-size:12px;
  flex:1 1 240px;min-width:0}
.sl-state .g{width:12px;height:12px;border-radius:50%;flex:none;
  border:1.5px solid currentColor;display:grid;place-items:center}
.sl-state.is-wait{color:var(--state-wait)}
.sl-state.is-done{color:var(--state-done)}
.sl-state.is-redo{color:var(--warn)}
.sl-state.is-done .g{background:currentColor;border-color:currentColor}
.sl-state.is-done .g svg{color:var(--raised)}
.sl-state .sl-why{color:var(--faint)}
/* After dark, both come from html[data-room="dark"] at the top. */

.sl-more{margin:4px 0 0 58px}
.sl-more > summary{cursor:pointer;font-size:12px;color:var(--faint);
  min-height:32px;display:flex;align-items:center}
.sl-morebody{font-size:12.5px;color:var(--muted);padding:4px 0 2px;
  display:grid;gap:3px}
.sl-morebody code{font-family:var(--f-m);font-size:12px}
.sl-stub{padding:11px 13px;border:1px dashed var(--firm);border-radius:10px;
  background:var(--sunk);font-size:13.5px;color:var(--muted);margin:6px 0 0}
.rw-lanesay{font-size:12.5px;color:var(--muted);margin:9px 0 0}
.rw-lanesay.bad{color:var(--stop)}

@media (max-width:640px){
  /* The slider gets the width; everything else wraps beneath it. */
  .sl-main{grid-template-columns:auto minmax(0,1fr) auto;row-gap:10px}
  .sl-track{grid-column:1 / -1;order:3}
  .sl-act{order:4;grid-column:1 / -1}
  .sl-state,.sl-more{margin-left:0}
}

/* The check counts are controls, so they look and behave like controls. */
.chkc{cursor:pointer;border:1px solid transparent;background:none;font:inherit;
  text-align:left;min-height:44px}
.chkc:disabled{cursor:default;opacity:.55}
.chkc[aria-pressed="true"]{border-color:var(--accent);
  background:color-mix(in srgb,var(--accent) 10%,transparent);border-radius:10px}
.chkfilter{font-size:13px;color:var(--muted);margin:8px 0 0}

/* A video waiting for, or showing, its adaptive player. */
.media-stream-stage{display:flex;align-items:center;justify-content:center;
  flex-direction:column;gap:12px;width:100%;height:100%;min-height:240px}
.media-stream-stage .lbimg{max-height:60%;object-fit:contain}
.media-stream-player{width:100%;aspect-ratio:16/9;border:0;background:#000}


/* WHAT WILL HAPPEN TO THIS FILE, said before it is sent.
   A prediction, and worded as one -- "will be filed", never "filed". */
.upplan{margin:2px 0 0;font-family:var(--f-s);font-size:12px;line-height:1.45;
  color:var(--faint);display:flex;flex-wrap:wrap;gap:4px 8px;align-items:baseline}
.upplan b{color:var(--muted);font-weight:600}
.upplan .upshield{color:var(--accent)}

/* ==================================================================
   People & access
   ------------------------------------------------------------------
   The approved permissions visual, expressed in this House's own tokens.
   The reference prototype carried its own `--ih-*` palette — plum on cream in
   the light, plum and pink after dark. This House already has that world, in
   `--ground`, `--raised`, `--sunk`, `--accent` and the rest, and it already
   follows the artist's chosen look and the eight seasonal themes. So nothing
   below declares a color: every value is a token, and the screen follows the
   look the way the rest of the app does rather than sitting inside it wearing
   a palette of its own.
   Proportions ARE from the reference and are kept: a 212px role rail, ~24px
   between sections, 12–13px corners on the local panels, a serif section
   title. Small supporting text is a step larger than the mockup's, because the
   mockup's 10px labels carry real sentences here — "nobody has said they were
   added at the sign-in provider" is not a caption.
   ================================================================== */

.ihx{
  border:1px solid var(--line); border-radius:18px; overflow:hidden;
  background:var(--ground); margin-top:18px;
}
.ihx-top{
  display:flex; align-items:center; justify-content:space-between; gap:14px;
  padding:17px 20px; border-bottom:1px solid var(--line); flex-wrap:wrap;
}
.ihx-where{ font:12px/1.5 var(--f-s); color:var(--muted); letter-spacing:.2px; }
.ihx-where i{ font-style:normal; opacity:.55; margin:0 4px; }

/* The crown, and the only place it appears.
   Accent-colored so it reads as the one authoritative mark on the page, and
   never larger than the words beside it — it supports the label "House Owner",
   it does not replace it. */
.ih-owner-mark{
  display:inline-flex; align-items:center; gap:8px;
  font:13px/1.4 var(--f-s); color:var(--ink);
}
.ih-owner-mark svg{ color:var(--accent); flex:none; }
.ih-owner-mark i{ font-style:normal; color:var(--muted); margin:0 2px; }

.ihx-shell{ display:grid; grid-template-columns:212px minmax(0,1fr); }
.ihx-rail{ background:var(--sunk); padding:20px 10px; border-right:1px solid var(--line); }
.ihx-main{ min-width:0; padding:22px 24px; }

.ih-eyebrow{
  font:650 10px/1.5 var(--f-s); letter-spacing:1.6px; text-transform:uppercase;
  color:var(--muted); margin:0 0 12px; padding:0 10px;
}
.ih-eyebrow+.ih-person-list{ margin-bottom:18px; }
.ih-person-list{ display:block; }

.ih-person{
  display:flex; align-items:center; gap:10px; width:100%; min-height:44px;
  padding:11px 10px; margin:0 0 6px; border:1px solid transparent;
  border-radius:12px; text-align:left; background:transparent; color:var(--ink);
  font:inherit; cursor:pointer;
}
.ih-person[aria-pressed="true"]{
  background:var(--raised); border-color:var(--line);
}
.ih-person-text{ min-width:0; }
.ih-person strong{ display:block; font:600 13px/1.35 var(--f-s); }
.ih-person small{ display:block; color:var(--muted); font:11.5px/1.4 var(--f-s); margin-top:2px; }
.ih-role-icon{
  width:30px; height:30px; display:grid; place-items:center; flex:none;
  color:var(--accent);
}
.ih-side-note{ font:11.5px/1.6 var(--f-s); color:var(--muted); padding:10px; margin:10px 0 0; }
.ih-add,.ih-back{
  width:100%; min-height:44px; margin-top:12px; border:1px solid var(--firm);
  border-radius:11px; background:var(--raised); color:var(--ink);
  font:13px/1.2 var(--f-s); cursor:pointer;
}
.ih-add:hover,.ih-back:hover{ border-color:var(--accent); }

.ih-context{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  flex-wrap:wrap; color:var(--muted); font:12px/1.5 var(--f-s);
}
.ih-draft,.ih-custom{
  display:inline-flex; align-items:center; gap:5px; border:1px solid var(--line);
  border-radius:20px; padding:3px 10px; font:11px/1.5 var(--f-s);
  letter-spacing:.5px; color:var(--muted); text-transform:uppercase;
}
.ih-custom{ border:0; color:var(--accent); margin-left:10px; vertical-align:middle; }

.ihx-title{ font:34px/1.12 var(--f-d); letter-spacing:-.6px; margin:14px 0 6px; color:var(--ink); }
.ihx-sub{ margin:0 0 18px; color:var(--muted); font:13.5px/1.6 var(--f-s); max-width:58ch; }
.ihx-loading{ color:var(--muted); font:13px/1.6 var(--f-s); }
.ihx-bad{ color:var(--stop); font:13px/1.6 var(--f-s); }

.ih-steps{ display:flex; gap:14px; flex-wrap:wrap; margin:14px 0 18px;
  color:var(--muted); font:12px/1.5 var(--f-s); }
.ih-steps b{ color:var(--accent); font-weight:650; margin-right:4px; }
.ih-steps .on{ color:var(--ink); }

/* The tinted scope banner from the reference: the sentence that says what this
   role is pointed at, with the folder-key beside it. */
.ih-scope{
  display:flex; align-items:flex-start; gap:11px; background:var(--tile);
  padding:13px 15px; border-radius:12px; margin-bottom:16px;
}
.ih-scope svg{ color:var(--accent); margin-top:3px; flex:none; }
.ih-scope b{ display:block; font:600 13.5px/1.45 var(--f-s); }
.ih-scope small{ display:block; font:12px/1.6 var(--f-s); color:var(--muted); margin-top:3px; }
.ih-scope i{ font-style:normal; opacity:.6; }
.ih-scope .ih-custom{ margin-left:auto; align-self:center; white-space:nowrap; }
.ih-wait-scope{ background:var(--sunk); }

.ih-settings{ display:flex; gap:12px; flex-wrap:wrap; margin-bottom:18px; align-items:flex-end; }
.ih-setting{ display:block; font:600 12px/1.4 var(--f-s); flex:1; min-width:190px; }
.ih-setting small{ font-weight:400; color:var(--muted); }
.ih-input{
  display:block; width:100%; margin-top:6px; background:var(--raised);
  border:1px solid var(--firm); border-radius:9px; padding:11px 10px;
  color:var(--ink); font:13px/1.3 var(--f-s); min-height:44px;
}
.ih-check{
  display:flex; align-items:flex-start; gap:9px; flex:1; min-width:200px;
  min-height:44px; font:13px/1.5 var(--f-s); padding:9px 0; cursor:pointer;
}
.ih-check input{ margin:3px 0 0; accent-color:var(--accent); width:18px; height:18px; flex:none; }
.ih-check small{ display:block; color:var(--muted); font-size:12px; margin-top:2px; }
.ih-expiry{ max-width:260px; }

.ih-advanced{ width:100%; margin:0 0 16px; border-top:1px solid var(--line); padding-top:8px; }
.ih-advanced summary{ cursor:pointer; font:13px/1.5 var(--f-s); color:var(--muted); padding:8px 0; min-height:44px; }
.ih-advanced summary i{ font-style:normal; opacity:.6; }
.ih-advanced>div{ display:flex; flex-wrap:wrap; gap:10px; padding-top:6px; }

.ih-tabs{ display:flex; gap:22px; border-bottom:1px solid var(--line); margin:4px 0 20px; }
.ih-tab{
  background:transparent; color:var(--muted); padding:11px 0; border:0;
  border-bottom:2px solid transparent; font:13px/1.4 var(--f-s); cursor:pointer;
  min-height:44px;
}
.ih-tab[aria-selected="true"]{ color:var(--ink); border-bottom-color:var(--accent); font-weight:600; }

.ih-grid{ display:grid; grid-template-columns:minmax(0,.93fr) minmax(0,1.07fr); gap:24px; }
.ihx-main h3{ font:650 12.5px/1.5 var(--f-s); margin:0 0 12px; color:var(--ink); }
.ih-subhead{ margin-top:22px !important; }
.ih-row{
  display:flex; align-items:flex-start; justify-content:space-between; gap:13px;
  padding:10px 0; border-bottom:1px solid var(--line); font:12.5px/1.5 var(--f-s);
}
.ih-level{ text-align:right; color:var(--muted); font-size:12px; max-width:54%; }
.ih-level.ih-enabled{ color:var(--good); }

.ih-mini-list{ margin:0; padding:0; list-style:none; }
.ih-mini-list li{ display:flex; align-items:flex-start; gap:9px; margin:10px 0; font:12.5px/1.5 var(--f-s); }
.ih-mini-list svg{ flex:none; color:var(--good); margin-top:2px; }
.ih-mini-list.ih-blocked svg{ color:var(--muted); }
.ih-mini-list small{ display:block; color:var(--muted); font-size:11.5px; margin-top:2px; }
.ih-mini-list i{ font-style:normal; opacity:.55; }
.ih-history li{ margin:12px 0; }

.ih-resource{
  padding:12px 0; border-bottom:1px solid var(--line); display:flex;
  align-items:flex-start; gap:10px;
}
.ih-resource>svg{ flex:none; color:var(--muted); margin-top:3px; }
.ih-resource-text{ flex:1; min-width:0; }
.ih-resource b{ font:550 12.5px/1.45 var(--f-s); display:block; overflow-wrap:anywhere; }
.ih-resource small{ font:11.5px/1.5 var(--f-s); display:block; color:var(--muted); margin-top:2px; }
.ih-resource i{ font-style:normal; opacity:.55; }

/* A permission state, never an approval state. The green check on a row means
   "this is reachable"; an approved asset is a different fact with a different
   mark, and the two must not be able to be read for one another. */
.ih-chip{
  display:inline-flex; gap:4px; align-items:center; background:var(--tint);
  color:var(--good); padding:3px 8px; border-radius:6px; font:11.5px/1.5 var(--f-s);
  max-width:150px; text-align:right; flex:none;
}
.ih-chip.ih-private{ background:var(--sunk); color:var(--muted); }
.ih-chip.ih-wait{ color:var(--warn); }
.ih-chip.ih-inherit{ background:var(--sunk); color:var(--muted); }

.ih-footer{
  margin-top:20px; border-top:1px solid var(--line); padding-top:14px;
  display:flex; align-items:flex-start; gap:9px; color:var(--muted);
  font:12px/1.6 var(--f-s);
}
.ih-footer svg{ flex:none; color:var(--accent); margin-top:2px; }
.ih-footer b{ color:var(--ink); font-weight:600; }
.ih-footnote{ font:11.5px/1.6 var(--f-s); color:var(--muted); margin:10px 0 0; }

.ih-member{ background:var(--raised); border:1px solid var(--line); border-radius:13px; padding:20px; }
.ih-member-top{
  display:flex; justify-content:space-between; gap:10px; flex-wrap:wrap;
  font:11.5px/1.5 var(--f-s); color:var(--muted); margin-bottom:14px; letter-spacing:.3px;
}
.ih-member-top span+span{ text-transform:uppercase; }
.ih-member h3{ font:26px/1.2 var(--f-d); margin-bottom:6px; }
.ih-member p{ color:var(--muted); font:12.5px/1.6 var(--f-s); margin:0 0 13px; }
.ih-member-actions{ display:flex; gap:9px; flex-wrap:wrap; margin-top:18px; }
.ih-demo-feedback{ font:12px/1.6 var(--f-s); color:var(--muted); margin-top:12px; min-height:18px; }
.ih-demo-feedback.bad{ color:var(--stop); }

.ih-role-cards{ display:grid; grid-template-columns:repeat(auto-fit,minmax(230px,1fr)); gap:10px; }
.ih-role-card{
  display:flex; gap:10px; align-items:flex-start; padding:13px;
  border:1px solid var(--line); border-radius:12px; background:var(--raised);
}
.ih-role-card b{ display:block; font:600 13px/1.4 var(--f-s); }
.ih-role-card small{ display:block; color:var(--muted); font:12px/1.5 var(--f-s); margin-top:3px; }

.ih-assignment{ margin-bottom:16px; }
.ih-assignment-meta{
  font:11.5px/1.6 var(--f-s); color:var(--muted); margin:6px 0 0; padding-left:2px;
  display:flex; gap:10px; flex-wrap:wrap; align-items:center;
}
.ih-assignment-meta i{ font-style:normal; opacity:.55; }
.ih-remove{
  border:1px solid var(--firm); border-radius:8px; background:transparent;
  color:var(--ink); font:12px/1.2 var(--f-s); padding:9px 11px; min-height:38px;
  cursor:pointer;
}

.ih-change{
  margin-top:16px; padding:12px 14px; border:1px solid var(--line);
  border-radius:12px; background:var(--sunk); font:12.5px/1.6 var(--f-s);
}
.ih-change p{ margin:0 0 4px; }
.ih-change b{ color:var(--ink); }
.ih-linkbox{
  background:var(--sunk); border:1px solid var(--line); border-radius:10px;
  padding:11px 12px; overflow-wrap:anywhere; font:12px/1.6 var(--f-m);
}

/* The folder sheet. A dialog rather than a page, because it is always opened
   from something — a folder somebody is looking at — and losing that place to
   read who can see it is the wrong trade. */
.ih-sheet{
  position:fixed; inset:0; background:rgba(0,0,0,.42); display:grid;
  place-items:center; padding:16px; z-index:90; overflow:auto;
}
.ih-sheet-card{
  background:var(--ground); border:1px solid var(--line); border-radius:16px;
  padding:20px 22px; width:min(620px,100%); max-height:88vh; overflow:auto;
}
/* Its way out is the one .sheet-head (Done, on the left): every tap here
   applies at once, so there is nothing to cancel and nothing to save. */

@media (max-width:800px){
  .ihx-shell{ grid-template-columns:175px minmax(0,1fr); }
  .ihx-main{ padding:20px 16px; }
  /* The two columns of the access map stack. Reading "what they can do" beside
     "what they cannot reach" is the point of the pair, and two 160px columns
     is not reading either. */
  .ih-grid{ grid-template-columns:1fr; gap:22px; }
  .ihx-title{ font-size:30px; }
}
@media (max-width:520px){
  .ihx{ border-radius:12px; }
  .ihx-top{ padding:15px; }
  /* The rail goes above the content, as two columns of choices rather than one
     long list — five roles down the page is five scrolls before the thing you
     came to do. */
  .ihx-shell{ display:block; }
  .ihx-rail{ border-right:0; border-bottom:1px solid var(--line); padding:14px 11px; }
  .ih-person-list{ display:grid; grid-template-columns:1fr 1fr; gap:6px; }
  .ih-person-list.ih-one{ grid-template-columns:1fr; }
  .ih-person{ margin:0; height:100%; align-items:flex-start; padding:10px 8px; gap:6px; }
  .ih-role-icon{ width:24px; height:26px; }
  .ih-side-note{ display:none; }
  .ihx-main{ padding:18px 14px; }
  .ihx-title{ font-size:28px; }
  .ih-setting,.ih-check{ min-width:100%; }
  /* 16px, so iOS does not zoom the page when somebody taps the address field
     during an invitation. */
  .ih-input{ font-size:16px; }
  .ih-chip{ max-width:112px; }
  .ih-member{ padding:14px; }
  .ih-owner-mark{ font-size:12px; }
}
/* 320px: the narrowest real phone. The owner's crown stays — a narrow screen
   is not a reason to stop saying whose House this is. */
@media (max-width:360px){
  .ih-person-list{ grid-template-columns:1fr; }
  .ihx-title{ font-size:25px; }
  .ih-steps{ gap:8px; }
}

/* The mark for somebody who holds neither the crown nor one of the five roles.
   Their initial, not a borrowed glyph: the five role glyphs mean five roles,
   and a briefcase beside a person who is not a manager is the same kind of
   mistake as a crown beside a person who does not own the House. */
.ih-initial{
  width:26px; height:26px; border-radius:50%; display:grid; place-items:center;
  background:var(--sunk); border:1px solid var(--line); color:var(--muted);
  font:600 12px/1 var(--f-s);
}

/* An action inside a status line. A refusal that names the way forward needs
   somewhere to press, or the person retypes the address with a typo in it. */
.ih-inline-do{
  display:inline-block; margin-left:6px; border:1px solid var(--firm);
  border-radius:8px; background:var(--raised); color:var(--ink);
  font:12px/1.2 var(--f-s); padding:8px 11px; min-height:36px; cursor:pointer;
}
.ih-inline-do:hover{ border-color:var(--accent); }
/* The artwork card's picture is the one gallery (public/viewer.js): the whole image, square frame. */
.lbcard .art-pswp-host{position:relative;width:100%;aspect-ratio:1;border-radius:15px 15px 0 0;overflow:hidden;background:var(--lift)}.lbcard .art-pswp-host .pswp{position:absolute;--pswp-root-z-index:auto;z-index:auto;--pswp-bg:var(--lift)}

/* The song and release covers open the artwork viewer. */
[data-open-art]{cursor:zoom-in}
[data-open-art]:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* The Housekeeper's new-song question (public/app/housekeeper.js): two
   answers under the question, never squeezed beside it, and "Not a new
   song" opens the House's songs underneath as buttons to tap. */
.row.hkask{grid-template-columns:1fr}
.row.hkask .rt{flex-wrap:wrap}
.row.hkask .rt .act{width:auto;margin:0;padding:10px 16px}
.row.hkask .rt .tb{padding:0 14px}
.hkpick{display:flex;flex-direction:column;gap:10px}
.hkpick[hidden]{display:none}
.hkpick .sb{margin:0}
.hksongs{display:flex;flex-wrap:wrap;gap:8px;max-height:240px;overflow-y:auto}
.hksongs .tb{padding:0 12px}
.hksongs .tb[hidden]{display:none}
/* Item 5: the artwork note says something only after an upload has news. */
#artnote:empty{display:none}

/* "Your part today" as a to-do list (Phase 3 punch list, item 4): compact
   rows, the verb first, one action each, and a chevron -- never the diagonal
   arrow, which says "leaves the app". */
.room-tasks{list-style:none;margin:0;padding:0}
.room-taskrow{border-top:1px solid var(--room-rule)}
.room-taskrow .room-task{border-top:0;min-height:60px;padding:0;gap:12px}
.room-task-t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.room-task-t b{font-weight:600}
.room-task-t small{display:inline;font:400 14px var(--f-s);color:var(--room-soft);margin:0}

/* The pushed fix's navigation bar: the back button names where it returns. */
.fixbar{position:fixed;left:0;right:0;top:var(--hq-vv-top, 0px);z-index:119;display:flex;align-items:center;gap:10px;
  min-height:48px;padding:env(safe-area-inset-top, 0px) max(12px, env(safe-area-inset-right, 0px)) 0
  max(8px, env(safe-area-inset-left, 0px));background:var(--chrome, var(--ground));
  -webkit-backdrop-filter:saturate(1.2) blur(8px);backdrop-filter:saturate(1.2) blur(8px);
  border-bottom:1px solid var(--line)}
.fixbar-back{display:inline-flex;align-items:center;gap:4px;min-height:44px;padding:0 8px;border:0;
  background:none;color:var(--accent);font:500 16px var(--f-s);cursor:pointer;white-space:nowrap}
.fixbar-back span{font-size:26px;line-height:1;margin-top:-3px}
.fixbar-t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font:600 15px var(--f-s);color:var(--ink);text-align:right}

/* ======================================== no dead space at the top of a page
   Phase 3 punch list, items 3 and 10 (Jay, 2026-09-25). On every tab and
   every detail screen, content begins about 24-32px under the nav bar. A
   page photograph or a hero gradient lives BEHIND the title, never above it
   as empty space, and nothing reserves room for artwork that is not there.
   Wide screens keep their own compositions (from 1200px the page photograph
   sits beside the column and pads nothing). */
@media (max-width:1199px){
  #view.haswash{padding-top:28px}
  .pagewash{height:260px}
  .homebody{padding-top:28px}
  .hero{height:300px}
}
/* Home's photograph, on a phone (build 10, item 1). The rule above stands:
   the greeting is the first thing under the nav bar and nothing sits above
   it. The photograph comes straight after the greeting, as a picture in the
   column -- framed, clear, no veil -- rather than a background with the
   greeting, both buttons and the upcoming rows laid over it, which is how it
   ended up a dark smudge that also painted over the nav bar's lower edge.

   The photograph is the page's sibling of .homebody (the desktop composition
   puts it in its own column), so on a phone .homebody steps aside
   (display:contents) and .home orders the pieces: greeting, photograph, the
   rest in their own order. Flex items do not collapse margins the way the
   block column did, so the two pairs that collapsed there keep their gaps
   here: the buttons to "Upcoming Releases" (30px) and, with nothing
   upcoming, the buttons to the ways in (15px). */
@media (max-width:899px){
  .home{display:flex;flex-direction:column}
  .homebody{display:contents}
  /* What .homebody's own stacking did: text above the decorated looks' art. */
  .homebody > *{position:relative;z-index:2}
  /* The decorated looks' art starts at the nav bar, not 14px over it. */
  .stage{top:0}
  .greet{order:-2;margin:28px 0 14px}
  .hero{order:-1;position:relative;top:0;left:0;width:auto;transform:none;
    height:236px;margin:0 0 17px;border-radius:14px;z-index:0;
    -webkit-mask-image:none;mask-image:none}
  .heroveil{display:none}
  /* Nothing is kept for a photograph that did not arrive. */
  .hero.nophoto{display:none}
  .acts{margin-bottom:0}
  .acts + .ways{margin-top:15px}
}
/* The release hero: no minimum height on a phone, and no room kept for a
   print that is not there. */
@media (max-width:999px){
  .rw-hero{min-height:0;padding-top:24px}
}
.rw-hero:not(:has(.rw-pola)) .rw-id{padding-right:0;max-width:none}
.rw-hero.noart{min-height:0}

/* ------------------------------------------------------------ the document viewer
   #/doc/<id> (public/app/docview.js, Jay's TestFlight note of September 27):
   the House's own chrome around a document -- back, its name, ··· -- and the
   document filling the rest. No address bar, no download question. */
.docview{display:flex;flex-direction:column;min-height:calc(100dvh - 160px)}
.dochead{display:grid;grid-template-columns:44px minmax(0,1fr) 44px;align-items:center;gap:6px;
  margin:0 0 10px;position:sticky;top:env(safe-area-inset-top, 0px);z-index:2;background:var(--ground);padding:4px 0}
/* Scrolled, the bar stays below the status bar, and what scrolls under it
   does not show through the strip above it. */
.dochead::before{content:"";position:absolute;left:0;right:0;bottom:100%;height:env(safe-area-inset-top, 0px);
  background:var(--ground)}
.docback{width:44px;height:44px;display:flex;align-items:center;justify-content:center;
  border:0;background:none;color:var(--accent);border-radius:999px;cursor:pointer;padding:0}
.docback svg{transform:scaleX(-1)}
.docback:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.doctitle{margin:0;font:600 16px/1.3 var(--f-s);color:var(--ink);text-align:center;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.doccovers{display:flex;align-items:center;gap:8px;margin:0 0 12px;font:400 13.5px/1.4 var(--f-s);color:var(--muted)}
.doccovers svg{flex:none;color:var(--accent)}
.doccovers a{color:var(--ink)}
.docnote{font:400 13px/1.45 var(--f-s);color:var(--muted);margin:0 0 12px}
/* The Approved mark on a document (R13). */
.docapproved{margin:0 0 12px}
.docapproved[hidden]{display:none}
.docbody{flex:1;display:flex;flex-direction:column}
.docframe{flex:1;width:100%;min-height:70dvh;border:0;border-radius:10px;background:var(--raised)}
.docimg{max-width:100%;height:auto;border-radius:10px;align-self:center}
.docpage{background:var(--raised);border:1px solid var(--line);border-radius:12px;
  padding:22px 20px;font:400 15.5px/1.6 var(--f-s);color:var(--ink);overflow-wrap:anywhere}
.docpage p{margin:0 0 .85em}
.docpage p:last-child{margin-bottom:0}
.docempty{display:flex;flex-direction:column;align-items:center;gap:10px;text-align:center;
  padding:48px 16px;color:var(--muted)}
.docempty svg{color:var(--accent)}
/* The writing hour's row (Settings): a button drawn as a row, chevron last. */
button.nmrow.nmhour{width:100%;background:none;border:0;border-bottom:1px solid var(--line);
  text-align:left;font:inherit;color:inherit;cursor:pointer}
button.nmrow.nmhour[hidden]{display:none}

/* Your writing hour (Jay's approved redesign, September 29): a sheet from the
   bottom of the glass, the learned hour as one card, then a wheel of hours
   and AM/PM (public/app/writing-hour.js). It rides the action sheet's own
   layer and scrim (.hq-as, shell.css); everything drawn here is a token. */
.hq-as.wh{padding:0}
.hq-as.wh .hq-as-scrim{cursor:pointer}
/* The top of the sheet is its handle: dragged down, it lets the sheet go. */
.wh-grab,.wh-title,.wh-sub{touch-action:none}
.wh-card{position:relative;width:100%;max-width:480px;background:var(--raised);color:var(--ink);
  border-radius:28px 28px 0 0;padding:10px 22px calc(22px + env(safe-area-inset-bottom, 0px));
  max-height:calc(100dvh - 12px - env(safe-area-inset-top, 0px));overflow-y:auto;overscroll-behavior:contain;
  transform:translateY(40px);opacity:0;transition:transform .3s ease,opacity .25s;outline:0;
  box-shadow:0 -8px 36px rgba(0,0,0,.22)}
.hq-as.open .wh-card{transform:none;opacity:1}
@media (min-width:768px){ .wh-card{border-radius:28px;padding-bottom:26px} }
.wh-grab{width:40px;height:5px;border-radius:3px;background:var(--firm);margin:2px auto 16px;
  box-sizing:content-box;padding:8px 40px;margin-top:-6px;margin-bottom:8px;background-clip:content-box}
.wh-title{margin:0;font:600 24px/1.2 var(--f-s);letter-spacing:-.3px;text-align:center;color:var(--ink)}
.wh-sub{margin:6px 0 20px;text-align:center;font:400 14px/1.5 var(--f-s);color:var(--muted)}
.wh-smart{width:100%;display:flex;align-items:center;gap:14px;padding:16px 18px;text-align:left;
  font:inherit;color:var(--ink);cursor:pointer;border-radius:20px;
  background:color-mix(in srgb, var(--good) 12%, var(--raised));
  border:1.5px solid color-mix(in srgb, var(--good) 38%, var(--raised));
  transition:border-color .2s,background .2s}
.wh-check{flex:none;width:26px;height:26px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;background:var(--good);color:var(--onsem);font:700 15px/1 var(--f-s);
  transition:background .2s,color .2s}
.wh-t{font:600 16.5px/1.3 var(--f-s)}
.wh-t small{display:block;margin-top:2px;font:400 13px/1.35 var(--f-s);
  color:color-mix(in srgb, var(--good) 55%, var(--muted))}
.wh-smart.off{background:var(--sunk);border-color:var(--line)}
.wh-smart.off .wh-check{background:var(--line);color:transparent}
.wh-smart.off .wh-t small{color:var(--faint)}
.wh-smart:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
.wh-or{display:flex;align-items:center;gap:12px;margin:20px 4px 14px;color:var(--faint);
  font:500 12.5px/1 var(--f-s);letter-spacing:.04em;text-transform:uppercase}
.wh-or::before,.wh-or::after{content:"";flex:1;border-top:1px solid var(--line)}
.wh-wheels{position:relative;display:flex;justify-content:center;gap:8px;padding:6px 0;
  background:var(--sunk);border:1px solid var(--line);border-radius:20px;overflow:hidden;
  transition:opacity .2s;will-change:opacity}
.wh-wheels.dim{opacity:.45}
.wh-wheel{height:216px;overflow-y:auto;scroll-snap-type:y mandatory;scrollbar-width:none;
  -webkit-overflow-scrolling:touch;overscroll-behavior:contain;outline:0;touch-action:pan-y}
.wh-wheel::-webkit-scrollbar{display:none}
.wh-wheel.hours{width:120px}
.wh-wheel.halves{width:110px}
.wh-wheel:focus-visible .wh-opt.sel{text-decoration:underline;text-underline-offset:5px}
.wh-sp{height:86px;scroll-snap-align:center}
.wh-opt{height:44px;display:flex;align-items:center;justify-content:center;scroll-snap-align:center;
  font:400 22px/1 var(--f-s);color:var(--off);transition:color .15s;user-select:none;
  -webkit-user-select:none;cursor:pointer}
.wh-opt.sel{color:var(--ink);font-weight:600}
.wh-band{position:absolute;left:18px;right:18px;top:50%;height:44px;margin-top:-22px;
  border-top:1px solid var(--firm);border-bottom:1px solid var(--firm);pointer-events:none}
.wh-fade{position:absolute;left:0;right:0;height:70px;pointer-events:none}
.wh-fade.top{top:0;background:linear-gradient(var(--sunk), transparent)}
.wh-fade.bot{bottom:0;background:linear-gradient(transparent, var(--sunk))}
/* Two lines held open whichever sentence is showing: the card must not change
   height under her finger when touching the wheels changes the words. */
.wh-preview{margin:18px 0 20px;min-height:2.8em;display:grid;place-items:center;text-align:center;
  font:italic 400 17px/1.4 var(--f-l);color:var(--muted)}
.wh-preview b{font-style:normal;font-weight:600;color:var(--good)}
/* Cream after dark, the ink itself by day: the sheet's one solid button. */
.wh-done{width:100%;padding:16px 0;border:0;border-radius:999px;cursor:pointer;
  background:var(--ink);color:var(--raised);font:600 17px/1 var(--f-s)}
.wh-done:disabled{opacity:.6;cursor:default}
.wh-done:focus-visible{outline:2px solid var(--focus);outline-offset:3px}
.wh-kept{margin:14px 0 0;min-height:22px;text-align:center;font:400 18px/1.3 var(--f-l);
  color:var(--good);opacity:0;transition:opacity .4s}
.wh-kept.show{opacity:1}
.wh-kept.bad{color:var(--stop);font:400 14px/1.45 var(--f-s)}

/* The song page's lyrics, once (Jay, September 27): the saved copy, a quiet
   Edit and Versions beneath it, and the original only inside the tray. */
.lyrquiet{display:flex;gap:18px;margin:8px 0 0}
.lyrquiet[hidden],.lyrtray[hidden],.lyrbox[hidden],.lyr[hidden]{display:none}
.lyrtray{margin:10px 0 0;padding:12px 14px;border-radius:11px;background:var(--sunk)}
.lyrtray-k{margin:0 0 6px;font-family:var(--f-l);font-size:11px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--faint)}
.lyrtray .lyr{margin:0;padding:0;border:0;background:none;max-height:none}
details.lyprep{margin:10px 0 0}
details.lyprep summary{font-size:13px;color:var(--muted);cursor:pointer;padding:4px 0}

/* Every team-plan step opens (Jay, September 27): the rows on the release page
   and the plan's own rows are tappable, each with its trailing chevron, and
   the "nobody accountable" warning goes straight to those steps. */
.blk.tap{cursor:pointer;align-items:center}
.blk.tap:active{background:var(--sunk)}
a.blkwarn{display:block;text-decoration:none}
.blkwarn-go{white-space:nowrap;color:var(--accent)}
.ev .body[data-step]{cursor:pointer}
.evmore{color:var(--faint);padding:0 2px 0 6px}
.lbl.stk{margin:16px 0 8px}
.stpick{display:flex}
.strows{margin:16px 0 0}

/* Everybody Eats: the Handshakes row in a song's Ownership (app/songs.js). A
   row that opens something carries a chevron. */
.hk-entry{display:flex;align-items:center;gap:12px;margin:14px 0 0;padding:12px 14px;
  border:1px solid var(--line);border-radius:11px;background:var(--raised);color:var(--ink);
  text-decoration:none;-webkit-tap-highlight-color:transparent}
.hk-entry:active{background:var(--sunk)}
.hk-entry-t{flex:1;min-width:0}
.hk-entry-t b{display:block;font:500 16px/1.3 var(--f-s)}
.hk-entry-t small{display:block;margin-top:2px;font:400 13px/1.35 var(--f-s);color:var(--muted)}

/* A suggestion on its own page (app/suggestions.js), under the quiet rule: the
   same row, with × beside it to put it away for 30 days. */
.hk-entry.sug-card{padding:0;gap:0}
.sug-card-go{flex:1;min-width:0;display:flex;align-items:center;gap:12px;padding:12px 6px 12px 14px;
  color:inherit;text-decoration:none;border-radius:11px 0 0 11px}
.sug-card-go:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.sug-x{flex:none;display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;
  margin:0 4px 0 0;padding:0;border:0;border-radius:50%;background:none;color:var(--faint);cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.sug-x:active{background:var(--sunk)}
.sug-x:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}

/* House Admin -> Suggested actions (app/suggestions.js; ready/suggested-actions-
   mockup.html, approved 2026-10-01). Calm: the ground, white cards, a dark
   pill for the one tap, and Later in the quietest ink there is. */
.sug{max-width:620px;margin:0 auto;padding:6px 0 28px;font-family:var(--f-s);color:var(--ink)}
.sug-top{display:flex;align-items:center;justify-content:space-between;padding:6px 2px 18px}
.sug-back,.sug-top-pad{flex:none;width:38px;height:38px}
.sug-back{display:inline-flex;align-items:center;justify-content:center;border:1.5px solid var(--firm);
  border-radius:50%;color:var(--ink);text-decoration:none}
.sug-back svg{transform:scaleX(-1)}
.sug-back:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.sug-house{font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--faint)}
.sug-h{margin:2px 0 8px;font-family:var(--f-l);font-weight:500;font-size:34px;line-height:1.1;letter-spacing:-.01em}
.sug-lede{margin:0 0 6px;font-size:15px;line-height:1.5;color:var(--muted)}
.sug-count{margin:0 0 20px;font-size:13px;color:var(--faint)}
.sug-group{margin:0 0 26px}
.sug-group-head{display:flex;align-items:center;gap:10px;margin:0 0 10px;padding:0 4px}
.sug-group-glyph{display:inline-flex;align-items:center;justify-content:center;flex:none;width:34px;height:34px;
  border-radius:50%;background:var(--cta);color:var(--oncta);font-size:16px}
.sug-group-name{margin:0;font-family:var(--f-l);font-size:21px;font-weight:500}
.sug-group-n{margin-left:auto;font-size:13px;color:var(--muted);background:var(--sunk);border-radius:999px;padding:3px 10px}
.sug-card-list{background:var(--raised);border:1px solid var(--line);border-radius:18px;overflow:hidden}
.sug-row{display:flex;align-items:center;gap:12px;padding:15px 16px;cursor:pointer;
  transition:opacity .35s,transform .35s;-webkit-tap-highlight-color:transparent}
.sug-row + .sug-row{border-top:1px solid color-mix(in srgb, var(--line) 70%, transparent)}
.sug-row.dismissing{opacity:0;transform:translateX(24px)}
.sug-row-text{flex:1;min-width:0}
.sug-row-title{margin:0 0 3px;font-size:16px;font-weight:600;line-height:1.3}
.sug-row-why{font-size:13.5px;line-height:1.4;color:var(--muted)}
.sug-cta{flex:none;display:inline-flex;align-items:center;min-height:34px;padding:0 14px;border-radius:999px;
  background:var(--cta);color:var(--oncta);font-size:14px;font-weight:600;text-decoration:none}
.sug-cta:focus-visible,.sug-later:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.sug-later{flex:none;min-height:44px;padding:0 4px;border:0;background:none;color:var(--faint);
  font:400 13px var(--f-s);cursor:pointer}
.sug-foot{margin:22px 0 0;padding:16px 18px;border-radius:16px;background:var(--sunk);
  font-size:13.5px;line-height:1.55;color:var(--muted)}
.sug-foot strong{color:var(--ink)}
@media (prefers-reduced-motion:reduce){ .sug-row{transition:none} }


/* ===================================================== First, in two screens
   (app/share.js; Jay, October 3, 2026: the approved v3 concept and the
   beauty-sweep-2 mockup). Screen 1 picks the music in Music's compact rows;
   screen 2 composes the link as the listener will get it. One action at the
   foot, in the thumb zone. Tokens only, so every look carries it. */
.fs{--fs-gap:color-mix(in srgb, var(--ground) 70%, var(--line));padding-bottom:calc(var(--fs-dockh, 88px) + 16px)}
.fs .sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.fs-step{margin:0;float:right;font:600 13px/34px var(--f-s);color:var(--muted);letter-spacing:.02em}
.fs-title{margin:0 0 14px;font:400 30px/1.12 var(--f-l);color:var(--ink);letter-spacing:-.005em}
.fs-note-rel{margin:0 0 12px;font:400 13.5px/1.45 var(--f-s);color:var(--soft)}
.fs-h{display:flex;justify-content:space-between;align-items:baseline;gap:12px;margin:24px 0 8px;
  font:600 13px var(--f-s);letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.fs-h span{font-weight:500;letter-spacing:0;text-transform:none}
.fs-foot{margin:7px 0 0;font:400 13px/1.4 var(--f-s);color:var(--muted)}
.fs-foot.bad{color:var(--stop)}
.fs-grp{background:var(--raised);border-radius:12px;box-shadow:0 0 0 1px var(--line);overflow:hidden}

/* the search and the filter: they stay put while the list scrolls */
.fs-find{position:sticky;top:env(safe-area-inset-top, 0px);z-index:5;margin:0 -16px;padding:4px 16px 10px;
  background:var(--ground);box-shadow:0 1px 0 var(--line)}
.fs-search{display:flex;align-items:center;gap:8px;height:42px;padding:0 12px;border-radius:12px;
  background:var(--sunk);color:var(--faint)}
.fs-search svg{flex:none}
.fs-search input{flex:1;min-width:0;height:100%;border:0;background:none;color:var(--ink);
  font:400 16px var(--f-s);-webkit-appearance:none;appearance:none;outline:0}
.fs-search input::placeholder{color:var(--faint)}
.fs-search:focus-within{box-shadow:0 0 0 2px var(--accent)}
.fs-filt{display:flex;align-items:center;gap:8px;margin-top:10px}
.fs-count{margin-left:auto;font:400 13px var(--f-s);color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap}

/* artwork */
.fs-art{position:relative;flex:none;display:grid;place-items:center;width:52px;height:52px;border-radius:14px;
  overflow:hidden;background:var(--tile, var(--sunk));color:var(--muted)}
.fs-art img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.fs-art.sm{width:40px;height:40px;border-radius:10px}
.fs-n{position:absolute;right:3px;bottom:3px;min-width:18px;height:18px;padding:0 5px;border-radius:9px;
  background:color-mix(in srgb, var(--ink) 78%, transparent);color:var(--ground);font:700 11px/18px var(--f-s);text-align:center}

/* THE STAGE'S COLOR, ONE LANGUAGE (Jay, October 4, 2026): by how finished it
   is -- green, amber, the early ink -- on First's bars and pills and on every
   stage bar and square in Music alike. app/tones.js says which status is
   which tone; the tone's color is the look's own, so every look and both
   themes are covered here and nowhere else. */
.stage-done{--stage-on:var(--good)}
.stage-mid{--stage-on:var(--warn)}
.stage-early{--stage-on:var(--mauve)}
.stage-stop{--stage-on:var(--stop)}

/* A song's stage wherever a song is listed outside Music (app/stage-bars.js):
   Music's six bars, the same size and the same dim unfilled bars, then the
   word. Read-only, so no button box around it. */
.sstage{display:inline-flex;align-items:center;gap:7px;min-width:0;vertical-align:middle}
.sbars{flex:none;display:inline-flex;align-items:center;gap:3px}
.sbars i{width:5px;height:16px;border-radius:2.5px;background:var(--firm);opacity:.5}
.sbars i.on{background:var(--stage-on);opacity:1}
.sstage-w{font-weight:600;color:var(--ink);white-space:nowrap}
.sstage-w.unset{font-weight:400;color:var(--muted)}

/* Music's compact row */
.fs-list{margin:0 -16px;padding:0;list-style:none}
.fs-list li{margin:0}
.fs-r{position:relative;display:flex;align-items:center;gap:12px;width:100%;min-height:80px;padding:10px 16px;
  border:0;background:none;color:inherit;font:inherit;text-align:left;cursor:pointer;-webkit-tap-highlight-color:transparent}
.fs-list li + li .fs-r::before{content:"";position:absolute;top:0;left:80px;right:0;height:1px;background:var(--line)}
.fs-r:active{background:var(--sunk)}
.fs-r.on{background:color-mix(in srgb, var(--accent) 6%, transparent)}
.fs-r:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
.fs-tx{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}
.fs-ti{font:500 16px/1.25 var(--f-s);color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fs-ti.serif{font:400 19px/1.2 var(--f-l)}
.fs-su{display:flex;align-items:center;gap:7px;min-width:0;font:400 12.5px/18px var(--f-s);color:var(--muted);white-space:nowrap}
.fs-su > span:not(.fs-stg){overflow:hidden;text-overflow:ellipsis}
.fs-su > b{flex:none;font-weight:600;color:var(--soft)}
.fs-dot{flex:none;font-style:normal;color:var(--faint)}
/* Round 5 (October 4, 2026): a First row is the song's own line (its six bars
   and its word, drawn by stage-bars.js) over the recording's line (v06 .
   [take chip] . 3 takes . Released). The take's stage is a property of the
   recording, never the row's lead. */
.fs-lead{display:flex;min-width:0}
.fs-add{flex:none;display:grid;place-items:center;width:32px;height:32px;border-radius:50%;
  border:1.6px solid var(--firm);color:var(--muted)}
.fs-r.on .fs-add{background:var(--accent);border-color:var(--accent);color:var(--onacc, var(--raised))}
.fs-empty{margin:8px 0;color:var(--muted);font:italic 400 15px var(--f-s)}

/* what she chose, with its takes */
.fs-cr{position:relative;display:flex;align-items:center;gap:12px;min-height:60px;padding:8px 4px 8px 12px}
.fs-cg + .fs-cg .fs-cr::before{content:"";position:absolute;top:0;left:64px;right:0;height:1px;background:var(--line)}
/* The play order, dragged (share.js bindPlayOrder): the row is the handle, so
   a long press on it must not select its words or open iOS's callout. The
   lifted song is the long-press menu's lift (.hqm-lift): eased forward and
   shadowed; the others part with a short ease to show where it will land. */
.fs-cr{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
.fs-grp.fs-order{overflow:visible}
.fs-cg{position:relative;background:var(--raised);border-radius:12px}
.fs-cg > .fs-tk{border-radius:0 0 12px 12px}
.fs-sorting .fs-cg{transition:transform .18s cubic-bezier(.2,.8,.3,1)}
.fs-sorting .fs-cg.fs-lift{z-index:2;transition:none;box-shadow:0 14px 40px rgba(56,36,47,.22)}
html[data-theme="dark"] .fs-sorting .fs-cg.fs-lift{box-shadow:0 16px 44px rgba(0,0,0,.55)}
.fs-sorting .fs-cg.fs-lift .fs-cr::before,.fs-sorting .fs-cg.fs-lift + .fs-cg .fs-cr::before{opacity:0}
@media (prefers-reduced-motion:reduce){ .fs-sorting .fs-cg{transition:none} }
.fs-takes{flex:none;display:inline-flex;align-items:center;gap:4px;height:32px;padding:0 10px 0 12px;border:0;border-radius:16px;
  background:color-mix(in srgb, var(--lift) 70%, var(--raised));color:var(--ink);font:600 13.5px var(--f-s);cursor:pointer;position:relative}
.fs-takes::after{content:"";position:absolute;inset:-6px -2px}
.fs-takes.open{background:var(--accent);color:var(--onacc, var(--raised))}
.fs-takes:disabled{opacity:.6}
.fs-one{flex:none;padding:0 6px;font:500 13px var(--f-s);color:var(--faint)}
.fs-x{flex:none;display:grid;place-items:center;width:44px;height:44px;border:0;background:none;color:var(--faint);cursor:pointer}
.fs-x:active{color:var(--ink)}
.fs-tk{background:var(--sunk);padding:4px 0 8px;border-top:1px solid var(--line)}
.fs-tkr{position:relative;display:flex;align-items:center;gap:12px;width:100%;min-height:52px;padding:6px 16px 6px 64px;
  border:0;background:none;color:inherit;font:inherit;text-align:left;cursor:pointer}
.fs-tkr + .fs-tkr::before{content:"";position:absolute;top:0;left:100px;right:0;height:1px;background:var(--line)}
.fs-tkr.off{opacity:.55;cursor:default}
.fs-ck{flex:none;display:grid;place-items:center;width:24px;height:24px;border-radius:50%;border:1.6px solid var(--firm);color:transparent}
.fs-ck.on{background:var(--accent);border-color:var(--accent);color:var(--onacc, var(--raised))}
.fs-tkl{flex:1;min-width:0}
.fs-tkl b{display:block;font:600 15.5px/1.3 var(--f-s);color:var(--ink)}
.fs-tkl small{display:block;margin-top:2px;font:400 12.5px/1.35 var(--f-s);color:var(--muted)}
.fs-cur{flex:none;padding:3px 7px;border-radius:6px;font:700 11px var(--f-s);letter-spacing:.04em;text-transform:uppercase;
  background:color-mix(in srgb, var(--good) 15%, transparent);color:var(--good)}
.fs-tkhint{margin:0;padding:6px 16px 2px 64px;font:400 12.5px/1.4 var(--f-s);color:var(--muted)}

/* the one action, in the thumb zone */
.fs-dock{position:fixed;left:0;right:0;bottom:var(--fs-tabs, 0px);z-index:39;padding:12px 16px 12px;
  background:color-mix(in srgb, var(--ground) 88%, transparent);
  -webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);box-shadow:0 -1px 0 var(--line)}
.fs-dock > *{max-width:728px;margin-left:auto;margin-right:auto}
.fs-cta{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;height:52px;border:0;border-radius:14px;
  background:var(--cta);color:var(--oncta);font:600 17px var(--f-s);cursor:pointer}
.fs-cta:disabled{background:var(--sunk);color:var(--faint);box-shadow:inset 0 0 0 1px var(--line);cursor:default}
/* Waiting on her answer, and still a button: it takes her to the row. */
.fs-cta.need{background:color-mix(in srgb, var(--accent) 12%, var(--raised));color:var(--accent);
  box-shadow:inset 0 0 0 1.5px color-mix(in srgb, var(--accent) 45%, transparent)}
.fs-cta:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
.fs-ctn{min-width:24px;height:24px;padding:0 7px;border-radius:12px;font-size:14px;line-height:24px;
  background:color-mix(in srgb, var(--oncta) 22%, transparent)}
.fs-dockhint{margin:8px 0 0;text-align:center;font:400 12.5px/1.35 var(--f-s);color:var(--muted)}

/* screen 2: the cover, as the listener sees it */
.fs-cover{display:flex;flex-direction:column;align-items:center;text-align:center}
.fs-big{display:grid;place-items:center;width:212px;height:212px;border-radius:16px;overflow:hidden;
  background:var(--sunk);color:var(--faint);box-shadow:0 18px 40px color-mix(in srgb, var(--ink) 22%, transparent)}
.fs-big img{width:100%;height:100%;object-fit:cover;display:block}
.fs-big.none{box-shadow:inset 0 0 0 1px var(--line)}
.fs-ltitle{display:flex;align-items:center;justify-content:center;gap:6px;width:100%;margin-top:14px;color:var(--faint)}
.fs-ltitle input{width:auto;min-width:6ch;max-width:calc(100% - 28px);field-sizing:content;border:0;border-radius:8px;
  background:none;padding:2px 4px;color:var(--ink);font:400 28px/1.15 var(--f-l);text-align:center;outline:0}
.fs-ltitle input::placeholder{color:var(--faint);font-style:italic}
.fs-ltitle input:focus{background:var(--sunk)}
.fs-by{margin:4px 0 0;font:400 14px var(--f-s);color:var(--muted)}
.fs-strip{display:flex;gap:10px;margin:16px -16px 0;padding:6px 16px 4px;overflow-x:auto;scrollbar-width:none}
.fs-strip::-webkit-scrollbar{display:none}
.fs-th{flex:none;display:flex;flex-direction:column;align-items:center;gap:5px;width:62px;padding:0;border:0;background:none;
  color:var(--muted);font:400 11.5px var(--f-s);cursor:pointer}
.fs-thb{position:relative;display:grid;place-items:center;width:58px;height:58px;border-radius:12px;overflow:hidden;
  background:var(--sunk);color:var(--soft);box-shadow:inset 0 0 0 1.5px var(--firm)}
.fs-thb img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.fs-none{font:600 12px var(--f-s)}
.fs-thl{max-width:62px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fs-th.on .fs-thb{box-shadow:0 0 0 2.5px var(--ground),0 0 0 4.5px var(--accent)}
.fs-th.on{color:var(--ink);font-weight:600}
.fs-th:focus-visible .fs-thb{outline:2px solid var(--focus);outline-offset:3px}

/* who it is for */
.fs-chips{display:flex;gap:8px;margin:0 -16px;padding:2px 16px 4px;overflow-x:auto;scrollbar-width:none}
.fs-chips::-webkit-scrollbar{display:none}
.fs-preset{margin:10px 0 0;padding:10px 12px;border-radius:12px;font:400 13.5px/1.4 var(--f-s);color:var(--soft);
  background:color-mix(in srgb, var(--accent) 7%, transparent)}
.fs-preset[hidden]{display:none}
.fs-namegrp{margin-top:0;transition:box-shadow .3s}
/* Who it is for: the one required answer on the screen reads as an action
   until it is given -- tinted in the brand color, with a Required badge -- and
   is a plain row with their name and glyph once it is. */
.fs-who.needs,.fs-whonew.needs{background:color-mix(in srgb, var(--accent) 10%, var(--raised))}
.fs-who.needs .fs-k{color:var(--accent);font-weight:600}
.fs-whonew.needs > span{color:var(--accent);font-weight:600}
.fs-whoav{flex:none;display:grid;place-items:center;width:32px;height:32px;border-radius:50%;color:var(--accent)}
.fs-who.needs .fs-whoav{background:color-mix(in srgb, var(--accent) 16%, transparent)}
.fs-whoav.named{color:inherit}
.fs-k.set{color:var(--ink)}
.fs-req{flex:none;padding:3px 8px;border-radius:999px;background:var(--accent);color:var(--onacc, var(--raised));
  font:700 11.5px var(--f-s);letter-spacing:.03em;text-transform:uppercase}
.fs-req[hidden]{display:none}
.fs-whonew[hidden]{display:none}
.fs-namegrp.nudge{animation:fs-nudge .9s ease-out}
@keyframes fs-nudge{0%{box-shadow:0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent)}
  100%{box-shadow:0 0 0 10px transparent}}
/* A person in a list: photo, else initials, in a small circle. */
.fs-pg{position:relative;display:grid;place-items:center;width:28px;height:28px;border-radius:50%;overflow:hidden;
  background:color-mix(in srgb, var(--accent) 14%, var(--raised));color:var(--accent);font:600 11.5px var(--f-s);letter-spacing:.02em}
.fs-pg img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.fs-whoav .fs-pg{width:32px;height:32px;font-size:12.5px}

/* rows */
.fs-row{position:relative;display:flex;align-items:center;gap:12px;width:100%;min-height:50px;margin:0;padding:0 16px;
  border:0;background:none;color:var(--ink);font:400 16px/1.3 var(--f-s);text-align:left;text-decoration:none;cursor:pointer}
.fs-row + .fs-row::before{content:"";position:absolute;top:0;left:16px;right:0;height:1px;background:var(--line)}
.fs-more .fs-row + .fs-row::before{left:52px}
a.fs-row:active,button.fs-row:active{background:var(--sunk)}
.fs-row:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
.fs-row > svg{flex:none;color:var(--accent)}
.fs-k{flex:1;min-width:0}
.fs-k small{display:block;margin-top:2px;font:400 13px/1.35 var(--f-s);color:var(--muted)}
.fs-v{flex:0 1 auto;min-width:0;color:var(--muted);font-size:15.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fs-chev{margin-left:2px}
.fs-field{cursor:text}
.fs-field > span{flex:none;width:96px}
.fs-field input{flex:1;min-width:0;height:48px;border:0;background:none;color:var(--ink);font:400 16px var(--f-s);outline:0}
.fs-field input::placeholder{color:var(--faint)}
.fs-grp .tglrow{padding:10px 16px}
.fs-grp .tglrow + .tglrow{border-top:1px solid var(--line)}
.fs-song{min-height:60px;padding-left:12px}
.fs-song + .fs-song::before{left:64px}
.fs-stg{flex:none;padding:2px 6px;border-radius:5px;font:700 11px var(--f-s);letter-spacing:.03em}
.fs-stg.stage-done{background:color-mix(in srgb, var(--stage-on) 15%, transparent);color:var(--stage-on)}
.fs-stg.stage-mid{background:color-mix(in srgb, var(--stage-on) 18%, transparent);color:var(--stage-on)}
.fs-stg.stage-early{background:color-mix(in srgb, var(--stage-on) 16%, transparent);color:var(--stage-on)}
/* What she sees is what they get: stages off, and the songs say none. */
.fs2:has(#f-stage[aria-checked="false"]) .fs-stg{display:none}

/* the note: a quiet row until she wants it */
.fs-note0{color:var(--faint)}
.fs-note0[hidden]{display:none}
.fs-notebox{padding:12px 16px}
.fs-notebox[hidden]{display:none}
.fs-notebox textarea{display:block;width:100%;min-height:76px;border:0;padding:0;background:none;resize:none;
  color:var(--ink);font:400 16px/1.45 var(--f-s);outline:0;field-sizing:content}
.fs-notebox textarea::placeholder{color:var(--faint)}
.fs-notebar{display:flex;align-items:center;justify-content:space-between;margin-top:10px}
.fs-ji{display:inline-flex;align-items:center;gap:7px;min-height:36px;padding:0 13px 0 10px;border:0;border-radius:18px;
  background:color-mix(in srgb, var(--lift) 70%, var(--raised));color:var(--ink);font:600 14px var(--f-s);cursor:pointer}
.fs-ji:disabled{opacity:.6}
.fs-notebox .impsay{margin:8px 0 0}

/* the link, once it exists */
.fs-done{margin:24px 0 0;padding:16px;border-radius:12px;background:var(--raised);box-shadow:0 0 0 1px var(--line)}
.fs-doneh{margin:0 0 6px;font:400 22px/1.2 var(--f-l);color:var(--ink)}
.fs-done .url{width:100%;margin-top:10px;height:44px;padding:0 12px;border:1px solid var(--line);border-radius:10px;
  background:var(--sunk);color:var(--ink);font:400 14px var(--f-m, var(--f-s))}

/* Bring in files: one card per service, everything about it inside (Session 4,
   Oct 5 2026; the approved mockup). Mark and name on one line, connecting it
   under that, and its default folder nested beneath. */
.svc{background:var(--raised);border:1px solid var(--line);border-radius:16px;margin:14px 0;overflow:hidden}
.svc-top{display:grid;grid-template-columns:40px minmax(0,1fr) auto;gap:12px;align-items:center;padding:16px 16px 14px}
.svc-logo{width:40px;height:40px;border-radius:10px;background:var(--sunk);display:grid;place-items:center}
.svc-logo svg{width:24px;height:24px}
.svc-tx{min-width:0}
.svc-nm{font-family:var(--f-l);font-size:20px;line-height:1.2;color:var(--ink);margin:0}
.svc-sb{font-family:var(--f-s);font-size:12.5px;color:var(--muted);margin:2px 0 0;line-height:1.4}
.svc-on{display:inline-flex;align-items:center;gap:5px;color:var(--good);font:500 12.5px var(--f-s);white-space:nowrap}
.svc-on svg{width:14px;height:14px}
.svc-why{font:400 12.5px/1.5 var(--f-s);color:var(--muted);margin:-6px 16px 14px 68px}
.svc-cta{padding:0 16px 16px}
.svc-cta .act{margin:0}
.svc-nest{border-top:1px solid var(--line);margin-left:68px;padding:12px 16px 14px 0}
.svc-lab{font-family:var(--f-s);font-weight:500;font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);margin:0 0 6px}
.svc-fold{display:grid;grid-template-columns:22px minmax(0,1fr) auto;gap:10px;align-items:center;width:100%;
  appearance:none;background:none;border:0;padding:8px 0;min-height:44px;text-align:left;cursor:pointer;
  color:var(--ink);font:400 15px/1.3 var(--f-s);overflow-wrap:anywhere}
.svc-fold > svg{width:20px;height:20px;color:var(--muted)}
.svc-fold small{display:block;font-size:12px;color:var(--muted);margin-top:1px}
.svc-fold .ph{display:block;color:var(--accent);font-weight:500}
.svc-fold[disabled]{cursor:default;color:var(--faint)}
.svc-fold[disabled] .chev{visibility:hidden}
.svc-scan{margin:10px 0 0}
.svc-scan .act{margin:0}

/* ---- the Approved mark (R13, app/handoff.js): one badge on every screen
   that shows a file, Media's tiles and viewer, the Handoff package. */
/* It sits on pictures, so it carries its own ground: a dark pill with white
   words reads on any photograph and in every look, light or dark. The check
   is the done green the dark looks use. */
.hq-approved{display:inline-flex;align-items:center;gap:3px;padding:3px 7px 3px 5px;border-radius:999px;
  background:var(--approved-ground);color:var(--approved-ink);font:600 10.5px/1 var(--f-s);letter-spacing:.02em;
  white-space:nowrap;pointer-events:none;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.hq-approved svg{width:11px;height:11px;flex:none;color:var(--approved-check)}
/* The release Overview's one row into its Handoff package. */
.rw-hp{margin:18px 0 0;padding:0;overflow:hidden}
.rw-hp .rc-r{display:flex;align-items:center;gap:12px;min-height:52px;padding:12px 16px;
  color:var(--ink);text-decoration:none}
.rw-hp .rc-l{display:flex;align-items:center;gap:10px;flex:1 1 auto;min-width:0}
.rw-hp .rc-t{min-width:0;overflow-wrap:anywhere;font:500 16px/1.3 var(--f-s)}
.rw-hp .rc-t small{display:block;margin-top:2px;font:400 13px/1.35 var(--f-s);color:var(--muted)}
.rw-hp .rc-dot{flex:none;width:9px;height:9px;border-radius:50%;background:var(--stage-on, var(--faint))}

/* ================= Your Houses (#/houses) and one House's list (#/houses/<id>) =================
   The House switcher round (mockup scenes landing, swipe, markall, theo, desk-houses).
   Her page, not a House's: on a phone, IndyHouse's own mark and no tab bar while
   body.hq-your-houses is on (app/your-houses.js). Names, roles and counts only. */
body.hq-your-houses .tabs{display:none}
/* Her page, not a House's: the avatar is hers alone here (scene landing). */
body.hq-your-houses #prof .prof-house,body.hq-your-houses #prof .prof-dot{display:none}
@media (max-width:899px){
  body.hq-your-houses .topbar .mark img{content:url(/indyhouse-wordmark.png);width:118px;height:auto}
}
.yh{font-family:var(--f-s);color:var(--ink);padding-bottom:40px}
.yh-eb{margin:14px 0 0;font:600 12px var(--f-s);letter-spacing:.09em;text-transform:uppercase;color:var(--muted)}
.yh-h1{margin:6px 0 18px;font:400 32px/1.08 var(--f-d);letter-spacing:-.02em;color:var(--ink)}
.yh-lede{margin:0 0 18px;font-size:16px;line-height:1.5;color:var(--soft)}
.yh-rt{flex:1;min-width:0}
.yh .chev.yh-go{flex:none;color:var(--faint)}
.yh-cont{display:flex;align-items:center;gap:14px;width:100%;padding:14px;border:1px solid var(--line);border-radius:18px;
  background:var(--raised);color:var(--ink);text-align:left;font-family:var(--f-s);cursor:pointer}
.yh-cont .hs-face{--s:52px}
.yh-cont b{display:block;font:400 20px/1.2 var(--f-d);letter-spacing:-.01em}
.yh-cont small{display:block;margin-top:3px;font-size:13.5px;color:var(--muted)}
.yh-sec{display:flex;align-items:baseline;justify-content:space-between;margin:22px 0 6px;
  font:600 12px var(--f-s);letter-spacing:.09em;text-transform:uppercase;color:var(--muted)}
.yh-act{border:0;background:none;padding:8px 0;color:var(--link);font:600 14.5px var(--f-s);letter-spacing:0;text-transform:none;cursor:pointer}
.yh-card{border:1px solid var(--line);border-radius:18px;overflow:hidden;background:var(--raised)}
.yh-swipe{position:relative}
.yh-swipe + .yh-swipe::before{content:"";position:absolute;z-index:2;top:0;left:68px;right:0;height:1px;background:var(--line)}
.yh-swipe.hq-swipe > .hq-swipe-under.trail{background:var(--accent);color:var(--onacc);font:700 14px var(--f-s)}
.yh-swipe.hq-swipe.swiping > .hq-swipe-face{background:var(--raised)}
.yh-row{position:relative;display:flex;align-items:center;gap:14px;width:100%;min-height:68px;margin:0;padding:10px 12px 10px 14px;
  border:0;background:var(--raised);color:var(--ink);text-align:left;font-family:var(--f-s);cursor:pointer;-webkit-tap-highlight-color:transparent}
.yh-row:active{background:color-mix(in srgb, var(--accent) 8%, var(--raised))}
@media (hover:hover){ .yh-row:hover{background:color-mix(in srgb, var(--accent) 6%, var(--raised))} }
.yh-row:focus-visible{outline:2px solid var(--focus);outline-offset:-3px}
.yh-row.sel{background:var(--sel);color:var(--onsel)}
.yh-row.sel .yh-n{font-weight:600}
.yh-row.sel .yh-r,.yh-row.sel .yh-w{color:inherit;opacity:.85}
.yh-n{display:block;font:500 16.5px/1.25 var(--f-s);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.yh-r{display:block;margin-top:1px;font-size:13px;line-height:1.35;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.yh-w{display:block;margin-top:1px;font-size:13px;line-height:1.35;color:var(--soft);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.yh-w b{color:var(--accent);font-weight:600}
.yh-pill{flex:none;min-width:24px;height:24px;padding:0 8px;border-radius:12px;background:var(--lift);color:var(--ink);
  font:600 13px/24px var(--f-s);text-align:center}
.yh-pill.do{background:var(--accent);color:var(--onacc)}
.yh-quiet{display:flex;flex-wrap:wrap;gap:8px;margin:2px 0 0}
.yh-chip{display:flex;align-items:center;gap:8px;min-height:44px;padding:5px 12px 5px 5px;border:1px solid var(--line);border-radius:14px;
  background:var(--raised);color:var(--ink);font:500 14.5px var(--f-s);cursor:pointer}
.yh-chip .hs-face{--s:32px}
.yh-chip .chev{margin-left:2px}
.yh-hint{margin:22px 0 0;font-size:13.5px;line-height:1.5;color:var(--muted)}
/* One House's list */
.yh-back{display:inline-flex;align-items:center;gap:2px;margin:0 0 0 -10px;min-height:44px;padding:0 6px;
  color:var(--link);font:500 16px var(--f-s);text-decoration:none}
.yh-hh{display:flex;align-items:center;gap:14px;margin:6px 0 4px}
.yh-hh .hs-face{--s:58px}
.yh-hh h1{margin:0;font:400 29px/1.08 var(--f-d);letter-spacing:-.02em;color:var(--ink)}
.yh-hh p{margin:4px 0 0;font-size:14px;color:var(--muted)}
.yh-list{border-top:1px solid var(--line)}
.yh-item{position:relative;display:flex;align-items:center;gap:13px;width:100%;min-height:66px;padding:12px 2px 12px 14px;border:0;
  border-bottom:1px solid var(--line);background:none;color:var(--ink);text-align:left;font-family:var(--f-s);cursor:pointer}
.yh-dot{position:absolute;left:0;top:50%;width:8px;height:8px;margin-top:-4px;border-radius:50%;background:var(--accent)}
.yh-item.read{color:var(--soft)}
.yh-item.read .yh-dot{display:none}
.yh-ic{flex:none;width:36px;height:36px;border-radius:10px;display:grid;place-items:center;background:var(--tile);color:var(--accent)}
.yh-ic.do{background:var(--accent);color:var(--onacc)}
.yh-item b{display:block;font-size:15.5px;font-weight:500;line-height:1.3}
.yh-item small{display:block;margin-top:2px;font-size:13px;line-height:1.35;color:var(--muted)}
.yh-open{margin:26px 0 0}
.yh-open .btn{width:100%;min-height:54px;font-size:17px}
/* On a computer: the Houses on the left, the one she picked on the right. */
@media (min-width:900px){
  /* Wider than a reading page (app.css caps #view's children at 760px): the list and the panel side by side. */
  #view > .yh.yh-wide{max-width:1180px;width:100%;margin-inline:auto}
  .yh-wide{display:grid;grid-template-columns:minmax(0,430px) minmax(0,1fr);gap:36px;align-items:start}
  .yh-wide .yh-card{max-height:560px;overflow:auto}
  .yh-panel{padding:22px 26px;border:1px solid var(--line);border-radius:20px;background:var(--raised)}
  .yh-panel .yh-open .btn{width:auto;padding:0 22px;min-height:48px;font-size:16px}
}
