/* ============================================================================
 * dressing-room.css — The Dressing Room surface styles.
 *
 * unbifurcating-vault-surfaces S7 (curating-member-portrayal, 2026-07-23).
 * The soul: a performer's dressing room before the show — vanity mirror
 * ringed in warm bulbs (the official headshot), the wardrobe rail (curated
 * set), the proof drawer (confirmed appearances). Theme tokens live in
 * ffv-modal-theme.css (.ffv-theme-dressing, a cssOnly family member); this
 * sheet carries the room itself. Motion discipline: one slow bulb-breathe,
 * calmer than the vessel; prefers-reduced-motion collapses it.
 * ========================================================================== */

/* The bespoke shell in the dressing dress (same pattern as .ffv-theme-kg) */
.ffv-theme-dressing .fergi-bespoke-shell {
    background: var(--ffv-glass-bg);
    border-color: rgba(217, 138, 156, 0.35);
    box-shadow:
        0 0 0 1px rgba(255, 217, 160, 0.10),
        0 18px 60px rgba(18, 6, 12, 0.65),
        0 0 42px rgba(217, 138, 156, 0.14);
}
.ffv-theme-dressing .fergi-bespoke-shell::before {
    background: var(--ffv-rim-gradient);
}
.ffv-theme-dressing .fergi-bespoke-header {
    background: linear-gradient(90deg,
        rgba(217, 138, 156, 0.16), rgba(255, 217, 160, 0.09), rgba(239, 63, 165, 0.13));
    border-bottom: 1px solid rgba(217, 179, 106, 0.22);
}
.ffv-theme-dressing .fergi-bespoke-title {
    font-family: var(--ffv-display-font);
    font-weight: 600;
    letter-spacing: 0.015em;
    color: #ffeede;
    text-shadow: 0 0 20px rgba(255, 217, 160, 0.25);
}
.ffv-theme-dressing .fergi-bespoke-close:hover { background: rgba(217, 138, 156, 0.3); }
/* ::before, not the box — the theme dim rides the App-Panel scrim so it cannot
   wash the Header and the Control Panel rail (issue #6, S4 2026-08-13). */
.ffv-theme-dressing.fergi-bespoke-modal::before { background: rgba(20, 8, 14, 0.56); }

/* ── The room ───────────────────────────────────────────────────────────── */
.dr-in-bespoke { padding: 0; }
.dr-root {
    display: flex;
    gap: 18px;
    padding: 16px 18px 18px;
    color: var(--ffv-dr-text, #f3e7e0);
    font-family: var(--ffv-body-font, 'Source Sans 3', sans-serif);
    min-height: 340px;
}

/* ── The vanity (left) ─────────────────────────────────────────────────── */
.dr-vanity {
    flex: 0 0 218px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 14px 12px;
    border-radius: 14px;
    background: radial-gradient(ellipse 90% 55% at 50% 18%,
        rgba(255, 217, 160, 0.10), rgba(0, 0, 0, 0) 70%);
}
.dr-mirror-frame {
    position: relative;
    width: 172px;
    height: 172px;
}
.dr-mirror {
    position: absolute;
    inset: 14px;
    border-radius: 50%;
    overflow: hidden;
    background: #1a1016;
    border: 2px solid rgba(217, 179, 106, 0.55);
    box-shadow:
        inset 0 0 24px rgba(0, 0, 0, 0.55),
        0 0 26px rgba(255, 217, 160, 0.18);
}
.dr-mirror-face {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.dr-mirror-empty {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--ffv-display-font, Georgia, serif);
    font-size: 56px;
    color: rgba(255, 222, 190, 0.5);
}
/* the ring of vanity bulbs */
.dr-bulb {
    position: absolute;
    top: 50%; left: 50%;
    width: 9px; height: 9px;
    margin: -4.5px;
    border-radius: 50%;
    background: var(--ffv-bulb, #ffd9a0);
    box-shadow: 0 0 8px var(--ffv-bulb, #ffd9a0), 0 0 16px rgba(255, 217, 160, 0.5);
    transform: rotate(calc(var(--dr-bulb-i) * 36deg)) translateY(-84px);
    animation: dr-bulb-breathe 6s ease-in-out infinite alternate;
    animation-delay: calc(var(--dr-bulb-i) * -0.6s);
}
@keyframes dr-bulb-breathe {
    from { opacity: 0.55; }
    to   { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
    .dr-bulb { animation: none !important; opacity: 0.8; }
}

.dr-vanity-name {
    font-family: var(--ffv-display-font, Georgia, serif);
    font-size: calc(1.15rem * var(--type-scale, 1));
    color: #ffeede;
    text-align: center;
}
.dr-vanity-sub {
    font-size: calc(0.8rem * var(--type-scale, 1));
    color: var(--ffv-dr-muted, #c2a3a4);
    text-align: center;
    line-height: 1.35;
}
.dr-vanity-actions {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    width: 100%;
    margin-top: 4px;
}
.dr-btn {
    border: 1px solid rgba(217, 179, 106, 0.4);
    border-radius: 10px;
    background: rgba(217, 138, 156, 0.14);
    color: var(--ffv-dr-text, #f3e7e0);
    padding: 8px 10px;
    font-size: calc(0.85rem * var(--type-scale, 1));
    cursor: pointer;
    transition: background 0.15s ease;
}
.dr-btn:hover { background: rgba(217, 138, 156, 0.28); }
.dr-switch-label {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: calc(0.72rem * var(--type-scale, 1));
    color: var(--ffv-dr-muted, #c2a3a4);
}
.dr-switch {
    background: rgba(22, 16, 26, 0.85);
    color: var(--ffv-dr-text, #f3e7e0);
    border: 1px solid rgba(217, 138, 156, 0.35);
    border-radius: 8px;
    padding: 6px 8px;
    font-size: calc(0.82rem * var(--type-scale, 1));
}
/* cropping-solo-portraits S3 — the way out of this room to the whole-family
   contact sheet. Deliberately quieter than .dr-btn: the room's buttons write,
   and this one only opens a review where nothing is applied. */
.dr-sheet-link {
    display: block;
    margin-top: 4px;
    font-size: calc(0.72rem * var(--type-scale, 1));
    color: var(--ffv-dr-muted, #c2a3a4);
    text-decoration: none;
    border-top: 1px solid rgba(217, 138, 156, 0.18);
    padding-top: 8px;
}
.dr-sheet-link:hover { color: var(--ffv-dr-text, #f3e7e0); }
/* ⛔ `display:flex` beats the `hidden` attribute: without the [hidden] rule below, every room opened saying
 * "Official headshot changed. ↩ Undo" when nothing had changed (Greg G-135, 2026-10-21; the phone twin
 * .mdr-undo already had its guard). Pinned by tests/mobile/dressing-undo-honest.test.js. */
.dr-undo[hidden] { display: none; }
.dr-undo {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    border-radius: 10px;
    background: rgba(239, 63, 165, 0.12);
    border: 1px solid rgba(239, 63, 165, 0.3);
    font-size: calc(0.78rem * var(--type-scale, 1));
}

/* ── The rail + drawer (right) ─────────────────────────────────────────── */
.dr-main {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 14px;
    overflow-y: auto;
    max-height: min(66vh, 720px);
    padding-right: 4px;
}
.dr-h {
    margin: 0 0 8px;
    font-family: var(--ffv-display-font, Georgia, serif);
    font-weight: 600;
    font-size: calc(1rem * var(--type-scale, 1));
    color: #ffeede;
    border-bottom: 1px solid rgba(217, 179, 106, 0.25);
    padding-bottom: 5px;
}
.dr-h-sub {
    font-family: var(--ffv-body-font, sans-serif);
    font-weight: 400;
    font-size: calc(0.75rem * var(--type-scale, 1));
    color: var(--ffv-dr-muted, #c2a3a4);
}
.dr-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));
    gap: 10px;
}
.dr-tile {
    position: relative;
    margin: 0;
    border-radius: 10px;
    overflow: hidden;
    background: rgba(20, 12, 18, 0.8);
    border: 1px solid rgba(217, 138, 156, 0.22);
    aspect-ratio: 1 / 1;
}
.dr-tile--official {
    border-color: rgba(255, 217, 160, 0.75);
    box-shadow: 0 0 14px rgba(255, 217, 160, 0.28);
}
.dr-tile--missing { display: none; }
.dr-tile img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    cursor: pointer;
}
.dr-chip {
    position: absolute;
    top: 6px; left: 6px;
    padding: 2px 7px;
    border-radius: 999px;
    background: rgba(22, 16, 26, 0.82);
    border: 1px solid rgba(217, 179, 106, 0.4);
    font-size: calc(0.66rem * var(--type-scale, 1));
    color: #ffeede;
    pointer-events: none;
}
.dr-chip-official { border-color: rgba(255, 217, 160, 0.8); color: var(--ffv-bulb, #ffd9a0); }
.dr-chip-proof    { border-color: rgba(64, 226, 210, 0.5); color: #a9f0e6; }
.dr-tile-acts {
    position: absolute;
    left: 0; right: 0; bottom: 0;
    display: flex;
    gap: 5px;
    justify-content: center;
    padding: 6px 5px;
    background: linear-gradient(180deg, rgba(16, 10, 16, 0), rgba(16, 10, 16, 0.88) 55%);
    opacity: 0;
    transition: opacity 0.15s ease;
}
.dr-tile:hover .dr-tile-acts,
.dr-tile:focus-within .dr-tile-acts { opacity: 1; }
/* touch (projection / coarse pointers): actions always visible — hover is an
 * enhancement, never a gate (S5 hover-inventory law). */
@media (pointer: coarse) {
    .dr-tile-acts { opacity: 1; }
}
.dr-act {
    border: 1px solid rgba(217, 179, 106, 0.45);
    border-radius: 8px;
    background: rgba(30, 18, 26, 0.9);
    color: var(--ffv-dr-text, #f3e7e0);
    font-size: calc(0.68rem * var(--type-scale, 1));
    padding: 3px 7px;
    cursor: pointer;
    white-space: nowrap;
}
.dr-act:hover { background: rgba(217, 138, 156, 0.35); }
.dr-act-official { border-color: rgba(255, 217, 160, 0.6); }
.dr-act-remove:hover { background: rgba(180, 60, 60, 0.5); }
/* A finger needs 44 px (Greg G-134, 2026-10-21, FergiPAD): "Official" was 66×26 beside a 24×26 "Take off the
 * rail", so a tap meant to choose a portrait could remove it. AFTER the base .dr-act rule on purpose (same
 * specificity: earlier, its padding lost). iPad tiles are ~120 px wide, so the gap is tight and "Official" keeps
 * slim sides: its label must fit, not run under the ✕. Desktop mouse sizes are unchanged. Pinned by
 * tests/mobile/dressing-touch-floors.test.js (WebKit). */
@media (pointer: coarse) {
    /* …and on a finger the actions sit UNDER the photo, never on it: at 44 px they covered the lower half of every
     * face, the very thing the member is choosing between (glass re-walk, 1.1.405). */
    .dr-tile { aspect-ratio: auto; display: flex; flex-direction: column; }
    .dr-tile img { height: auto; aspect-ratio: 1 / 1; flex: none; }
    .dr-tile-acts { position: static; background: rgba(16, 10, 16, 0.95); padding-top: 4px; padding-bottom: 4px; }
    .dr-tile-acts { gap: 4px; padding-left: 4px; padding-right: 4px; }
    .dr-act { min-height: 44px; min-width: 44px; }
    .dr-act-official { padding-left: 5px; padding-right: 5px; flex-shrink: 0; }
}
.dr-empty {
    padding: 18px 14px;
    border: 1px dashed rgba(217, 138, 156, 0.3);
    border-radius: 10px;
    color: var(--ffv-dr-muted, #c2a3a4);
    font-size: calc(0.85rem * var(--type-scale, 1));
    line-height: 1.4;
}

/* narrow shells: vanity stacks above the rail */
@media (max-width: 760px) {
    .dr-root { flex-direction: column; }
    .dr-vanity { flex: none; }
    .dr-main { max-height: none; }
}

/* ── Portrait provenance (cropping-solo-portraits S1) ──────────────────────
   Who chose the face in the mirror. Sits directly under the vanity subtitle
   because it qualifies that sentence: "this is the face the Vault shows" reads
   very differently depending on whether a person or a batch job decided it.
   Three states, three tempers — the hand-made one is the warm brass the room
   reserves for a deliberate act; the generated one recedes into the muted
   register; the unknown one wears the room's alert rose, because an
   unrecorded write is exactly the kind of thing this room is for surfacing. */
.dr-prov {
    display: flex;
    align-items: baseline;
    gap: 6px;
    margin-top: 8px;
    padding: 5px 9px;
    border-radius: 8px;
    font-size: calc(0.72rem * var(--type-scale, 1));
    line-height: 1.4;
    text-align: left;
}
.dr-prov-glyph { flex: none; font-size: 0.85em; }
.dr-prov--manual {
    border: 1px solid rgba(217, 179, 106, 0.4);
    background: rgba(217, 179, 106, 0.12);
    color: var(--ffv-dr-text, #f3e7e0);
}
.dr-prov--generated {
    border: 1px solid rgba(217, 138, 156, 0.18);
    background: rgba(217, 138, 156, 0.06);
    color: var(--ffv-dr-muted, #c2a3a4);
}
.dr-prov--unknown {
    border: 1px solid rgba(224, 122, 122, 0.4);
    background: rgba(224, 122, 122, 0.1);
    color: var(--ffv-dr-text, #f3e7e0);
}

/* A tile that fell back to the whole photo (cropping-solo-portraits S1) — the
   vault has no face box for this person here. Marked rather than hidden: the
   difference between "here is their face" and "here is the photo they are
   somewhere in" is the difference the operator is deciding on. */
.dr-tile-img--whole {
    outline: 1px dashed rgba(217, 138, 156, 0.45);
    outline-offset: -2px;
}

/* ══════════════════════════════════════════════════════════════════════════
   THE WARDROBE CONSOLE — the v14 sculpted chassis (porting-perimeter-souls S6)

   The fleet's first BESPOKE port. Every rule below is scoped
   `html.ffv-modal-fleet-v14 .ffv-theme-dressing …`, which is the seam's second
   half: the linework can gate itself inside `layers()`, but the SHELL cannot —
   `.ffv-theme-dressing .fergi-bespoke-shell` above draws a background, a
   border and a rim in BOTH states, so an unscoped override would break
   flag-off identity, and flag-off is the rollback path.

   ⛔ THE ONE ARCHITECTURAL FACT THIS ROOM ADDS. A RoomWindow spends its
   theme's `headerKeepOut` through `--ffrw-keepout`, which `.ffrw-header`
   consumes in room-windows.css. THE BESPOKE SHELL HAS NO SUCH CONSUMER — its
   framed padding is the fixed `12px 20px 14px 16px` the `kg` room established,
   and the two bespoke silhouettes that already ship were drawn thin enough to
   live inside it (their lip heads sit at y=40-48, against this fleet's
   130-175). The wardrobe canopy is a RoomWindow-scale crown at y=166.6; dropped
   into a fixed 12px padding it would put a quarter of the shell's height of
   lacquer on top of the member's vanity mirror.

   So this room consumes the keep-outs the chassis already resolves and
   publishes (`ffv-chassis.js` sets --ffrw-keepout / --ffrw-footkeepout on ANY
   shell whose theme declares them, and re-resolves both on resize). Scoped to
   this theme, so `kg`, `biographer`, `umi`, `library`, `theatre` and every
   satellite child are untouched — they declare no keep-outs, so the variables
   are never set on them and the fallbacks are today's literals.
   ══════════════════════════════════════════════════════════════════════════ */

html.ffv-modal-fleet-v14 .ffv-theme-dressing .fergi-bespoke-shell.ffvc-framed {
    background: transparent;
    border-color: transparent;
    box-shadow: none;
    overflow: visible;
    border-radius: 0;
    /* The canopy, the rail AND the flanks, spent as padding. All three come
       from the chassis kit, which resolves them against the layer's own box and
       re-resolves on every resize — so the room stays inside its vessel at every
       size-ladder rung rather than at the one rung it was authored against. The
       fallbacks are the `kg` literals, which is what a shell with no declared
       keep-out is handed today. */
    padding: var(--ffrw-keepout, 12px) var(--ffrw-sidekeepout, 20px)
             var(--ffrw-footkeepout, 14px) var(--ffrw-sidekeepout, 16px);
}
html.ffv-modal-fleet-v14 .ffv-theme-dressing .fergi-bespoke-shell.ffvc-framed::before {
    display: none;
}
/* the room rides above the chassis layer; `.ffs-handle` is excluded because the
   resize band keeps its own absolute edge placement (fleet resize-chrome
   contract, spatial-manager.css) — the same exclusion `.ffv-theme-kg` makes.
   ⛔ THE EXCLUSION NOW ALSO CARRIES THE ARMED BRACKETS (armed-bracket-perimeter
   S2). The corner cues are `.ffs-handle::after`, so this `:not()` is the only
   thing keeping them above the lifted content — drop it here and the brackets
   go dark in THIS room while staying lit everywhere else, which reads as
   "fixed in some rooms". There are FIVE content-lift sites in app/css
   (biography-modal, dressing-room, ffv-modal-theme, unified-media-modal,
   stories); they are one edit, and window-manager.smoke.cjs sweeps all of
   them so the set cannot drift by hand. */
html.ffv-modal-fleet-v14 .ffv-theme-dressing .fergi-bespoke-shell.ffvc-framed
    > :not(.ffv-chassis-layer):not(.ffs-handle) {
    position: relative;
    z-index: 1;
}
html.ffv-modal-fleet-v14 .ffv-theme-dressing .fergi-bespoke-shell.ffvc-framed
    .fergi-bespoke-header {
    background: none;
    border-bottom-color: rgba(217, 179, 106, 0.22);
}
/* a deeper wine behind the vanity, matching the Study's room dim */
html.ffv-modal-fleet-v14 .ffv-theme-dressing.fergi-bespoke-modal::before {
    background: rgba(16, 6, 11, 0.58);   /* ::before — scoped scrim, see :38 */
}

/* ── the linework ───────────────────────────────────────────────────────────
   Widths are the lab's own, carried by judgement #1: a length along a path
   cannot take an anisotropic map, so each takes the geometric mean 0.6614.
   The arithmetic is written out so it is checkable rather than trusted. */
html.ffv-modal-fleet-v14 .ffv-theme-dressing .ffvc-v14-vanity-arch {
    fill: none;
    stroke: #55b8ff;                 /* lab --room-metal */
    stroke-width: 1.98;              /* lab 3 x 0.6614 */
    stroke-linecap: round;
    opacity: .62;
}
html.ffv-modal-fleet-v14 .ffv-theme-dressing .ffvc-v14-bulb {
    fill: #ffe7a4;
    stroke: #ef3fa5;                 /* lab --room-c, the family orchid */
    stroke-width: 1.32;              /* lab 2 x 0.6614 */
    opacity: .85;
}
html.ffv-modal-fleet-v14 .ffv-theme-dressing .ffvc-v14-wardrobe-rail {
    fill: none;
    stroke: #55b8ff;                 /* lab --room-metal */
    stroke-width: 2.65;              /* lab 4 x 0.6614 */
    stroke-linecap: round;
    opacity: .55;
}
html.ffv-modal-fleet-v14 .ffv-theme-dressing .ffvc-v14-hanger-mini {
    fill: none;
    stroke: #4fd1a1;                 /* lab --room-a */
    stroke-width: 1.32;              /* lab 2 x 0.6614 */
    stroke-linejoin: round;
    opacity: .7;
}
html.ffv-modal-fleet-v14 .ffv-theme-dressing .ffvc-v14-drawer {
    fill: #210b16;
    stroke: #55b8ff;                 /* lab --room-metal */
    stroke-width: 1.32;              /* lab 2 x 0.6614 */
    opacity: .8;
}
html.ffv-modal-fleet-v14 .ffv-theme-dressing .ffvc-v14-drawer-pull {
    fill: #55b8ff;
    /* ⚠ the lab gives `.drawer-pull` no stroke rule at all, so the census
       reported its half stroke as a FLOOR rather than a fact. It is a filled
       ellipse with no stroke here, which is what the lab paints — the warning
       is honest and this is the reading that makes it moot. */
    opacity: .85;
}
html.ffv-modal-fleet-v14 .ffv-theme-dressing .ffvc-v14-hero-marquee {
    fill: none;
    stroke: #b99055;                 /* lab --room-b, the brass of the hanger */
    stroke-width: 1.98;              /* lab 3 x 0.6614 */
    stroke-linejoin: round;
    opacity: .78;
}
html.ffv-modal-fleet-v14 .ffv-theme-dressing .ffvc-v14-hero-ring {
    fill: rgba(185, 144, 85, .16);
}

/* ── motion (HELPER_CONTRACT §6b) ───────────────────────────────────────────
   The lab gives this room exactly ONE keyframe, `bulb-chase`, and it is
   `{ from { opacity: .4 } to { opacity: 1 } }` — PURE PAINT, so it carries
   verbatim. The alternation is the divergence matrix's named signature for
   this room ("alternating vanity lamps"), and it survives the port intact.

   Declared plainly rather than left to be inferred: NOTHING ELSE in this room
   animates. No transform is carried, because none exists to refuse — this is
   the first room in the fleet where §6b's ruling costs nothing.

   The name is `ffvc-v14-bulb-chase`, not `bulb-chase` and not a name another
   room already uses: `capture-gates.cjs` loads exactly ONE host stylesheet, so
   an animation defined in a sibling room's sheet renders in the vault and is
   invisible to the gate — and a gate that cannot see an animation cannot rule
   on it (S5's third motion ruling, met again here). */
@media (prefers-reduced-motion: no-preference) {
    html.ffv-modal-fleet-v14 .ffv-theme-dressing .ffvc-v14-bulb:nth-child(2n) {
        animation: ffvc-v14-bulb-chase 2.6s ease-in-out infinite alternate;
    }
    html.ffv-modal-fleet-v14 .ffv-theme-dressing .ffvc-v14-bulb:nth-child(2n+1) {
        animation: ffvc-v14-bulb-chase 2.6s -1.3s ease-in-out infinite alternate;
    }
}
@keyframes ffvc-v14-bulb-chase { from { opacity: .4; } to { opacity: 1; } }
