/* W6-C9 — PRESENTATION MODE. The agent takes the big screen.
 *
 * A 10-foot stylesheet. Everything here is sized in viewport units with a
 * clamp() floor and ceiling, because the same document has to read from
 * eight feet away on a 1920 wall AND from eight inches away on a 375 phone
 * held sideways. No fixed pixel type anywhere above the hairlines.
 *
 * The palette is the NetShow Alive family, not the app design system: this
 * page never loads the app shell, and the ground tone is deliberately the
 * element's own wrap colour (#0E1526, alive-element.js CSS) so the seam
 * between the page and the mounted face is invisible.
 *
 * The 10-foot rhythm — mono kickers at wide tracking, one amber command
 * accent, tabular telemetry, generous title-safe margins — follows the
 * wall precedent already running at public/dale/dale.css.
 *
 * LAYERS (z, back to front)
 *      1   .pv-ground     the still portrait
 * 2147483000 netshow-alive  the live face, fixed by its own :host rule
 * 2147483001 .pv-hud        identity rail, caption band, pairing slot
 */

:root {
    --pv-ground-a: #070C18;
    --pv-ground-b: #0E1526;
    --pv-ink: #E6EDFB;
    --pv-dim: #93A3BE;
    --pv-faint: #5A6C8A;
    --pv-line: #22304F;
    --pv-amber: #F2B544;
    --pv-teal: #3ED9C0;
    --pv-blue: #6FA8F5;
    --pv-red: #E4574C;

    --pv-mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
    --pv-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;

    /* Title-safe margin. TVs overscan; tablets have notches. Take whichever
       is larger — the device's own safe-area inset, or a flat 3.4vmin. */
    --pv-safe-t: max(env(safe-area-inset-top, 0px), 3.4vmin);
    --pv-safe-r: max(env(safe-area-inset-right, 0px), 3.4vmin);
    --pv-safe-b: max(env(safe-area-inset-bottom, 0px), 3.4vmin);
    --pv-safe-l: max(env(safe-area-inset-left, 0px), 3.4vmin);

    /* The lower third, in two parts.
         --pv-lower-min  the band's reserved floor. Generous on purpose: a
                         one-line caption and a three-line caption should not
                         move the face, so the common cases all fit inside it.
         --pv-lower-h    what the band ACTUALLY measures, written by
                         alive-present.js on every resize. The face layer and
                         the still portrait are inset by this, so a caption
                         that grows past its reserve pushes the face up
                         instead of landing on the chin.
       The fallback keeps the reserve honest before the first measurement and
       for any browser without ResizeObserver. */
    --pv-lower-min: clamp(8.5rem, 27vh, 21rem);
    --pv-lower-h: var(--pv-lower-min);

    /* The one live-state colour every state-lit part of the HUD reads. */
    --pv-state: var(--pv-faint);
}

* { box-sizing: border-box; }

html, body {
    height: 100%;
    margin: 0;
    overflow: hidden;                     /* a wall screen never scrolls */
}

body.pv {
    /* Deliberately the mounted element's own wrap colour, not the darker
       ground: the caption scrim fades to transparent at its top edge, and
       whatever sits behind that edge has to match the face layer above it or
       a hairline step draws itself across the screen. */
    background: var(--pv-ground-b);
    color: var(--pv-ink);
    font-family: var(--pv-sans);
    -webkit-font-smoothing: antialiased;
}

/* ── STATE COLOUR ──────────────────────────────────────────────────────────
   One custom property, set from the agent's five frozen renderer states
   (alive-renderers.js) plus the link state. Everything state-lit in the HUD
   reads var(--pv-state), so a new state is one line here, not a sweep. */
html[data-state="idle"]        { --pv-state: var(--pv-faint); }
html[data-state="listening"]   { --pv-state: var(--pv-blue); }
html[data-state="thinking"]    { --pv-state: var(--pv-amber); }
html[data-state="speaking"]    { --pv-state: var(--pv-teal); }
html[data-state="interrupted"] { --pv-state: var(--pv-red); }
html[data-link="offline"]      { --pv-state: var(--pv-red); }

/* ── 1 · THE STILL PORTRAIT ───────────────────────────────────────────── */
.pv-ground {
    position: fixed;
    inset: 0 0 var(--pv-lower-h) 0;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2.2vmin;
    padding: calc(var(--pv-safe-t) + 7vmin) var(--pv-safe-r) 2vmin var(--pv-safe-l);
    background:
        radial-gradient(120% 90% at 50% 34%, var(--pv-ground-b) 0%, var(--pv-ground-a) 72%);
}

.pv-portrait {
    width: min(46vmin, 60vw);
    aspect-ratio: 1;
    border-radius: 50%;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(160deg, #16223C, #0B1224);
    border: 1px solid var(--pv-line);
    box-shadow: 0 0 0 1.4vmin rgba(20, 32, 56, .38), 0 3vmin 9vmin rgba(0, 0, 0, .6);
}

.pv-portrait-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.pv-portrait-mono {
    font-family: var(--pv-mono);
    font-size: min(20vmin, 26vw);
    font-weight: 700;
    line-height: 1;
    color: var(--pv-amber);
    letter-spacing: .02em;
}

.pv-ground-note {
    margin: 0;
    font-family: var(--pv-mono);
    font-size: clamp(.62rem, 1.05vw, 1rem);
    letter-spacing: .2em;
    text-transform: uppercase;
    color: var(--pv-faint);
    text-align: center;
}

/* ── 2 · THE LIVE FACE ────────────────────────────────────────────────────
   <netshow-alive mode="kiosk"> paints itself fixed/inset:0 from its own
   :host rule. Outer-tree rules win over :host in the cascade, so the one
   thing this page changes is where the face's bottom edge lands — clear of
   the caption band. Everything else about kiosk mode is left exactly as the
   element authored it (its 4vmin face padding, its per-mode ASCII sizing). */
.pv-face-slot netshow-alive[mode="kiosk"] {
    bottom: var(--pv-lower-h);
}

/* ── 3 · THE HEAD-UP DISPLAY ─────────────────────────────────────────── */
.pv-hud {
    position: fixed;
    inset: 0;
    z-index: 2147483001;                  /* one above the element's kiosk layer */
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    pointer-events: none;                 /* the face stays clickable; only
                                             the ask row re-enables it */
}

/* A face mounted on a flat field reads as a cut-out floating in a void, which
   is exactly how it looked at 1920 before this line. One vignette gives the
   figure a room to stand in: a faint lift behind the head, corners dropped.
   Painted over the face rather than behind it — the element owns its own
   background and this page never reaches into its shadow root.

   Held deliberately light. The svg avatars are narrow portrait figures with
   empty field around them and could take a much heavier vignette, but the
   sketch-line and hybrid renderers paint a canvas edge to edge: at .58 in the
   corners the sketch face's own outline went to mud. This falloff is set by
   the renderer that fills the frame, not the one that floats in it. */
.pv-hud::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: radial-gradient(78% 70% at 50% 38%,
        rgba(34, 52, 90, .18) 0%,
        rgba(10, 16, 30, .06) 58%,
        rgba(4, 7, 14, .34) 100%);
}

/* identity rail ---------------------------------------------------------- */
.pv-rail {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 3vmin;
    padding: var(--pv-safe-t) var(--pv-safe-r) 4vmin var(--pv-safe-l);
    background: linear-gradient(180deg, rgba(7, 12, 24, .88) 0%, rgba(7, 12, 24, 0) 100%);
}

.pv-id {
    display: flex;
    align-items: center;
    gap: clamp(.6rem, 1.2vw, 1.3rem);
    min-width: 0;
}

.pv-id-mark {
    flex: none;
    display: grid;
    place-items: center;
    width: clamp(2.1rem, 3.4vw, 4rem);
    height: clamp(2.1rem, 3.4vw, 4rem);
    border-radius: 50%;
    border: 1px solid var(--pv-line);
    background: #0B1224;
    color: var(--pv-amber);
    font-family: var(--pv-mono);
    font-size: clamp(.95rem, 1.6vw, 1.9rem);
    font-weight: 700;
    line-height: 1;
}

.pv-id-text {
    display: flex;
    flex-direction: column;
    gap: .18em;
    min-width: 0;
}

.pv-id-name {
    font-size: clamp(1.05rem, 1.9vw, 2.35rem);
    font-weight: 650;
    letter-spacing: -.005em;
    line-height: 1.1;
    color: #F3F7FF;
    text-shadow: 0 .1em .4em rgba(0, 0, 0, .7);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pv-id-role {
    font-family: var(--pv-mono);
    font-size: clamp(.6rem, .95vw, 1.05rem);
    letter-spacing: .2em;
    text-transform: uppercase;
    color: var(--pv-dim);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* status ----------------------------------------------------------------- */
.pv-status {
    flex: none;
    display: flex;
    align-items: center;
    gap: clamp(.5rem, .9vw, 1rem);
    padding: clamp(.4rem, .7vw, .8rem) clamp(.75rem, 1.3vw, 1.5rem);
    border: 1px solid var(--pv-line);
    border-radius: 999px;
    background: rgba(11, 18, 36, .72);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}

.pv-dot {
    width: clamp(.5rem, .82vw, .95rem);
    height: clamp(.5rem, .82vw, .95rem);
    border-radius: 50%;
    background: var(--pv-state);
    box-shadow: 0 0 .7em var(--pv-state);
    animation: pv-pulse 2.4s ease-in-out infinite;
}

.pv-status-label {
    white-space: nowrap;
    font-family: var(--pv-mono);
    font-size: clamp(.75rem, 1vw, 1.12rem);
    letter-spacing: .22em;
    text-transform: uppercase;
    color: var(--pv-ink);
    font-variant-numeric: tabular-nums;
}

@keyframes pv-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: .38; }
}

/* lower third ------------------------------------------------------------ */
.pv-lower {
    position: relative;                   /* over the HUD vignette */
    min-height: var(--pv-lower-min);
    display: flex;
    flex-direction: column;
    justify-content: center;              /* a one-line caption sits in the
                                             band, not jammed on its floor */
    gap: clamp(.7rem, 1.4vh, 1.6rem);
    padding: 6vmin var(--pv-safe-r) var(--pv-safe-b) var(--pv-safe-l);

    /* The top of this scrim is EXACTLY the mounted element's own wrap colour
       (#0E1526, alive-element.js CSS). Anything else draws a hard tonal step
       across the screen at the element's bottom edge — visible at 1920 and
       impossible to unsee once you have. */
    background: linear-gradient(0deg,
        #080D1A 0%,
        rgba(9, 14, 27, .96) 46%,
        rgba(14, 21, 38, .72) 82%,
        rgba(14, 21, 38, 0) 100%);
}

.pv-caption {
    margin: 0;

    /* Broadcast measure. Captions past roughly forty characters a line stop
       being scannable from a couch — the eye has to track too far to find the
       next line start. */
    max-width: 42ch;

    font-size: clamp(1.45rem, 3.15vw, 4.1rem);
    line-height: 1.16;
    font-weight: 500;
    letter-spacing: -.012em;
    color: #FFFFFF;
    text-shadow: 0 .06em .5em rgba(0, 0, 0, .85);
    text-wrap: balance;

    /* Three lines, hard. A caption band that grows without limit eats the
       face; one that clips mid-word is unreadable. Clamp and ellipsis. */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* The standing line before anyone has spoken reads as an invitation, not as
   live speech — dimmer, lighter, and it steps back the moment words land. */
.pv-caption[data-idle="1"] {
    color: var(--pv-dim);
    font-weight: 400;
}

/* ask row (only rendered for ?agent=local) -------------------------------- */
.pv-ask {
    display: flex;
    gap: clamp(.5rem, .9vw, 1rem);
    pointer-events: auto;
}

.pv-ask-input {
    flex: 1;
    min-width: 0;
    background: rgba(11, 18, 36, .86);
    border: 1px solid var(--pv-line);
    border-radius: .6em;
    color: var(--pv-ink);
    font-family: inherit;
    font-size: clamp(.95rem, 1.45vw, 1.75rem);
    padding: .55em .8em;
    outline: none;
}

.pv-ask-input:focus {
    border-color: var(--pv-teal);
    box-shadow: 0 0 0 .16em rgba(62, 217, 192, .22);
}

.pv-ask-go {
    flex: none;
    background: #182342;
    border: 1px solid var(--pv-line);
    border-radius: .6em;
    color: var(--pv-amber);
    font-family: inherit;
    font-size: clamp(.95rem, 1.45vw, 1.75rem);
    font-weight: 600;
    padding: .55em 1.3em;
    cursor: pointer;
}

.pv-ask-go:hover { border-color: var(--pv-amber); }

/* The missing-look door's one way on: "Meet <name> live". It sits in the rail
   inside .pv-hud (pointer-events: none), so it re-enables its own clicks. It is
   its own item under .pv-id-role (tiny mono, letter-spaced, uppercase), not a
   word inside it (line 12215), and a real pill a thumb can hit: 44 px tall,
   sentence case, only as wide as its words. */
.pv-hud [data-pv-missing-live],
.pv-live-link {
    pointer-events: auto;
    display: inline-flex;
    align-self: flex-start;
    align-items: center;
    min-height: 44px;
    margin-top: .5em;
    padding: 0 1.1em;
    background: #182342;
    border: 1px solid var(--pv-line);
    border-radius: 999px;
    color: var(--pv-amber);
    font-family: var(--pv-sans);
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: normal;
    text-transform: none;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}
.pv-live-link:hover,
.pv-live-link:focus-visible { border-color: var(--pv-amber); }

/* Line 12454 (present3d_missing_look_name_first): with no 3D look the pill is
   the page's primary button. House orange with dark words (white on #f97316
   reads 2.80:1; #111 reads 6.8:1), 48 px tall. The attribute prints only with
   the key lit, so OFF the pill above is unchanged. */
.pv-hud a[data-pv-missing-live][data-pv3d-primary] {
    min-height: 48px;
    padding: 0 1.4em;
    background: var(--ns-orange, #f97316);
    border-color: var(--ns-orange, #f97316);
    color: #111;
    font-weight: 700;
}
.pv-hud a[data-pv-missing-live][data-pv3d-primary]:hover,
.pv-hud a[data-pv-missing-live][data-pv3d-primary]:focus-visible {
    background: #ea580c;
    border-color: #fff;
    outline: none;
}
/* Same key, phones only: with no 3D look her portrait is the face of the page,
   so it grows to min(70vw, 320px). :has() reads the attribute the key prints. */
@media (orientation: portrait) and (max-width: 480px) {
    body:has([data-pv3d-name-first]) .pv-portrait { width: min(70vw, 320px); }
}

/* SHINE-03 server-turn strip (rendered only behind ai.features.present_door_turn)
   Rides the ask row's sizes so the two never drift; adds the mic button
   (hidden until the loader finds browser speech recognition) and a one-line
   note under the row for the visitor-lane cap / a failed turn. At 375 the
   row stays a single line: input flexes, the two buttons keep their
   intrinsic width, the Send label shortens through font-size not wrapping. */
.pv-ask--turn { align-items: stretch; }

.pv-ask-mic {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: auto;
    min-width: 2.9em;
    background: #182342;
    border: 1px solid var(--pv-line);
    border-radius: .6em;
    color: var(--pv-ink);
    font-size: clamp(.95rem, 1.45vw, 1.75rem);
    padding-inline: .65em;
    white-space: nowrap;
    cursor: pointer;
}

.pv-ask-mic:hover { border-color: var(--pv-teal); }
.pv-ask-mic[aria-pressed="true"] {
    border-color: var(--pv-teal);
    color: var(--pv-teal);
    box-shadow: 0 0 0 .16em rgba(62, 217, 192, .22);
}

.pv-ask--turn[data-busy="1"] .pv-ask-input,
.pv-ask--turn[data-busy="1"] .pv-ask-go { opacity: .6; }

.pv-ask--turn[data-capped="1"] .pv-ask-mic,
.pv-ask--turn[data-capped="1"] .pv-ask-go { display: none; }

.pv-turn-note {
    margin: .35em 0 0;
    color: var(--pv-dim);
    font-size: clamp(.78rem, 1.05vw, 1.15rem);
    line-height: 1.35;
    pointer-events: auto;
}

.pv-turn-note a { color: var(--pv-amber); }

@media (max-width: 480px) {
    .pv-ask--turn .pv-ask-go { padding: .55em .9em; }
}

/* foot: the mark and the pairing slot ------------------------------------- */
.pv-foot {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 3vmin;
}

.pv-mark {
    white-space: nowrap;
    font-family: var(--pv-mono);
    font-size: clamp(.75rem, .92vw, 1.02rem);
    letter-spacing: .32em;
    text-transform: uppercase;
    color: var(--pv-faint);
}

.pv-pair {
    display: flex;
    align-items: center;
    gap: clamp(.7rem, 1.3vw, 1.5rem);
    padding: clamp(.6rem, 1vw, 1.1rem);
    border: 1px solid var(--pv-line);
    border-radius: .8em;
    background: rgba(11, 18, 36, .86);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}

.pv-pair[hidden] { display: none; }

.pv-pair-qr {
    display: block;
    width: clamp(4.2rem, 8vw, 9rem);
    height: auto;
    border-radius: .35em;
    background: #FFFFFF;
}

.pv-pair-qr[hidden] { display: none; }

.pv-pair-copy {
    display: flex;
    flex-direction: column;
    gap: .3em;
}

.pv-pair-kicker {
    font-family: var(--pv-mono);
    font-size: clamp(.55rem, .85vw, .95rem);
    letter-spacing: .26em;
    text-transform: uppercase;
    color: var(--pv-amber);
}

.pv-pair-code {
    font-family: var(--pv-mono);
    font-size: clamp(1.2rem, 2.4vw, 3rem);
    font-weight: 700;
    letter-spacing: .18em;
    line-height: 1;
    color: #F3F7FF;
    font-variant-numeric: tabular-nums;
}

.pv-pair-hint {
    font-size: clamp(.7rem, 1.05vw, 1.15rem);
    color: var(--pv-dim);
    line-height: 1.35;
}

.pv-pair-code:empty,
.pv-pair-hint:empty { display: none; }

/* ── PORTRAIT ──────────────────────────────────────────────────────────────
   A tablet stood upright in a lobby, or a phone. The face gets the height it
   needs, so the lower third gives some of its band back and the caption
   drops a notch — three lines of 3.15vw would be a wall of text at 9:16. */
@media (orientation: portrait) {
    :root { --pv-lower-min: clamp(7.5rem, 21vh, 16rem); }

    .pv-rail {
        flex-direction: column;
        align-items: stretch;
        gap: 2vmin;
    }

    .pv-status { align-self: flex-start; }

    .pv-caption { font-size: clamp(1.35rem, 5.4vw, 3.1rem); }

    .pv-foot {
        flex-direction: column-reverse;
        align-items: stretch;
        gap: 1.6vmin;
    }

    .pv-portrait { width: min(58vmin, 74vw); }
}

/* Short landscape (a laptop lid, a 16:10 monitor turned into a screen): the
   band would swallow the face at 27vh, so cap it in absolute terms. */
@media (orientation: landscape) and (max-height: 560px) {
    :root { --pv-lower-min: clamp(6.5rem, 34vh, 11rem); }

    .pv-caption {
        font-size: clamp(1.15rem, 2.5vw, 2.1rem);
        -webkit-line-clamp: 2;
    }

    .pv-rail { padding-bottom: 2vmin; }
    .pv-lower { padding-top: 3vmin; }
}

/* ── REDUCED MOTION ────────────────────────────────────────────────────────
   The live face is not mounted at all under this setting (the loader bails
   before importing the element — the same rule the marketplace use door
   follows). What is left is this page's own motion, and it stops too. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
    }

    .pv-dot { opacity: 1; }
}

/* ── FORCED COLORS ─────────────────────────────────────────────────────────
   A wall screen in a high-contrast kiosk profile still has to name the agent
   and carry the caption. Hand the scrims and glows back to the OS. */
@media (forced-colors: active) {
    .pv-status,
    .pv-pair { background: Canvas; }

    .pv-caption,
    .pv-id-name { text-shadow: none; }

    .pv-dot { forced-color-adjust: none; }
}

/* The shared voice stylesheet is linked after the controls in the body.
   Mount their fixed box in this head-loaded sheet so its arrival cannot
   move the controls from the top of the page to the bottom band. */
body[data-door-voice-first].pv > .ns-door-voice-controls {
    position: fixed;
    left: 12px;
    right: 12px;
    bottom: 16%;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 8px;
    margin: 16px auto;
    padding: 8px;
}

@media (max-width: 480px) {
    body[data-door-voice-first].pv > .ns-door-voice-controls {
        gap: 4px;
        margin: 8px auto;
    }
}

/* Keep the voice band's greeting box mounted while its words change.
   Its shared caption uses a 1.6 line-height; reserve three lines on phones
   as well as walls without limiting longer replies or the open menu. */
body[data-door-voice-first].pv > .ns-door-voice-controls > [data-door-voice-caption] {
    min-height: 4.8em;
    display: block;
    width: 100%;
    max-width: 640px;
    margin: 8px auto;
    padding: 0 16px;
    text-align: center;
    font: clamp(16px, 2vw, 20px)/1.6 system-ui;
    overflow-wrap: anywhere;
}
