/* /Components/Layout/MainLayout.razor.rz.scp.css */
.page[b-jxe3h01yd1] {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.topbar[b-jxe3h01yd1] {
    position: sticky;
    top: 0;
    z-index: 100;
    background: #17161a;
    color: #fff;
    box-shadow: var(--shadow);
}

/* Teletext colour rule under the bar — the one unmistakably broadcast flourish,
   and purely decorative so it carries no meaning to convey. */
.topbar[b-jxe3h01yd1]::after {
    content: "";
    display: block;
    height: 3px;
    background: linear-gradient(90deg,
        var(--tt-red) 0 16.6%,
        var(--tt-yellow) 16.6% 33.3%,
        var(--tt-green) 33.3% 50%,
        var(--tt-cyan) 50% 66.6%,
        var(--tt-blue) 66.6% 83.3%,
        var(--tt-magenta) 83.3% 100%);
}

.main-content[b-jxe3h01yd1] {
    flex: 1;
    padding: var(--sp-4);
}

.sitefooter[b-jxe3h01yd1] {
    flex: 0 0 auto;
    /* Wrapping is allowed but the gaps are sized so it does not need to on a desktop,
       because a second line would come out of the picture's height. */
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: center;
    gap: var(--sp-2) var(--sp-4);
    /* Tight vertically, roomy horizontally. On the home page every pixel here is taken
       from the television — the footer's height feeds --chrome, which sets how much of the
       window the picture may have — and this footer was spending more of itself on padding
       than on its own text. */
    padding: var(--sp-1) var(--sp-4);
    line-height: 1.4;
    text-align: center;
    font-size: 0.8rem;
    border-top: 1px solid var(--border);
    background: var(--surface);
}

.sitefooter-purpose[b-jxe3h01yd1] {
    color: var(--ink-muted, inherit);
}

/* The home page fills the viewport exactly, so a footer there would either be
   pushed off or steal height from the chat. It's reachable from every other page.

   Height as well as width: a phone in landscape is wider than the 800px threshold but
   far shorter, and there the footer was taking 45px of a 308px viewport — a sixth of
   the screen, for one link, while the picture went short of room. */
@media (max-width: 800px), (max-height: 600px) {
    .sitefooter[b-jxe3h01yd1] {
        display: none;
    }
}

#blazor-error-ui[b-jxe3h01yd1] {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss[b-jxe3h01yd1] {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }
/* /Components/Layout/NavMenu.razor.rz.scp.css */
/* Top navigation. Broadcast-style bar: dark, chunky, with a teletext colour rule
   under it. Positioning comes from MainLayout .topbar. */
.topnav[b-eei6f64ncz] {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    padding: var(--sp-2) var(--sp-4);
    flex-wrap: wrap;
}

.topnav-brand[b-eei6f64ncz] {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.35rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #fff;
    text-decoration: none;
}

/* Small teletext-style colour block beside the name. */
.topnav-brand-mark[b-eei6f64ncz] {
    width: 14px;
    height: 18px;
    background: linear-gradient(180deg,
        var(--tt-red) 0 33%,
        var(--tt-green) 33% 66%,
        var(--tt-cyan) 66% 100%);
    border-radius: 1px;
}

.topnav-panel[b-eei6f64ncz] {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    flex: 1 1 auto;
    flex-wrap: wrap;
}

.topnav-links[b-eei6f64ncz] {
    display: flex;
    align-items: center;
    gap: var(--sp-1);
    list-style: none;
    margin: 0;
    padding: 0;
    flex-wrap: wrap;
}

.topnav-account[b-eei6f64ncz] {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--sp-3);
}

.topnav-user[b-eei6f64ncz] {
    color: #cbd5e1;
    font-size: 0.9rem;
    max-width: 22ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

[b-eei6f64ncz] .nav-link {
    color: #e6e2da;
    text-decoration: none;
    padding: 0.4rem 0.7rem;
    border-radius: var(--radius-sm);
    display: inline-block;
    font-size: 0.95rem;
}

[b-eei6f64ncz] .nav-link:hover {
    background: rgba(255, 255, 255, 0.12);
    color: #fff;
}

/* Active page marked with a teletext-yellow underline rather than a fill. */
[b-eei6f64ncz] .nav-link.active {
    color: #fff;
    background: rgba(255, 255, 255, 0.08);
    box-shadow: inset 0 -3px 0 var(--tt-yellow);
}

.logout-form[b-eei6f64ncz] {
    display: inline;
    margin: 0;
}

.logout-form .btn-link[b-eei6f64ncz] {
    background: none;
    border: none;
    color: #e6e2da;
    cursor: pointer;
    padding: 0.4rem 0.7rem;
    font: inherit;
    font-size: 0.95rem;
}

.logout-form .btn-link:hover[b-eei6f64ncz] {
    text-decoration: underline;
    color: #fff;
}

/* ---- Collapsible menu button (narrow screens only) ---- */
.topnav-toggle[b-eei6f64ncz] {
    display: none;
    align-items: center;
    gap: var(--sp-2);
    margin-left: auto;
    padding: 0.45rem 0.7rem;
    font: inherit;
    font-size: 0.95rem;
    color: #e6e2da;
    background: rgba(255, 255, 255, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.22);
    border-radius: var(--radius-sm);
    cursor: pointer;
}

.topnav-toggle:hover[b-eei6f64ncz] {
    background: rgba(255, 255, 255, 0.18);
    color: #fff;
}

.topnav-toggle-bars[b-eei6f64ncz],
.topnav-toggle-bars[b-eei6f64ncz]::before,
.topnav-toggle-bars[b-eei6f64ncz]::after {
    display: block;
    width: 16px;
    height: 2px;
    background: currentColor;
    content: "";
}

.topnav-toggle-bars[b-eei6f64ncz] {
    position: relative;
}

.topnav-toggle-bars[b-eei6f64ncz]::before { position: absolute; top: -5px; }
.topnav-toggle-bars[b-eei6f64ncz]::after  { position: absolute; top: 5px; }

@media (max-width: 800px) {
    .topnav[b-eei6f64ncz] {
        gap: var(--sp-2);
    }

    .topnav-toggle[b-eei6f64ncz] {
        display: inline-flex;
    }

    /* Collapse keyed off aria-expanded, which is present in the server-rendered
       HTML — so the menu starts closed on the very first paint, with no dependency
       on script having run. (An earlier version keyed off an attribute JS added,
       which left the menu stuck open until it did.) Blazor Server needs JS anyway,
       so aria-expanded is a safe single source of truth. */
    .topnav-toggle[aria-expanded="false"] ~ .topnav-panel[b-eei6f64ncz] {
        display: none;
    }

    .topnav-toggle[aria-expanded="true"] ~ .topnav-panel[b-eei6f64ncz] {
        display: flex;
    }

    .topnav-panel[b-eei6f64ncz] {
        flex-direction: column;
        align-items: stretch;
        width: 100%;
        gap: var(--sp-2);
        padding-bottom: var(--sp-2);
    }

    .topnav-links[b-eei6f64ncz] {
        flex-direction: column;
        align-items: stretch;
    }

    [b-eei6f64ncz] .nav-link {
        display: block;
        padding: 0.6rem 0.7rem;
    }

    .topnav-account[b-eei6f64ncz] {
        margin-left: 0;
        flex-wrap: wrap;
        border-top: 1px solid rgba(255, 255, 255, 0.18);
        padding-top: var(--sp-2);
    }

    .topnav-user[b-eei6f64ncz] {
        max-width: none;
    }
}
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-uyqx1zlo01],
.components-reconnect-repeated-attempt-visible[b-uyqx1zlo01],
.components-reconnect-failed-visible[b-uyqx1zlo01],
.components-pause-visible[b-uyqx1zlo01],
.components-resume-failed-visible[b-uyqx1zlo01],
.components-rejoining-animation[b-uyqx1zlo01] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible[b-uyqx1zlo01],
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation[b-uyqx1zlo01],
#components-reconnect-modal.components-reconnect-paused .components-pause-visible[b-uyqx1zlo01],
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible[b-uyqx1zlo01],
#components-reconnect-modal.components-reconnect-retrying[b-uyqx1zlo01],
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible[b-uyqx1zlo01],
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation[b-uyqx1zlo01],
#components-reconnect-modal.components-reconnect-failed[b-uyqx1zlo01],
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible[b-uyqx1zlo01] {
    display: block;
}


/* Silent while it is only retrying.
   A circuit drops for a second whenever a phone changes network, locks, or the tab goes to
   the background, and it almost always comes straight back. Throwing a modal over the
   picture for that is worse than the interruption it announces — the stream carries on
   playing underneath, because video is not served over the circuit.

   The states that need a person are still shown: reconnection having given up, and the
   session being paused or failing to resume. Those leave the page genuinely inert, and
   hiding them would leave someone tapping a dead button with no explanation. */
#components-reconnect-modal.components-reconnect-show:not(.components-reconnect-failed)[b-uyqx1zlo01],
#components-reconnect-modal.components-reconnect-retrying:not(.components-reconnect-failed)[b-uyqx1zlo01] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show:not(.components-reconnect-failed)[b-uyqx1zlo01]::backdrop,
#components-reconnect-modal.components-reconnect-retrying:not(.components-reconnect-failed)[b-uyqx1zlo01]::backdrop {
    background-color: transparent;
    animation: none;
}

#components-reconnect-modal[b-uyqx1zlo01] {
    background-color: white;
    width: 20rem;
    margin: 20vh auto;
    padding: 2rem;
    border: 0;
    border-radius: 0.5rem;
    box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
    animation: components-reconnect-modal-fadeOutOpacity-b-uyqx1zlo01 0.5s both;
    &[open]

{
    animation: components-reconnect-modal-slideUp-b-uyqx1zlo01 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity-b-uyqx1zlo01 0.5s ease-in-out 0.3s;
    animation-fill-mode: both;
}

}

#components-reconnect-modal[b-uyqx1zlo01]::backdrop {
    background-color: rgba(0, 0, 0, 0.4);
    animation: components-reconnect-modal-fadeInOpacity-b-uyqx1zlo01 0.5s ease-in-out;
    opacity: 1;
}

@keyframes components-reconnect-modal-slideUp-b-uyqx1zlo01 {
    0% {
        transform: translateY(30px) scale(0.95);
    }

    100% {
        transform: translateY(0);
    }
}

@keyframes components-reconnect-modal-fadeInOpacity-b-uyqx1zlo01 {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes components-reconnect-modal-fadeOutOpacity-b-uyqx1zlo01 {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.components-reconnect-container[b-uyqx1zlo01] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

#components-reconnect-modal p[b-uyqx1zlo01] {
    margin: 0;
    text-align: center;
}

#components-reconnect-modal button[b-uyqx1zlo01] {
    border: 0;
    background-color: #6b9ed2;
    color: white;
    padding: 4px 24px;
    border-radius: 4px;
}

    #components-reconnect-modal button:hover[b-uyqx1zlo01] {
        background-color: #3b6ea2;
    }

    #components-reconnect-modal button:active[b-uyqx1zlo01] {
        background-color: #6b9ed2;
    }

.components-rejoining-animation[b-uyqx1zlo01] {
    position: relative;
    width: 80px;
    height: 80px;
}

    .components-rejoining-animation div[b-uyqx1zlo01] {
        position: absolute;
        border: 3px solid #0087ff;
        opacity: 1;
        border-radius: 50%;
        animation: components-rejoining-animation-b-uyqx1zlo01 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
    }

        .components-rejoining-animation div:nth-child(2)[b-uyqx1zlo01] {
            animation-delay: -0.5s;
        }

@keyframes components-rejoining-animation-b-uyqx1zlo01 {
    0% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    4.9% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    5% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 1;
    }

    100% {
        top: 0px;
        left: 0px;
        width: 80px;
        height: 80px;
        opacity: 0;
    }
}
/* /Components/StreamStatus/StreamViewer.razor.rz.scp.css */
/* =====================================================================
   Vintage 1970s/80s UK colour television set.
   Wood cabinet + CRT-shaped screen (4:3, cropped-to-fill). The streamed
   image itself is left untouched — no filters/scanlines over the video.
   The whole set is bounded to the viewport height so the page never scrolls.
   ===================================================================== */

.tv-set[b-nsepu3tzli] {
    --wood-light: #8a5c34;
    --wood-mid: #6f4a29;
    --wood-dark: #533619;
    --screen-radius: 16px / 13px;
    /* Space reserved around the screen so it fits the viewport.
       h-reserve: horizontal (chat column, controls, paddings).
       v-reserve: vertical (nav, page padding, cabinet chrome, caption).

       v-reserve is built from --chrome, the measured height of the nav, footer and page
       padding, plus 100px for the cabinet's own padding, the bezel and the caption beneath
       it — measured at 92px on a desktop, with the remainder as headroom.

       It used to be a flat 205, which was 19px short of what the cabinet actually needs. The
       error was invisible while the page reserved only 6rem for its own chrome, because the
       column was then 36px taller than the window and had room to absorb it. Correcting that
       exposed this: the caption carrying ON AIR or STANDBY was drawn past the end of its
       column and under the footer. Two mistakes had been cancelling out. */
    --h-reserve: calc(var(--chat-width, 340px) + var(--chat-reserve, 220px));
    --v-reserve: calc(var(--chrome, 132px) + 100px);
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    min-height: 0;
}

/* ---- Cabinet ---- */
.tv-cabinet[b-nsepu3tzli] {
    display: flex;
    gap: 14px;
    width: fit-content;      /* hug the screen + controls instead of the whole column */
    max-width: 100%;
    margin: 0 auto;
    padding: 16px 16px 18px;
    border-radius: 16px;
    box-sizing: border-box;
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.08), rgba(0, 0, 0, 0.22)),
        repeating-linear-gradient(87deg, rgba(40, 22, 8, 0.30) 0 2px, rgba(120, 80, 40, 0) 2px 8px),
        linear-gradient(90deg, var(--wood-dark), var(--wood-mid) 45%, var(--wood-light) 70%, var(--wood-mid));
    box-shadow:
        inset 0 2px 3px rgba(255, 255, 255, 0.15),
        inset 0 -6px 12px rgba(0, 0, 0, 0.4),
        0 12px 24px rgba(0, 0, 0, 0.45);
}

/* ---- Screen + bezel ---- */
.tv-screen-area[b-nsepu3tzli] {
    flex: 0 0 auto;   /* size to the screen so the cabinet hugs it */
    min-width: 0;
}

.tv-bezel[b-nsepu3tzli] {
    display: flex;
    justify-content: center;
    /* Centre, never stretch. A flex item stretches to its container's cross size by
       default, and the cabinet is a row whose height is set by the taller of its two
       sides — usually the control column, with the dial and speaker on it. That was
       pulling the tube taller than the 4:3 its width asks for: measured on an iPad in
       landscape it came out 520x424 where 520x390 was intended, and object-fit then
       cropped more off the sides to fill the extra height. The aspect-ratio property
       cannot help here; a stretched cross size wins over it. */
    align-items: center;
    padding: 14px;
    border-radius: 20px;
    background: linear-gradient(160deg, #2b2b2d, #111112 60%, #050506);
    box-shadow:
        inset 0 2px 4px rgba(255, 255, 255, 0.08),
        inset 0 -3px 8px rgba(0, 0, 0, 0.8),
        0 3px 6px rgba(0, 0, 0, 0.5);
}

.tv-screen[b-nsepu3tzli] {
    position: relative;
    /* The screen is the smaller of the width the layout allows and the height
       the viewport allows, so it stays 4:3, fills the space, and never scrolls.

       svh, not vh and not dvh. Measured on Edge for Android in landscape: innerHeight
       and clientHeight both 308px, while 100vh, 100dvh and 100lvh all reported 360px.
       Only 100svh gave 308. dvh is meant to track the chrome as it moves and there it
       simply does not, so sizing from it put 52px of picture below the bottom edge.

       svh is the viewport at its smallest — chrome fully shown — so it always fits.
       That costs a little height on browsers whose chrome does retract, which is the
       right way round: too small is a slightly smaller picture, too large is a picture
       running off the screen. This page never scrolls, so there is no dynamic case to
       track anyway. vh first, as a fallback for browsers without svh. */
    width: min(calc(100vw - var(--h-reserve)), calc((100vh - var(--v-reserve)) * 4 / 3));
    width: min(calc(100vw - var(--h-reserve)), calc((100svh - var(--v-reserve)) * 4 / 3));
    /* --vph is innerHeight, set from script on load and on every rotation. See App.razor:
       svh is wrong on Edge for Android and stale after rotation on iOS. */
    width: min(calc(100vw - var(--h-reserve)), calc((var(--vph, 100svh) - var(--v-reserve)) * 4 / 3));
    aspect-ratio: 4 / 3;
    overflow: hidden;
    border-radius: var(--screen-radius);
    background: #000;
}

/* Our own <video> fills the 4:3 screen. object-fit:cover scales the 16:9 stream
   to cover the screen, cropping the pillarbox black bars so the 4:3 content fills
   it exactly — no filters, the shown pixels are the stream's own. */
.tv-video[b-nsepu3tzli] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border: 0;
    background: #000;
    display: block;
}

/* Fullscreen has to undo all of that.
   The browser's own fullscreen styling is a UA rule, so the author rules above beat it —
   position:absolute wins over the UA's position:fixed, and the video goes on being laid
   out against .tv-screen, the small CRT box it normally sits in. The result is a
   fullscreen video positioned as though the cabinet were still around it, which is why
   it appeared off the screen.

   object-fit also flips. Cropping to 4:3 exists to fill the round-cornered CRT; in
   fullscreen there is no CRT to fill, so the whole frame is shown instead of having its
   sides cut off. */
.tv-video:fullscreen[b-nsepu3tzli],
.tv-video:-webkit-full-screen[b-nsepu3tzli] {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    object-fit: contain;
}

/* Fallback: Owncast embed iframe (best-effort fill; it can't be object-fit cropped). */
.tv-embed[b-nsepu3tzli] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
    background: #000;
    display: block;
}

/* ---- Player status overlay (loading / reconnecting / error) ---- */
.tv-status[b-nsepu3tzli] {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    pointer-events: none;   /* let the video controls beneath stay usable */
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 0.95rem;
    letter-spacing: 0.03em;
}

.tv-status.error[b-nsepu3tzli] {
    color: #ffb3ac;
}

.tv-status-dot[b-nsepu3tzli] {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: currentColor;
    animation: tv-pulse-b-nsepu3tzli 1.1s ease-in-out infinite;
}

@keyframes tv-pulse-b-nsepu3tzli {
    0%, 100% { opacity: 0.25; }
    50% { opacity: 1; }
}

/* Tap-to-unmute affordance (autoplay starts muted) */
.tv-unmute[b-nsepu3tzli] {
    position: absolute;
    left: 50%;
    bottom: 14%;
    transform: translateX(-50%);
    border: 0;
    border-radius: 999px;
    padding: 0.4rem 0.9rem;
    cursor: pointer;
    font-size: 0.85rem;
    color: #111;
    background: rgba(255, 255, 255, 0.9);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.5);
}

.tv-unmute:hover[b-nsepu3tzli] {
    background: #fff;
}

/* ---- Off air: analogue snow ---- */
.tv-testcard[b-nsepu3tzli] {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #0b0b0b;
}

/* Scaled up only slightly, so the grain stays fine. Smoothing (the default) is
   kept rather than pixelated, which keeps it soft instead of blocky. */
.tv-snow[b-nsepu3tzli] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0.7;
}

.tv-nosignal[b-nsepu3tzli] {
    position: relative;   /* above the snow */
    max-width: 82%;
    padding: 1rem 1.4rem;
    text-align: center;
    color: #fff;
    background: rgba(0, 0, 0, 0.82);
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 4px;
    font-family: var(--font-body);
}

.tv-nosignal[b-nsepu3tzli]  h1,
.tv-nosignal[b-nsepu3tzli]  h2 {
    margin: 0 0 0.4rem;
}

.tv-nosignal[b-nsepu3tzli]  p {
    margin: 0.2rem 0;
}

.tv-lastlive[b-nsepu3tzli] {
    margin-top: 0.75rem !important;
    padding-top: 0.6rem;
    border-top: 1px solid rgba(255, 255, 255, 0.25);
    font-size: 0.85rem;
    color: #cfcfcf;
}

/* ---- Control panel ---- */
.tv-controls[b-nsepu3tzli] {
    flex: 0 0 100px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    padding: 10px 8px;
    border-radius: 12px;
    background:
        linear-gradient(180deg, rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0.05)),
        linear-gradient(90deg, var(--wood-mid), var(--wood-dark));
    box-shadow: inset 0 1px 2px rgba(255, 255, 255, 0.12), inset 0 -4px 8px rgba(0, 0, 0, 0.4);
}

.tv-brand[b-nsepu3tzli] {
    display: flex;
    align-items: center;
    gap: 6px;
}

.tv-brand-name[b-nsepu3tzli] {
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-weight: 700;
    font-size: 0.6rem;
    letter-spacing: 0.12em;
    color: #e8d8b0;
    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.6);
}

.tv-led[b-nsepu3tzli] {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #5c1a12;
    box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.8);
}

.tv-led.on[b-nsepu3tzli] {
    background: #ff3b2f;
    box-shadow: 0 0 6px 1px rgba(255, 59, 47, 0.9), inset 0 0 2px rgba(255, 255, 255, 0.6);
}

/* Rotary channel dial */
.tv-dial[b-nsepu3tzli] {
    width: 60px;
    height: 60px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: radial-gradient(circle at 38% 32%, #f0f0ef, #c9c9c6 45%, #8f8f8c 75%, #6a6a67);
    box-shadow:
        0 2px 4px rgba(0, 0, 0, 0.5),
        inset 0 2px 3px rgba(255, 255, 255, 0.7),
        inset 0 -3px 5px rgba(0, 0, 0, 0.35);
}

.tv-dial-number[b-nsepu3tzli] {
    font-family: 'Courier New', monospace;
    font-weight: 700;
    font-size: 1.3rem;
    color: #222;
}

.tv-knob-row[b-nsepu3tzli] {
    display: flex;
    gap: 12px;
}

.tv-knob[b-nsepu3tzli] {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: radial-gradient(circle at 38% 32%, #4a4a4a, #232323 70%, #111);
    box-shadow: 0 2px 3px rgba(0, 0, 0, 0.5), inset 0 1px 1px rgba(255, 255, 255, 0.25);
    position: relative;
}

.tv-knob[b-nsepu3tzli]::after {
    content: "";
    position: absolute;
    top: 3px;
    left: 50%;
    width: 2px;
    height: 7px;
    transform: translateX(-50%);
    background: #cfcfcf;
    border-radius: 1px;
}

/* Fullscreen / cast buttons, styled like chunky vintage push-buttons */
.tv-buttons[b-nsepu3tzli] {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    justify-content: center;
}

.tv-fs-btn[b-nsepu3tzli], .tv-cast-btn[b-nsepu3tzli] {
    width: 40px;
    height: 28px;
    border: 0;
    border-radius: 5px;
    cursor: pointer;
    font-size: 0.95rem;
    color: #eee;
    background: linear-gradient(180deg, #3a3a3a, #1c1c1c);
    box-shadow: 0 2px 3px rgba(0, 0, 0, 0.5), inset 0 1px 1px rgba(255, 255, 255, 0.2);
}

.tv-fs-btn:hover[b-nsepu3tzli], .tv-cast-btn:hover[b-nsepu3tzli] {
    color: #fff;
    background: linear-gradient(180deg, #464646, #242424);
}

.tv-fs-btn:active[b-nsepu3tzli], .tv-cast-btn:active[b-nsepu3tzli] {
    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.6);
}

/* Lit up while a cast session is running. */
.tv-cast-btn.casting[b-nsepu3tzli] {
    background: linear-gradient(180deg, #1d6fb8, #12507f);
    box-shadow: 0 0 6px 1px rgba(41, 128, 185, 0.8), inset 0 1px 1px rgba(255, 255, 255, 0.3);
}

/* Speaker grille */
.tv-speaker[b-nsepu3tzli] {
    width: 100%;
    flex: 1 1 auto;
    min-height: 34px;
    border-radius: 6px;
    background:
        repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.55) 0 2px, rgba(0, 0, 0, 0) 2px 6px),
        linear-gradient(180deg, #3a2513, #241407);
    box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.7);
}

/* ---- Caption below the set (holds the API stats — never cropped) ---- */
.tv-caption[b-nsepu3tzli] {
    margin-top: 10px;
    display: flex;
    /* One line, always. Off air this reads STANDBY alone; live it gains a duration and a
       viewer count, and a second line would be 20px the picture had already been given.
       The reserve above assumes a caption of a known height, so this is what makes that
       assumption true rather than hopeful. */
    flex-wrap: nowrap;
    white-space: nowrap;
    min-width: 0;
    overflow: hidden;
    align-items: center;
    gap: 12px;
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 0.85rem;
    color: #444;
}

.tv-onair[b-nsepu3tzli] {
    color: #c0392b;
    font-weight: 700;
    letter-spacing: 0.08em;
}

.tv-standby[b-nsepu3tzli] {
    color: #888;
    font-weight: 700;
    letter-spacing: 0.12em;
}

.tv-stat[b-nsepu3tzli] {
    color: #333;
    font-variant-numeric: tabular-nums;
}

.tv-title[b-nsepu3tzli] {
    color: #555;
    font-style: italic;
}

.tv-casting[b-nsepu3tzli] {
    color: #12507f;
    font-weight: 700;
}

/* ---- Narrow screens ---- */
/* ---- Mobile: no cabinet, just the picture ----
   The wood surround and its control column are charm, not information, and on a
   phone they cost width the video needs — the cabinet used to overflow the
   viewport because of them. Below 800px the set is stripped back to the screen
   itself, with the buttons moved beneath it. The 4:3 crop stays: the source is
   16:9 with 4:3 content pillarboxed, so cropping is what removes the black bars. */
/* ---- Plain screen: the cabinet stripped back to a picture ----
   Driven by a class rather than by media query alone, because the three cases that
   want it cannot be expressed as one query. A narrow phone is a width; a phone on
   its side is a height; a television is neither — its viewport is indistinguishable
   from a desktop, and only the person watching knows they are ten feet away. The
   script in App.razor ORs the three together and sets the class, which leaves this
   file with a single definition of what "plain" looks like instead of three copies
   drifting apart. */
html.plain-screen .tv-cabinet[b-nsepu3tzli] {
    display: block;
    width: 100%;
    padding: 0;
    border-radius: var(--radius);
    background: #000;
    box-shadow: var(--shadow);
}

html.plain-screen .tv-bezel[b-nsepu3tzli] {
    padding: 0;
    border-radius: var(--radius);
    background: #000;
    box-shadow: none;
}

html.plain-screen .tv-screen[b-nsepu3tzli] {
    margin: 0 auto;
    border-radius: var(--radius);
}

/* Keep the useful controls, drop the decoration. */
html.plain-screen .tv-controls[b-nsepu3tzli] {
    flex-direction: row;
    justify-content: center;
    gap: var(--sp-3);
    padding: var(--sp-2);
    background: none;
    box-shadow: none;
}

html.plain-screen .tv-brand[b-nsepu3tzli],
html.plain-screen .tv-dial[b-nsepu3tzli],
html.plain-screen .tv-knob-row[b-nsepu3tzli],
html.plain-screen .tv-speaker[b-nsepu3tzli] {
    display: none;
}

/* The cabinet is not on offer here — it needs width beside the picture for its
   controls, and a phone held upright has none to spare — so the control that asks
   for it goes away rather than sitting there doing harm. Everywhere else, including
   the same phone turned on its side, the cabinet is the default. */
@media (max-width: 800px) and (orientation: portrait) {
    .tv-plain-btn[b-nsepu3tzli] {
        display: none;
    }
}

/* ---- Portrait mobile: picture above chat ----
   Cap the picture's share of the screen so the chat below always has usable room.
   Constraining width rather than height keeps the 4:3 intact.

   Orientation rather than a height threshold: this is about a phone being upright,
   which is exactly what the feature tests, and it does not need a pixel figure
   chosen to sit between two device sizes. */
@media (max-width: 1024px) and (orientation: portrait) {
    .tv-set[b-nsepu3tzli] {
        --h-reserve: 8px;
        --v-reserve: 300px;
    }

    /* Capped at 42% of the height rather than measured against a reserve, because the chat
       sits below and needs the rest. The width term is spelled out as 100vw minus the
       reserve instead of 100%, which would mean "all of .tv-screen-area" — and that box is
       sized to its contents, so the picture would be asking how wide it is. */
    .tv-screen[b-nsepu3tzli] {
        width: min(100%, calc(42svh * 4 / 3));
        width: min(calc(100vw - var(--h-reserve)), calc(var(--vph, 100svh) * 0.42 * 4 / 3));
    }
}

/* Tablet portrait keeps the cabinet — it is only a phone held upright that cannot afford
   one — so the controls stand in their column beside the picture and need width of their
   own, which a phone stacking them underneath does not. */
@media (min-width: 801px) and (max-width: 1024px) and (orientation: portrait) {
    .tv-set[b-nsepu3tzli] {
        --h-reserve: 160px;
    }
}

/* ---- Landscape phones: cabinet, beside the chat ----
   The cabinet stays, and the controls sit in their usual column beside the picture,
   so nothing but the caption is stacked underneath it.

   What has to be reserved is everything that is not the picture: the nav and footer
   (about 100px), the cabinet's own padding and the bezel around the tube (about 60px
   between them), and the caption. The caption is the one that matters — it carries ON
   AIR, the viewer count and the duration, in a live region. Reserve too little and the
   picture pushes it out of the clipped area, where it is lost rather than scrolled to. */
@media (max-height: 600px) {
    /* Measured on an 848x308 viewport — a real phone in landscape, not a guess. With the
       footer hidden the stream column gets 221px, and the cabinet, bezel and caption take
       58 of them, so 145 is the figure that fits exactly. 150 is used, because exact fits
       have failed twice here the moment something grew by a line. */
    .tv-set[b-nsepu3tzli] {
        --v-reserve: 150px;
    }

    /* Kept to one line, so the 58px above stays 58px. Off air the caption reads ON AIR
       alone; live it gains a duration and a viewer count, and wrapping to a second line
       is precisely what pushed it under the column's overflow before. */
    .tv-caption[b-nsepu3tzli] {
        flex-wrap: nowrap;
        white-space: nowrap;
        min-width: 0;
        overflow: hidden;
        font-size: 0.8rem;
    }

    /* The channel dial and the speaker grille go. Together they are 94px of a column that
       stands beside the picture, and because the cabinet is a row, the taller of the two
       sides sets its height — so that 94px was being taken out of the picture even though
       the picture had nothing to do with it. Shrinking the picture did not help, which is
       what made this hard to see: the set stayed exactly 273px tall however small the
       picture got. The wood, the bezel, the brand and the working buttons all stay. */
    .tv-dial[b-nsepu3tzli],
    .tv-speaker[b-nsepu3tzli] {
        display: none;
    }

    /* The cabinet keeps its wood and its shape, but not its generous padding. Measured on
       a 390px-tall screen, the surround and bezel were taking 101px — a quarter of the
       display — before the picture had any. Thinner trim gives about 34px of that back,
       which is the difference between a caption that fits and one that is clipped away. */
    .tv-cabinet[b-nsepu3tzli] {
        padding: 8px;
    }

    .tv-bezel[b-nsepu3tzli] {
        padding: 6px;
    }

    /* Stripped back on request, there is no cabinet padding or bezel to allow for, so the
       picture may have that space instead. Measured: 29px of chrome against the cabinet's
       58, needing a reserve of 116.

       This had been left at 165 after the cabinet's own figure came down to 150, which put
       it the wrong way round — asking for the plain screen made the picture smaller than
       leaving the cabinet in place, and 49px of the column went unused. */
    html.plain-screen .tv-set[b-nsepu3tzli] {
        --v-reserve: 120px;
    }

    html.plain-screen .tv-cabinet[b-nsepu3tzli] {
        display: flex;
        width: auto;
    }

    html.plain-screen .tv-controls[b-nsepu3tzli] {
        flex-direction: column;
        justify-content: center;
    }
}
