/* ==========================================================================
   Node 42 — CABINET: frame art + side control panel
   Vel supplied the art 2026-09-01; this positions it.
   ==========================================================================
   Every percentage here was MEASURED FROM THE PNG ALPHA CHANNEL, not eyeballed.
   They live as custom properties so there is exactly ONE place to correct if the
   art is re-exported at different proportions.

     Node-42.png        1672x941  (ratio 1.7768)  aperture is a genuine cut-out
     Right-Side-Panel.png 740x2126 (ratio 0.3481) interior is OPAQUE (alpha 253),
                                                  so controls sit ON it
   ========================================================================== */

/* THE GEOMETRY CONSTANTS SCOPE TO .n42, NOT .n42-cabinet. Moved 2026-09-14.
   These numbers describe the ARTWORK, and the artwork is used by every skin — but
   `.n42-cabinet` is only ONE skin's root class. The hub screen on page 512 sets
   `n42-hub-overlay` INSTEAD of `n42-cabinet` (player_markup's `root_class` option
   replaces it, it does not add to it), so scoping these to the cabinet left every
   var() below UNDEFINED in the hub.
   An undefined var() with no fallback is invalid at computed-value time, so the
   property falls back to its INITIAL value — `aspect-ratio: auto` and `auto` on all
   four aperture insets, applied to two absolutely-positioned elements. The screen
   lost its geometry entirely and the <video> at height:100% resolved against a
   collapsed box (black picture, working sound), while .n42-panel-inner fell out of
   the bezel and read as the old fallback bar. Two symptoms, one cause. Measured
   2026-09-14: the served page carries `n42-panel` 5x and `n42-bar` ZERO times, so
   the bar was never rendering — it only looked like it was.
   `.n42` is on the root element in BOTH skins, which makes it the correct scope. */
.n42 {
    --n42-frame-ratio: 1.7768;
    --n42-ap-left:      3.65%;
    --n42-ap-top:      11.58%;
    --n42-ap-width:    92.70%;
    --n42-ap-height:   80.34%;

    --n42-panel-ratio: 0.3481;
    --n42-pn-left:     15.95%;
    --n42-pn-top:       2.68%;
    --n42-pn-width:    68.24%;
    --n42-pn-height:   94.03%;
}

.n42-cabinet {
    display: flex;
    align-items: stretch;
    gap: clamp(4px, 0.8vw, 14px);
    width: 100%;
    max-width: 1400px;
    margin: 1.5rem auto;
}

/* The television. aspect-ratio keeps the art undistorted at every width, so the
   aperture percentages stay true without a single media query. */
.n42-set {
    position: relative;
    flex: 1 1 auto;
    aspect-ratio: var(--n42-frame-ratio);
    min-width: 0;               /* without this a flex item refuses to shrink */
}

/* Sits BEHIND the frame and shows through its cut-out. */
.n42-screen {
    position: absolute;
    left:   var(--n42-ap-left);
    top:    var(--n42-ap-top);
    width:  var(--n42-ap-width);
    height: var(--n42-ap-height);
    background: #000;
    overflow: hidden;
    z-index: 1;
}

.n42-screen .n42-video {
    width: 100%;
    height: 100%;
    /* CONTAIN, not cover. The aperture is 2.05:1 but most of this library is 4:3
       mid-century film, and `cover` would crop the top and bottom off every reel
       to fill a decorative hole. Pillarboxed 4:3 inside a wide bezel is also
       exactly what a real set looked like. */
    object-fit: contain;
    background: #000;
    display: block;
}

/* The embedded (YouTube) transport, added 2026-09-14. Fills the same aperture the
   <video> does, so the bezel art frames it identically and neither transport needs to
   know which one is on screen. display:none by default — it is created empty and only
   revealed when an embedded programme is actually mounted.
   z-index sits BELOW .n42-frame (2) so the bezel still overlays its edge, and below
   the slate/bug so a credit is never hidden behind the picture. */
.n42-screen .n42-yt {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: none;
    background: #000;
    z-index: 1;
}

/* The iframe the IFrame API injects has its own width/height attributes; override
   them or it renders at YouTube's default 640x360 inside our aperture. */
.n42-screen .n42-yt iframe {
    position: absolute;
    inset: 0;
    width: 100% !important;
    height: 100% !important;
    border: 0;
    display: block;
}

.n42-frame {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    /* The art is a frame, never a control: it must not eat clicks aimed at the
       video or at anything the theme places behind it. */
    pointer-events: none;
    z-index: 2;
    user-select: none;
}

/* ---------------------------------------------------------------- panel ---- */

.n42-panel {
    position: relative;
    /* WIDTH IS AN EXPLICIT PERCENTAGE, NOT aspect-ratio.
       The first version used `aspect-ratio: 0.3481` with `align-items: stretch`, which
       is circular: panel width came from panel height, panel height came from the
       container, the container's height came from the set's height, and the set's
       width depended on how much room the panel left. Flex resolved that cycle by
       giving the panel ZERO width and the sidebar rendered as nothing at all.

       Solved algebraically instead. For the two artworks to stand exactly the same
       height with no distortion:
           panel_w = set_h * 0.3481,  set_h = set_w / 1.7768
           => panel_w = set_w * 0.19591
           => as a share of the cabinet: p = (1-p) * 0.19591 => p = 0.16382
       At 16.382% the panel's stretched box lands on 0.348 naturally, so
       `background-size: 100% 100%` fills it with no stretching. */
    flex: 0 0 16.382%;
    min-width: 96px;
    align-self: stretch;
    background-repeat: no-repeat;
    background-position: center;
    background-size: 100% 100%;
}

.n42-panel-inner {
    position: absolute;
    left:   var(--n42-pn-left);
    top:    var(--n42-pn-top);
    width:  var(--n42-pn-width);
    height: var(--n42-pn-height);
    display: flex;
    flex-direction: column;
    gap: 0.4em;
    /* The bezel is tall and narrow; on a short viewport the controls would
       otherwise spill outside their own frame. */
    overflow-y: auto;
    padding: 0.2em 0;
    font-size: clamp(0.5rem, 0.95vw, 0.82rem);
    line-height: 1.25;
}

.n42-panel-head {
    color: var(--n42-accent);
    font-size: 0.78em;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    opacity: 0.75;
    padding: 0.35em 0.2em 0;
    flex: 0 0 auto;
}

.n42-dial {
    display: flex;
    flex-direction: column;
    gap: 0.28em;
    flex: 0 0 auto;
}

.n42-freq {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.05em;
    background: rgba(10, 30, 70, 0.55);
    border: 1px solid rgba(90, 150, 255, 0.35);
    border-radius: 3px;
    color: #cfe3ff;
    padding: 0.35em 0.45em;
    cursor: pointer;
    text-align: left;
    width: 100%;
    font: inherit;
    transition: background 0.15s, border-color 0.15s;
}

.n42-freq:hover {
    background: rgba(20, 60, 130, 0.75);
    border-color: rgba(140, 190, 255, 0.7);
}

.n42-freq:focus-visible {
    outline: 2px solid var(--n42-accent);
    outline-offset: 1px;
}

.n42-freq.is-tuned {
    background: rgba(30, 90, 190, 0.9);
    border-color: var(--n42-accent);
    box-shadow: 0 0 8px rgba(80, 160, 255, 0.55);
    color: #fff;
}

/* An off-air frequency is still listed and still tunable - hiding it would make
   the dial lie about what exists - but it should not look like live programming. */
.n42-freq.is-dark { opacity: 0.5; }
.n42-freq.is-dark .n42-freq-name::after { content: ' - off air'; }

.n42-freq-code { font-weight: 700; letter-spacing: 0.08em; font-size: 0.95em; }
.n42-freq-name { opacity: 0.7; font-size: 0.85em; }

.n42-panel .n42-now {
    color: #e8f2ff;
    padding: 0 0.2em;
    flex: 0 0 auto;
    font-size: 0.92em;
}

/* Attribution is a promise made at ingest, so it renders where a viewer can see
   it rather than only living in a database column. */
.n42-credit {
    color: #8fb4e8;
    opacity: 0.75;
    font-size: 0.74em;
    padding: 0 0.2em;
    flex: 0 0 auto;
}

.n42-panel .n42-sound {
    flex: 0 0 auto;
    background: rgba(10, 30, 70, 0.55);
    border: 1px solid rgba(90, 150, 255, 0.35);
    border-radius: 3px;
    color: #cfe3ff;
    padding: 0.35em 0.3em;
    cursor: pointer;
    font: inherit;
    /* SIZE CORRECTED 2026-09-14 (Vel: "slightly too large for where it sits").
       `font: inherit` above is a shorthand, so it RESETS font-size - and at (0,2,0) it
       outranks the base `.n42-sound { font-size: 0.72rem }` in node42-player.css at
       (0,1,0). The buttons were therefore inheriting .n42-panel-inner's readout scale,
       clamp(0.5rem, 0.95vw, 0.82rem), which is up to 14% larger than the base design
       intended. "Back to map" is the longest label in the bezel, so it showed first.
       min() rather than a flat 0.72rem: on a narrow viewport the panel's own clamp
       falls to 0.5rem, and pinning an absolute size there would make the buttons
       BIGGER than their surroundings - the same mistake in the other direction. */
    font-size: min(0.72rem, 1em);
    /* The bezel interior is a fixed, measured box. A control may not leave it,
       whatever a future label says. */
    box-sizing: border-box;
    width: 100%;
    max-width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* `margin-top: auto` was on EVERY .n42-sound, and in a column flex container auto
   margins SPLIT the free space between all the items that carry one - so the two
   buttons were pushed apart by half the bezel instead of sitting together at the
   bottom, which is what the original comment said it wanted. Put the auto margin on
   the first of the group only; the rest follow it with an ordinary gap. */
.n42-panel .n42-sound:not(.n42-exit) { margin-top: auto; }
.n42-panel .n42-exit { margin-top: 0.35em; }

.n42-panel .n42-sound:hover { background: rgba(20, 60, 130, 0.75); }

/* Below ~700px a panel beside a 16:9 set leaves the video too small to watch, so
   the cabinet stacks and the panel becomes a horizontal control strip. The art is
   dropped here on purpose: a 740x2126 bezel cannot be a wide strip. */
@media (max-width: 700px) {
    .n42-cabinet { flex-direction: column; }
    .n42-panel {
        aspect-ratio: auto;
        width: 100%;
        background-image: none !important;
        background: rgba(6, 16, 40, 0.9);
        border: 1px solid rgba(90, 150, 255, 0.35);
        border-radius: 6px;
    }
    .n42-panel-inner {
        position: static;
        width: auto;
        height: auto;
        padding: 0.6em;
        font-size: 0.8rem;
    }
    .n42-dial { flex-direction: row; flex-wrap: wrap; }
    .n42-freq { width: auto; flex: 1 1 30%; }
}
