/* TV Class — Modern edu SaaS design system
   "Mini-glass" — soft tinted gradient page background, semi-translucent cards
   with backdrop-filter where supported, gentle golden accents on key strokes.
   RTL/LTR-safe via CSS logical properties (no JS), and the font stack falls
   back to Cairo for Arabic glyphs and Inter for Latin ones. */

:root {
    --bg: #F6F8FC;
    --bg-elev: #FFFFFF;
    --surface-2: #F1F4FA;
    --border: #E4E8F0;
    --border-strong: #CBD3E1;
    --glass-bg: rgba(255, 255, 255, 0.74);
    --glass-border: rgba(255, 255, 255, 0.5);
    --glass-edge: rgba(15, 23, 42, 0.06);

    --ink-900: #0B1220;
    --ink-700: #1F2A44;
    --ink-500: #475569;
    --ink-400: #64748B;
    --ink-300: #94A3B8;

    /* Palette derived from the launcher icon:
       deep navy stage, warm gold "TV" mark, green leaves, accent red star.
       Brand = navy, accent = gold (CTAs), success = green. */
    --brand: #0E2A5E;
    --brand-600: #091F4A;
    --brand-50: #E6ECF7;
    --accent: #F5C518;
    --accent-600: #D9A912;
    --accent-50: #FFF6D6;
    --gold: #F5C518;
    --gold-50: #FFF6D6;

    --success: #22C55E;
    --success-50: #E7F8EE;
    --warn: #F59E0B;
    --warn-50: #FFF7E6;
    --danger: #EF4444;
    --danger-50: #FEF2F2;

    --radius-sm: 8px;
    --radius: 12px;
    --radius-lg: 18px;
    --radius-pill: 999px;

    --shadow-1: 0 1px 2px rgba(15, 23, 42, 0.06), 0 1px 1px rgba(15, 23, 42, 0.04);
    --shadow-2: 0 12px 32px rgba(15, 23, 42, 0.10), 0 2px 6px rgba(15, 23, 42, 0.04);
    --shadow-brand: 0 10px 30px rgba(14, 42, 94, 0.22);
    --shadow-glass: 0 14px 38px rgba(15, 23, 42, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.6);

    --font-sans: "Inter", "Cairo", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
    --font-ar:   "Cairo", "Inter", "Segoe UI", system-ui, sans-serif;
    --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    color: var(--ink-700);
    font-family: var(--font-sans);
    font-size: 15px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    /* Guard against accidental horizontal scrollbars from wide elements
       (TV-sized cards on a narrow controller viewport, gradient overflow,
       inline images, …). overflow-x: clip is the modern non-scrollable
       clip; fall back to hidden for older Chromiums on TV boxes. */
    overflow-x: hidden;
    overflow-x: clip;
    max-width: 100%;
    /* Static mini-glass background: a base wash plus three soft radial blooms.
       Cheaper than animation, lighter than backdrop on body. */
    background:
        radial-gradient(900px 600px at 12% -10%, rgba(14, 42, 94, 0.10), transparent 60%),
        radial-gradient(800px 500px at 110% 8%,  rgba(245, 197, 24, 0.10), transparent 60%),
        radial-gradient(700px 500px at 50% 110%, rgba(34, 197, 94, 0.08), transparent 60%),
        var(--bg);
    background-attachment: fixed;
    min-height: 100vh;
}

/* Arabic content (page-level RTL, individual blocks marked lang="ar") gets
   Cairo as the primary face for clearer Arabic shaping. */
html[lang^="ar"], [lang^="ar"], html[dir="rtl"] { font-family: var(--font-ar); }

a { color: var(--brand); text-decoration: none; }
a:hover { color: var(--brand-600); }

/* Layout shell */
.shell {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}
.shell-header {
    padding: 6px 12px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid var(--glass-edge);
    background: var(--glass-bg);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
    backdrop-filter: saturate(180%) blur(14px);
    position: sticky; top: 0; z-index: 5;
}
/* The `hidden` HTML attribute would normally hide the fallback header in
   the app (where the native top bar owns the title row), but a base
   `.shell-header { display: flex }` rule above overrides `hidden`'s
   `display:none`. This selector wins because it carries `display: none`
   on the same element with the attribute — restoring the expected
   `hidden` semantics so the duplicate bar stays out of the WebView. */
.shell-header[hidden] { display: none; }
@media (min-width: 720px) {
    .shell-header { padding: 12px 24px; }
}
.shell-body {
    /* On mobile we go block-display with zero padding so the panel inside
       is unambiguously 100 vw wide. Flex centering kicks in only at
       720 px+, where there's room for a constrained card layout. */
    flex: 1;
    display: block;
    padding: 0;
}
@media (min-width: 720px) {
    .shell-body {
        display: flex;
        align-items: flex-start;
        justify-content: center;
        padding: 12px 16px 16px;
    }
}
.shell-body.start-top { align-items: flex-start; padding-top: 56px; }
.shell-footer {
    padding: 14px 28px;
    text-align: center;
    color: var(--ink-300);
    font-size: 12.5px;
}

/* Brand */
.brand {
    display: flex;
    align-items: center;
    gap: 10px;
    font-weight: 700;
    color: var(--ink-900);
    letter-spacing: -0.01em;
}
.brand-mark {
    /* Miniature TV screen — same colour story as the launcher icon.
       Outer navy bezel + slightly inset gold-on-navy "screen" so the mark
       reads as a tiny TV at any size. */
    width: 26px; height: 26px;
    border-radius: 7px;
    background: var(--brand);
    border: 1.5px solid var(--brand-600);
    box-shadow: 0 3px 8px rgba(14,42,94,0.28), inset 0 1px 0 rgba(255,255,255,0.10);
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--accent); font-weight: 900; font-size: 11px;
    letter-spacing: 0.04em;
    position: relative;
}
@media (min-width: 720px) {
    .brand-mark { width: 34px; height: 34px; border-radius: 9px;
                  border-width: 2px; font-size: 12.5px; }
}
.brand-mark::after {
    /* Tiny gold "stand" hint under the TV — the same silhouette as the
       launcher icon's framed look. */
    content: '';
    position: absolute;
    bottom: -4px; left: 50%;
    transform: translateX(-50%);
    width: 12px; height: 3px;
    border-radius: 0 0 3px 3px;
    background: var(--accent);
    opacity: .9;
}
.brand-title { font-size: 15px; }
.brand-sub { color: var(--ink-300); font-weight: 500; font-size: 12.5px; margin-inline-start: 4px; }

/* Status pills inside the brand row — small icon-only chips. The role
   pill sits flush against the brand; the connection pill follows and
   gets a coloured background once it's live/off. */
.header-pill {
    display: inline-flex; align-items: center; justify-content: center;
    margin-inline-start: 6px;
    padding: 2px 7px;
    border-radius: 99px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    color: var(--ink-700);
    font-size: 13px; line-height: 1;
    min-width: 24px;
    user-select: none;
}
.header-pill.live { background: var(--success-50); border-color: var(--success); }
.header-pill.off  { background: var(--danger-50);  border-color: var(--danger); }
#headerRolePill { margin-inline-start: 10px; } /* leading pill gets a wider gap from the brand */

/* Small icon button used by the header refresh action. Minimal chrome so
   it doesn't compete with the brand on the same row. */
.header-icon-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 32px; height: 32px;
    margin-inline-start: auto;
    padding: 0;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 50%;
    color: var(--ink-500);
    cursor: pointer;
    transition: background .15s ease, border-color .15s ease, color .15s ease, transform .12s ease;
}
.header-icon-btn:hover { background: var(--surface-2); color: var(--brand); border-color: var(--brand); }
.header-icon-btn:active { transform: rotate(-180deg); }
.header-icon-btn:focus,
.header-icon-btn:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.header-icon-btn svg { width: 18px; height: 18px; display: block; }
@media (min-width: 720px) {
    .header-icon-btn { width: 36px; height: 36px; }
    .header-icon-btn svg { width: 20px; height: 20px; }
}

/* Header status pills — small icon-only badges opposite the brand.
   Compact, always LTR (emojis sit in a fixed row regardless of page direction). */
.header-status {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-inline-start: auto;
    direction: ltr;
}
.header-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 28px;
    padding: 3px 8px;
    border-radius: 99px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    font-size: 14px;
    line-height: 1;
    user-select: none;
    transition: background .15s ease, border-color .15s ease;
}
.header-pill.live { background: var(--success-50); border-color: var(--success); }
.header-pill.off  { background: var(--danger-50); border-color: var(--danger); }
body.role-tv .header-pill { min-width: 34px; padding: 4px 10px; font-size: 16px; }

/* Card — mini-glass: translucent fill, soft inner highlight, generous shadow. */
.card {
    background: var(--glass-bg);
    -webkit-backdrop-filter: saturate(180%) blur(18px);
    backdrop-filter: saturate(180%) blur(18px);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-glass);
    padding: 32px;
    width: 100%;
    max-width: 560px;
    position: relative;
}
/* Faint golden hairline along the top edge of every card — the "fancy" touch. */
.card::before {
    content: '';
    position: absolute; inset: 0;
    border-radius: inherit;
    pointer-events: none;
    background: linear-gradient(180deg, rgba(200, 162, 74, 0.35), transparent 8%);
    mix-blend-mode: multiply;
    opacity: .55;
}
.card.wide {
    width: 100%;
    /* Mobile: span the viewport edge-to-edge, NO max-width clamp, no side
       padding, no decorative border. The lesson cards inside carry their
       own padding so the grid is the only thing that owns horizontal
       space. Below the title we leave 4 px so it's not flush. */
    max-width: none;
    padding: 4px 0 8px;
    border-radius: 0;
    border: 0;
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    box-shadow: none;
}
.card.wide::before { content: none; } /* drop the golden hairline overlay on mobile */
.card.wide p.lede   { margin: 0 6px 6px; }

/* Page title inside the page — sticky at the top so it stays visible while
   the cards scroll under it. A solid background covers the scrolling
   content; no explicit text-align so the page's natural lang/dir on
   <html> (set by i18n.php) drives the alignment (LTR → left, RTL → right)
   without any JS. Padding is logical so it mirrors automatically too. */
.card.wide h1.title {
    position: sticky;
    top: 0;
    z-index: 4;
    margin: 0 0 6px;
    padding: 8px 12px;
    background: var(--bg-elev);
    border-bottom: 1px solid var(--border);
    font-size: 18px; line-height: 1.2;
}

@media (min-width: 720px) {
    .card.wide {
        max-width: 880px;
        padding: 12px 20px;
        border-radius: var(--radius-lg);
        border: 1px solid var(--glass-border);
        background: var(--glass-bg);
        -webkit-backdrop-filter: saturate(180%) blur(18px);
        backdrop-filter: saturate(180%) blur(18px);
        box-shadow: var(--shadow-glass);
    }
    .card.wide::before { content: ''; }
    .card.wide h1.title { font-size: 24px; margin: 0 0 8px; }
    .card.wide p.lede   { margin: 0 0 8px; }
}
body.role-tv .card.wide,
body.view-tv .card.wide { padding: 14px 20px; }
body.role-tv .card.wide h1.title,
body.view-tv .card.wide h1.title { font-size: 26px; margin: 0 0 8px; }
.card.tv  { max-width: 1100px; padding: 40px; }

.kicker {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 4px 10px;
    background: var(--brand-50);
    color: var(--brand);
    border-radius: var(--radius-pill);
    font-size: 12px; font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}
.kicker.accent { background: var(--accent-50); color: #0F766E; }

h1.title {
    font-size: 28px; line-height: 1.2;
    color: var(--ink-900);
    margin: 14px 0 8px;
    letter-spacing: -0.02em;
    font-weight: 700;
}
h2.subtitle {
    font-size: 18px;
    color: var(--ink-700);
    margin: 0 0 6px;
    font-weight: 600;
}
p.lede { color: var(--ink-500); margin: 0 0 22px; }
p.muted { color: var(--ink-400); }

/* Buttons */
.btn {
    appearance: none;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    padding: 11px 18px;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    transition: transform .08s ease, box-shadow .15s ease, background .15s ease, color .15s ease, border-color .15s ease;
    text-decoration: none;
}
.btn:active { transform: translateY(1px); }
.btn-primary {
    background: var(--brand);
    color: #fff;
    box-shadow: var(--shadow-brand);
}
.btn-primary:hover { background: var(--brand-600); color: #fff; }
.btn-secondary {
    background: var(--bg-elev);
    color: var(--ink-700);
    border-color: var(--border-strong);
}
.btn-secondary:hover { background: var(--surface-2); }
.btn-ghost {
    background: transparent;
    color: var(--ink-500);
}
.btn-ghost:hover { color: var(--ink-900); background: var(--surface-2); }
.btn-danger {
    background: var(--danger);
    color: #fff;
}
.btn-danger:hover { background: #DC2626; color: #fff; }
.btn-block { width: 100%; }
.btn-lg { padding: 14px 22px; font-size: 16px; border-radius: var(--radius); }

.btn-row { display: flex; gap: 10px; flex-wrap: wrap; }

/* Role picker (start screen) */
.role-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
    margin-top: 8px;
}
@media (max-width: 620px) {
    .role-grid { grid-template-columns: 1fr; }
}
.role-card {
    appearance: none;
    text-align: left;
    background: var(--bg-elev);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 22px;
    cursor: pointer;
    transition: border-color .15s ease, transform .08s ease, box-shadow .15s ease;
    font: inherit;
    color: inherit;
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-height: 180px;
}
.role-card:hover {
    border-color: var(--brand);
    box-shadow: var(--shadow-2);
    transform: translateY(-1px);
}
.role-card .role-icon {
    width: 44px; height: 44px; border-radius: 12px;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--brand-50); color: var(--brand);
}
.role-card .role-icon.accent { background: var(--accent-50); color: #0F766E; }
.role-card h3 { margin: 0; font-size: 17px; color: var(--ink-900); }
.role-card p { margin: 0; color: var(--ink-500); font-size: 13.5px; }

/* Status pills */
.pill {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 5px 11px;
    border-radius: var(--radius-pill);
    font-size: 12.5px; font-weight: 600;
    background: var(--surface-2);
    color: var(--ink-500);
}
.pill .dot {
    width: 8px; height: 8px; border-radius: 50%;
    background: currentColor; opacity: .85;
}
.pill.waiting { background: var(--warn-50); color: #92400E; }
.pill.paired  { background: var(--success-50); color: #065F46; }
.pill.error   { background: var(--danger-50); color: #991B1B; }
.pill.live {
    background: var(--success-50); color: #065F46;
}
.pill.live .dot {
    animation: pulseDot 1.4s ease-in-out infinite;
}
@keyframes pulseDot {
    0%,100% { transform: scale(1); opacity: .85; }
    50%     { transform: scale(1.4); opacity: 1; }
}

/* Status text */
.status {
    margin-top: 18px;
    padding: 12px 14px;
    background: var(--surface-2);
    color: var(--ink-500);
    border-radius: var(--radius);
    font-size: 13.5px;
}
.status.error { background: var(--danger-50); color: #991B1B; }
.status.success { background: var(--success-50); color: #065F46; }

/* Meta */
.meta {
    margin-top: 22px;
    padding-top: 18px;
    border-top: 1px dashed var(--border);
    color: var(--ink-400);
    font-size: 12.5px;
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 4px 16px;
}
.meta dt { color: var(--ink-300); }
.meta dd { margin: 0; color: var(--ink-500); }

/* QR */
.qr-stage {
    display: grid;
    grid-template-columns: minmax(280px, 360px) 1fr;
    gap: 32px;
    align-items: center;
    margin-top: 14px;
}
@media (max-width: 820px) {
    .qr-stage { grid-template-columns: 1fr; }
}
.qr-frame {
    background: #fff;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 18px;
    box-shadow: var(--shadow-2);
    display: flex; align-items: center; justify-content: center;
    aspect-ratio: 1 / 1;
    position: relative;
    overflow: hidden;
}
.qr-frame img { width: 100%; height: 100%; object-fit: contain; display: block; }
.qr-frame.loading::after {
    content: '';
    position: absolute; inset: 0;
    background: linear-gradient(110deg, transparent 30%, rgba(79,70,229,0.08) 50%, transparent 70%);
    animation: shimmer 1.4s linear infinite;
}
@keyframes shimmer { 0% { transform: translateX(-100%);} 100% { transform: translateX(100%);} }

.code-display {
    font-family: var(--font-mono);
    font-size: 38px;
    letter-spacing: 0.3em;
    color: var(--ink-900);
    background: var(--surface-2);
    border-radius: var(--radius);
    padding: 14px 18px;
    text-align: center;
    margin-top: 14px;
}

.steps { list-style: none; padding: 0; margin: 18px 0 0; }
.steps li {
    display: flex; gap: 12px; padding: 10px 0;
    color: var(--ink-500);
}
.steps li .num {
    flex: 0 0 26px; height: 26px;
    border-radius: 50%;
    background: var(--brand-50); color: var(--brand);
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 13px; font-weight: 700;
}

/* TV (room) full-bleed layout
   TVs typically overscan ~5% from each edge, so chrome-style padding has
   to be generous to keep the layout fully visible. */
.tv-stage {
    min-height: 100vh;
    background:
        radial-gradient(1200px 600px at 80% -10%, rgba(79,70,229,0.10), transparent 60%),
        radial-gradient(900px 500px at -10% 110%, rgba(20,184,166,0.10), transparent 60%),
        var(--bg);
    display: flex; align-items: center; justify-content: center;
    padding: 64px 80px;
    position: relative;
    overflow: hidden;
}

/* ─── tv-pair: compact pairing layout ───
   Used by room.php. The stage owns the viewport (100 vh, overflow hidden)
   and centers a single card. The card splits into two columns aligned to
   the same top edge: a QR column (QR + icon refresh) on one side and an
   info column (title, code, status, text actions) on the other. RTL
   automatically swaps which side is which via flex row direction.
   fit-screen.js scales the card down whenever its natural size exceeds
   the viewport so nothing ever scrolls. */
.tv-stage.tv-pair {
    padding: 16px 20px;
    min-height: 100vh;
    height: 100vh;
    overflow: hidden;
    align-items: center;
}
.tv-pair-card {
    width: 100%;
    max-width: 980px;
    display: flex;
    flex-direction: row;
    align-items: flex-start;   /* both columns start at the same top */
    justify-content: center;
    gap: 24px;
    text-align: start;
    transform-origin: center center;
    will-change: transform;
}
.tv-pair-col { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.tv-pair-qr-col {
    flex: 0 0 auto;
    align-items: center;
}
.tv-pair-qr-col .qr-frame {
    width: 220px; height: 220px;
    padding: 8px;
    aspect-ratio: 1 / 1;
}
.tv-pair-info-col {
    flex: 1 1 auto;
}
.tv-pair-info-col .kicker { align-self: flex-start; }
.tv-pair-info-col h1 {
    margin: 0;
    font-size: 22px; line-height: 1.15;
    color: var(--ink-900);
    letter-spacing: -0.02em;
}
.tv-pair-info-col .lede {
    margin: 0;
    font-size: 13.5px; line-height: 1.4;
    color: var(--ink-500);
    max-width: 56ch;
}
.tv-pair-info-col .code-display {
    margin: 0;
    font-size: 30px;
    padding: 10px 14px;
    letter-spacing: 0.2em;
    text-align: center;
}
.tv-pair-pills { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.tv-pair-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    align-items: center;
}
.tv-pair-actions .btn-sm {
    padding: 8px 14px;
    font-size: 13.5px;
    border-radius: 10px;
}

/* Circular icon-only button — used for the refresh affordance under the
   QR. Sized identically to the bottom-nav buttons so the visual rhythm
   matches; large character glyph centered with no text padding. */
.btn-circle {
    width: 48px; height: 48px;
    padding: 0;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 22px;
    line-height: 1;
}

/* TV mode — slightly larger type / QR so the room reads from across the
   room. Same two-column layout, just bigger numbers. */
body.role-tv .tv-pair-card,
body.view-tv .tv-pair-card { max-width: 1180px; gap: 32px; }
body.role-tv .tv-pair-qr-col .qr-frame,
body.view-tv .tv-pair-qr-col .qr-frame { width: 280px; height: 280px; }
body.role-tv .btn-circle,
body.view-tv .btn-circle { width: 56px; height: 56px; font-size: 26px; }
body.role-tv .tv-pair-info-col h1,
body.view-tv .tv-pair-info-col h1 { font-size: 30px; }
body.role-tv .tv-pair-info-col .lede,
body.view-tv .tv-pair-info-col .lede { font-size: 15px; }
body.role-tv .tv-pair-info-col .code-display,
body.view-tv .tv-pair-info-col .code-display { font-size: 40px; padding: 12px 18px; }
body.role-tv .tv-pair-actions .btn-sm,
body.view-tv .tv-pair-actions .btn-sm { padding: 10px 18px; font-size: 15px; }
.tv-room {
    display: grid;
    grid-template-columns: 1.05fr 1fr;
    gap: 56px;
    max-width: 1200px;
    width: 100%;
    align-items: center;
}
.tv-room .qr-frame { max-width: 240px; }
.tv-room h1 { font-size: 38px; line-height: 1.1; margin: 18px 0 10px; color: var(--ink-900); letter-spacing: -0.02em; }
.tv-room .lede { font-size: 16px; }
.tv-room .code-display { font-size: 48px; }

/* Corner cluster for room.php — QR pinned to the top end + a vertical
   action stack (regenerate, change role, jump to native nav) directly
   below it. The whole cluster stays inside the TV's safe area; on
   narrow viewports it collapses to a normal column above the main copy.

   We pin LTR with `right:` and explicitly flip on `[dir="rtl"]` rather
   than rely on `inset-inline-end` alone — some older Chromium TV WebViews
   leave the physical `right:` value in effect even with logical props,
   ending up with the QR stuck on the right in Arabic. The explicit
   override is the safest path. */
.tv-room-corner {
    position: absolute;
    top: 36px;
    right: 36px;
    width: 220px;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
}
[dir="rtl"] .tv-room-corner {
    right: auto;
    left: 36px;
}
.tv-room-corner .qr-frame {
    width: 100%;
    aspect-ratio: 1 / 1;
    padding: 10px;
}
.tv-room-actions {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.tv-room-actions .btn-sm {
    padding: 9px 14px;
    font-size: 13.5px;
    border-radius: 10px;
    text-align: center;
    justify-content: center;
}

.tv-room-main {
    max-width: 760px;
    width: 100%;
    /* leave room on the QR side so the title can never run under the
       corner cluster (QR + 3 buttons ≈ 200 + room) */
    padding-inline-end: 260px;
}
.tv-room-main h1 {
    font-size: 36px;
    line-height: 1.1;
    margin: 16px 0 10px;
    color: var(--ink-900);
    letter-spacing: -0.02em;
}
.tv-room-main .lede { font-size: 16px; }
.tv-room-main .code-display { font-size: 44px; }
@media (max-width: 900px) {
    .tv-room-corner { position: static; width: auto; margin-bottom: 18px;
                      align-items: center; }
    .tv-room-corner .qr-frame { max-width: 200px; }
    .tv-room-actions { flex-direction: row; flex-wrap: wrap; justify-content: center; }
    .tv-room-main   { padding-inline-end: 0; }
}

/* Lesson list — responsive grid.
   Single column on phones < 480 px so the cards read at full width.
   Two columns from 480 px, then auto-fill once the viewport can carry
   300 px+ cards. `align-items: start` keeps each card content-sized
   (no stretchy empty space when a neighbour is taller). */
.lesson-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 10px;
    margin: 6px auto 0;
    align-items: start;
    justify-items: center;
    width: 100%;
    max-width: 720px;       /* keeps the grid centered on wide phones / tablets */
    min-width: 0;
    box-sizing: border-box;
    padding: 0 8px;         /* gutter so cards aren't flush against the viewport */
}
.lesson-grid > .lesson-card {
    min-width: 0;
    width: 100%;
    max-width: 560px;       /* never wider than a thumb's reach; centers on bigger phones */
    box-sizing: border-box;
}
/* 2-column only kicks in at 600 px so portrait phones (up to ~414 px and
   landscape phones up to ~720 px) still get a single readable column.
   `auto-fit` (not `auto-fill`) so empty tracks collapse and the row stays
   visually centered when there are only a couple of cards. */
@media (min-width: 600px) {
    .lesson-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
}
@media (min-width: 900px) {
    .lesson-grid {
        grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
        max-width: 1080px;
    }
}

/* ─── Lesson card ───
   CSS-grid layout: badge sits inline with the title (top row), description
   spans the full width (middle), open-lesson tag hugs the bottom. No
   absolute positioning, no overlapping decorations. A slim coloured
   strip on the leading edge identifies the type; the badge repeats it
   as a tile so the page reads at a glance. */
.lesson-card {
    /* Solid white background + crisper border + a clear elevation shadow
       so each card is unmistakably its own object on top of the page.
       The previous glass+blur was blending into the page gradient. */
    background: #fff;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 1px 2px rgba(15,23,42,0.06), 0 4px 12px rgba(15,23,42,0.05);
    padding: 12px 14px;
    padding-inline-start: 18px; /* room for the colored leading strip */
    cursor: pointer;
    transition: border-color .15s ease, transform .12s ease, box-shadow .15s ease;
    text-align: start;
    text-decoration: none;
    color: inherit;
    display: grid;
    grid-template-columns: 36px 1fr;
    grid-template-rows: auto auto auto;
    column-gap: 12px;
    row-gap: 6px;
    align-items: center;
    position: relative;
    overflow: hidden;
    font: inherit;
}
@media (min-width: 480px) {
    .lesson-card { padding: 14px 16px; padding-inline-start: 20px;
                   grid-template-columns: 40px 1fr; }
}
.lesson-card::before {
    /* Thick coloured leading strip — primary type identifier. */
    content: '';
    position: absolute;
    inset-inline-start: 0; top: 0; bottom: 0;
    width: 8px;
    background: var(--brand);
    pointer-events: none;
}
/* A faint tinted wash inside the card per type — adds a second visual
   cue without overpowering the white background. */
.lesson-card::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    background: linear-gradient(180deg, rgba(255,255,255,0) 60%, var(--card-tint, transparent) 100%);
    opacity: 0.5;
}
.lesson-card.lesson-type-youtube::before  { background: #DC2626; }
.lesson-card.lesson-type-live::before     { background: #DC2626; }
.lesson-card.lesson-type-external::before { background: var(--gold); }
.lesson-card.lesson-type-quiz::before     { background: var(--accent); }
.lesson-card.lesson-type-html::before     { background: var(--brand); }

.lesson-card.lesson-type-youtube  { --card-tint: rgba(220, 38, 38, 0.12); }
.lesson-card.lesson-type-live     { --card-tint: rgba(220, 38, 38, 0.16); }
.lesson-card.lesson-type-external { --card-tint: rgba(245, 197, 24, 0.16); }
.lesson-card.lesson-type-quiz     { --card-tint: rgba(34, 197, 94, 0.14); }
.lesson-card.lesson-type-html     { --card-tint: rgba(14, 42, 94, 0.08); }

.lesson-card:hover {
    border-color: var(--brand);
    box-shadow: 0 2px 4px rgba(15,23,42,0.08), 0 12px 24px rgba(14,42,94,0.12);
    transform: translateY(-2px);
}

/* Badge — first column, top row. Square tile, type-coloured. Scales up
   on wider viewports so it stays proportional to the title. */
.lesson-card .lesson-badge {
    grid-column: 1;
    grid-row: 1;
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px;
    background: var(--brand);
    color: var(--gold);
    border-radius: 9px;
    font-size: 16px; line-height: 1;
    box-shadow: 0 4px 10px rgba(14, 42, 94, 0.18);
    align-self: center;
}
@media (min-width: 480px) {
    .lesson-card .lesson-badge { width: 40px; height: 40px; border-radius: 10px; font-size: 18px; }
}
.lesson-card.lesson-type-youtube  .lesson-badge { background: #DC2626; color: #fff; }
.lesson-card.lesson-type-live     .lesson-badge { background: #DC2626; color: #fff;
    animation: lessonLivePulse 1.4s ease-in-out infinite; }
.lesson-card.lesson-type-external .lesson-badge { background: var(--gold); color: var(--brand); }
.lesson-card.lesson-type-quiz     .lesson-badge { background: var(--accent); color: #fff; }

@keyframes lessonLivePulse {
    0%, 100% { box-shadow: 0 4px 10px rgba(220, 38, 38, 0.30), 0 0 0 0 rgba(220, 38, 38, 0.45); }
    50%      { box-shadow: 0 4px 10px rgba(220, 38, 38, 0.30), 0 0 0 8px rgba(220, 38, 38, 0.00); }
}

/* Title — second column, top row, vertically centered with the badge.
   `min-width: 0` lets long titles ellipsise inside the grid track instead
   of forcing the card wider on narrow phones. */
.lesson-card .lesson-title {
    grid-column: 2;
    grid-row: 1;
    margin: 0;
    min-width: 0;
    font-size: 15px; font-weight: 700; line-height: 1.3;
    color: var(--ink-900);
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
@media (min-width: 480px) { .lesson-card .lesson-title { font-size: 15.5px; } }

/* Description — full width, two-line clamp.
   `min-width: 0` lets the grid track shrink; `overflow-wrap: anywhere`
   handles long unbreakable strings (URLs, run-on tokens) instead of
   pushing the card wider than its parent. */
.lesson-card .lesson-desc {
    grid-column: 1 / -1;
    grid-row: 2;
    margin: 0;
    min-width: 0;
    max-width: 100%;
    overflow-wrap: anywhere;
    font-size: 12.5px; color: var(--ink-500); line-height: 1.5;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
@media (min-width: 480px) { .lesson-card .lesson-desc { font-size: 13px; } }

/* Open-lesson tag — full width, sits right under the description (no
   stretchy 1fr row anymore, so cards stay content-sized). */
.lesson-card .lesson-tag {
    grid-column: 1 / -1;
    grid-row: 3;
    margin: 4px 0 0;
    font-size: 11px; font-weight: 700;
    color: var(--brand);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
@media (min-width: 480px) { .lesson-card .lesson-tag { font-size: 11.5px; } }
.lesson-card[dir="rtl"] .lesson-tag { text-align: right; }

/* Strong focus state — D-pad / keyboard navigation has to be unmistakable.
   On phones the lift is gentler so the card doesn't poke past the grid
   gap into the neighbour. Bigger displays get the full lift. */
.lesson-card:focus,
.lesson-card:focus-visible {
    outline: none;
    border-color: var(--brand);
    transform: translateY(-2px);
    box-shadow:
        0 0 0 3px var(--gold),
        0 12px 28px rgba(14, 42, 94, 0.18);
}
@media (min-width: 720px) {
    /* More dramatic focus pop only once there's grid padding to spare. */
    .lesson-card:focus,
    .lesson-card:focus-visible {
        transform: translateY(-3px) scale(1.02);
        box-shadow:
            0 0 0 4px var(--gold),
            0 18px 38px rgba(14, 42, 94, 0.22);
    }
}
.lesson-card:focus .lesson-tag,
.lesson-card:focus-visible .lesson-tag { color: var(--brand-600); }

/* Toolbar */
.toolbar {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px;
    margin-bottom: 18px;
}
.toolbar .left { display: flex; align-items: center; gap: 10px; }

/* Compact connection strip for lessons.php — a single narrow row of two
   icon-only chips. Doesn't wrap, never exceeds 22 px height, and stays
   small enough not to compete with the page title below. */
.conn-strip {
    display: flex; align-items: center; gap: 6px; flex-wrap: nowrap;
    margin-bottom: 10px;
    min-height: 20px;
    font-size: 12px;
}
.conn-chip {
    display: inline-flex; align-items: center; justify-content: center;
    padding: 1px 7px;
    border-radius: 99px;
    background: var(--surface-2);
    color: var(--ink-500);
    border: 1px solid var(--border);
    font-size: 12px; line-height: 1.3;
    white-space: nowrap;
    min-width: 26px;
}
.conn-chip.live    { background: var(--success-50); border-color: var(--success); }
.conn-chip.waiting { background: var(--warn-50);    border-color: var(--warn); }
.conn-chip.error,
.conn-chip.off     { background: var(--danger-50);  border-color: var(--danger); }
body.role-tv .conn-strip,
body.view-tv .conn-strip { font-size: 14px; min-height: 24px; }
body.role-tv .conn-chip,
body.view-tv .conn-chip  { font-size: 14px; padding: 2px 9px; min-width: 30px; }

/* Lesson viewer */
.viewer-frame {
    width: 100%;
    height: calc(100vh - 110px);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--bg-elev);
    box-shadow: var(--shadow-1);
    overflow: hidden;
}
.viewer-frame iframe { width: 100%; height: 100%; border: 0; display: block; }

/* Toast */
.toast {
    position: fixed; bottom: 24px; left: 50%;
    transform: translateX(-50%);
    background: var(--ink-900);
    color: #fff;
    padding: 10px 16px;
    border-radius: var(--radius-pill);
    font-size: 13.5px;
    box-shadow: var(--shadow-2);
    opacity: 0;
    pointer-events: none;
    transition: opacity .2s ease, transform .2s ease;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(-4px); }

/* Hide chrome when running in webview-only fullscreen lesson */
body.embedded .shell-header,
body.embedded .shell-footer { display: none; }
body.embedded .shell-body { padding: 0; align-items: stretch; }
body.embedded .viewer-frame { height: 100vh; border-radius: 0; border: 0; }

/* ─────────────────────────────────────────────────────────────
   TV scaling — the room is viewed from across the room, so type
   and chrome are nudged larger and content reflows to use the
   wider landscape canvas without overflowing the viewport.
   ───────────────────────────────────────────────────────────── */
/* "view-tv" = render with the big-screen layout. Applied to:
     - body.role-tv (always)
     - body.role-mobile.paired (so the controller mirrors what the TV shows
       at the same scroll position — same content density per pixel). */
body.role-tv,
body.view-tv {
    font-size: 17px;
}
body.role-tv .shell-body, body.view-tv .shell-body { padding: 24px 36px; align-items: flex-start; }
body.role-tv .card,        body.view-tv .card        { max-width: 1100px; padding: 36px; }
body.role-tv .card.wide,   body.view-tv .card.wide   { max-width: 1280px; padding: 40px; }
body.role-tv h1.title,     body.view-tv h1.title     { font-size: 32px; }
body.role-tv h2.subtitle,  body.view-tv h2.subtitle  { font-size: 21px; }
body.role-tv p.lede,       body.view-tv p.lede       { font-size: 17px; }
body.role-tv .btn,         body.view-tv .btn         { padding: 13px 22px; font-size: 16px; }
body.role-tv .btn-lg,      body.view-tv .btn-lg      { padding: 16px 26px; font-size: 18px; }
body.role-tv .kicker,      body.view-tv .kicker      { font-size: 12.5px; padding: 5px 12px; }
body.role-tv .lesson-grid, body.view-tv .lesson-grid { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 18px; }
body.role-tv .lesson-card .lesson-title, body.view-tv .lesson-card .lesson-title { font-size: 17.5px; }
body.role-tv .lesson-card .lesson-desc,  body.view-tv .lesson-card .lesson-desc  { font-size: 14px; }
body.role-tv .lesson-card .lesson-badge, body.view-tv .lesson-card .lesson-badge { width: 46px; height: 46px; font-size: 22px; border-radius: 12px; }
/* On the real TV the cards breathe a little wider; the paired controller
   keeps the phone-tight grid layout — only typography matches. */
body.role-tv  .lesson-card { padding: 18px 20px; padding-inline-start: 24px; }
body.role-tv .pill,        body.view-tv .pill        { font-size: 13.5px; padding: 6px 14px; }
body.role-tv .meta,        body.view-tv .meta        { font-size: 13.5px; }
body.role-tv .steps li,    body.view-tv .steps li    { font-size: 16px; padding: 12px 0; }
body.role-tv .steps li .num, body.view-tv .steps li .num { width: 30px; height: 30px; font-size: 15px; }

/* D-pad focus visibility — the default Chromium focus ring is a 1 px blue
   line, invisible from across a room. On TV (and on paired controller, so
   both screens look identical) we widen it to a 4 px brand ring with
   offset, and gently scale focused cards/buttons for emphasis. */
body.role-tv :focus,        body.view-tv :focus,
body.role-tv :focus-visible, body.view-tv :focus-visible {
    outline: 4px solid var(--brand);
    outline-offset: 4px;
}
body.role-tv .lesson-card:focus,   body.view-tv .lesson-card:focus,
body.role-tv button:focus,         body.view-tv button:focus,
body.role-tv .btn:focus,           body.view-tv .btn:focus,
body.role-tv a.btn:focus,          body.view-tv a.btn:focus {
    border-color: var(--brand);
    transform: scale(1.03);
    transition: transform .08s ease, border-color .08s ease;
}
