/*
    KPI.tv full-screen "channel" kiosk theme. Reuses the .db-monitor /
    .epg-* class names/markup from the shared render helpers
    (dashboardWidgets.php) - this stylesheet just gives them kiosk-sized
    type/spacing for a screen viewed from across a room.

    The channel switcher itself (.channel-picker) is NOT shared with /dashboard's
    rail - it's its own centered "TV guide" style overlay, built and styled only
    here, since jumping between channels while watching a TV is a different
    interaction than picking a channel to manage.

    Deliberately NOT included here: modal CSS, .db-head quick actions, activity
    feed. This is a passive wall-mounted display - no "log an update"/"add a
    channel" affordances belong on it (those live on /dashboard).

    Design tokens (colours/fonts) live in shared/css/app.css (linked before
    this file). --radius was 16px here specifically - an undocumented,
    unexplained drift from every other screen's 14px (contrast the deliberate,
    commented kiosk-scale overrides below for body/.db-header/.brand/.btn) -
    removed so it converges on the shared 14px instead. --rail-width is kept
    local: a genuine per-screen value, like /dashboard's different one, for
    the same reason. This file still redeclares .db-header/.brand/.btn/body
    below at kiosk scale, on purpose - those win on cascade order over
    shared's smaller values, same mechanism, not a duplicate to remove.
*/

:root {
    --rail-width: 300px;
}

* { box-sizing: border-box; }

/* The outer document (html) has to be pinned to the viewport and dark too -
   otherwise IT becomes the scrolling element once content is taller than
   100vh (browsers default html to overflow:visible, growing past body),
   which shows html's own default white background below body and its own
   un-hidden native scrollbar, regardless of what's set on body below. */
html {
    height: 100%;
    overflow: hidden;
    background: var(--ink);
}

/* Kiosk-specific overrides below (body/.btn/.db-header/.brand) -
   deliberately larger scale "for a screen viewed from across a room" than
   shared/css/app.css's defaults, kept local on purpose and winning on
   cascade order (this file loads after shared). The reduced-motion query
   and a{color:inherit}/h1-h3 base that used to sit here were identical to
   shared's, so removed rather than kept as redundant copies. */

body {
    margin: 0;
    background: var(--ink);
    color: var(--paper);
    font-family: var(--font-body);
    font-size: 18px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    height: 100vh;
    /* No visible scrollbar (this is a TV/kiosk display, not a document to
       show scroll chrome on) - but still scrollable, not clipped, so a
       channel with more panels than fit the viewport (especially on a
       narrow mobile screen) can still be reached by touch/wheel/keyboard
       instead of just cutting content off. */
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    -ms-overflow-style: none;
}
body::-webkit-scrollbar {
    display: none;
}

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 12px 22px;
    border-radius: 999px;
    font-family: var(--font-body);
    font-weight: 600;
    font-size: 15px;
    text-decoration: none;
    border: 1px solid var(--line-2);
    cursor: pointer;
    background: none;
    color: var(--paper);
}
.btn:hover { border-color: var(--paper); }

/* ---------- App header ---------- */

.db-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 18px 28px;
    border-bottom: 1px solid var(--line);
}

.brand {
    display: flex;
    align-items: center;
    gap: 10px;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 21px;
    text-decoration: none;
    color: var(--paper);
    flex: none;
}
.brand .dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--on-air);
    box-shadow: 0 0 0 4px var(--on-air-dim);
}
.brand .tv { color: var(--muted); font-weight: 600; }

.db-channel-toggle {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: var(--panel);
    border: 1px solid var(--line-2);
    border-radius: 999px;
    padding: 9px 16px;
    color: var(--paper);
    font-family: var(--font-mono);
    font-size: 13.5px;
    cursor: pointer;
    min-width: 0;
    max-width: 40vw;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
.db-channel-toggle .db-rail-num { color: var(--on-air); }
.db-channel-toggle-chevron {
    flex: none;
    width: 13px;
    height: 13px;
    color: var(--muted);
}

.channel-header-right {
    display: flex;
    align-items: center;
    gap: 14px;
    flex: none;
}

.channel-live {
    display: flex;
    align-items: center;
    gap: 7px;
    font-family: var(--font-mono);
    font-size: 12.5px;
    letter-spacing: 0.1em;
    color: var(--muted-2);
    flex: none;
}
.channel-live .pulse {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--signal);
    --pulse-rgb: 52, 211, 153;
    animation: channel-pulse 2.2s ease-in-out infinite;
    transition: background 0.2s ease;
}
/* Briefly orange while a poll request is in flight, red if it fails (stays
   red until the next poll succeeds) - otherwise green/idle. */
.channel-live .pulse.is-updating { background: var(--tally); --pulse-rgb: 255, 176, 32; }
.channel-live .pulse.is-error    { background: var(--on-air); --pulse-rgb: 255, 65, 54; }
@keyframes channel-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(var(--pulse-rgb), 0.35); }
    50%      { box-shadow: 0 0 0 6px transparent; }
}

.channel-fullscreen-btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    background: var(--panel);
    border: 1px solid var(--line-2);
    border-radius: 999px;
    padding: 8px 14px;
    color: var(--paper);
    font-family: var(--font-mono);
    font-size: 12.5px;
    cursor: pointer;
    flex: none;
}
.channel-fullscreen-btn:hover { border-color: var(--on-air); color: var(--on-air); }
.channel-fullscreen-btn svg { width: 14px; height: 14px; flex: none; }

/* Owner-only "jump into editing this channel" shortcut - icon-only version
   of the fullscreen button's pill, not shown at all for a public/kiosk
   viewer (renderConfigLink() is only called for cls_eViewableType::Owned()). */
.channel-config-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    background: var(--panel);
    border: 1px solid var(--line-2);
    border-radius: 999px;
    color: var(--muted);
    flex: none;
}
.channel-config-link:hover { border-color: var(--signal); color: var(--signal); }
.channel-config-link svg { width: 14px; height: 14px; flex: none; }

.db-shell {
    min-height: calc(100vh - 73px);
}

/* ---------- Embed mode: shown inside /programme/:id's rotation iframe ----------
   The picker/fullscreen/live-pulse chrome doesn't make sense on a channel
   that's one automatic rotation slot, not being watched on its own - tv.php
   already skips rendering the picker markup itself when embed=1; this just
   hides the rest of the header and reclaims its vertical space. */

body[data-embed="1"] .db-header { display: none; }
body[data-embed="1"] .db-shell { min-height: 100vh; }

/* ---------- Channel picker: centered "TV guide" overlay, not a side rail ----------
   Triggered by the header's channel-toggle pill. Jumps straight to /channel/:id -
   this is about surfing channels while watching, not managing them. */

.channel-picker-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 99;
    background: rgba(4, 6, 10, 0.75);
}
.channel-picker-backdrop.is-open { display: block; }

.channel-picker {
    position: fixed;
    top: 50%;
    left: 50%;
    z-index: 100;
    width: min(600px, 92vw);
    max-height: 76vh;
    display: flex;
    flex-direction: column;
    background: linear-gradient(180deg, var(--panel-2), var(--panel));
    border: 1px solid var(--line-2);
    border-radius: 20px;
    box-shadow: 0 50px 100px -30px rgba(0, 0, 0, 0.75);
    opacity: 0;
    pointer-events: none;
    transform: translate(-50%, -50%) scale(0.94);
    transition: opacity 0.2s ease, transform 0.2s ease;
}
.channel-picker.is-open {
    opacity: 1;
    pointer-events: auto;
    transform: translate(-50%, -50%) scale(1);
}

.channel-picker-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 20px 24px;
    border-bottom: 1px solid var(--line);
    flex: none;
}
.channel-picker-head span {
    font-family: var(--font-mono);
    font-size: 12px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted);
}
.channel-picker-close {
    background: none;
    border: none;
    color: var(--muted);
    font-size: 24px;
    line-height: 1;
    cursor: pointer;
    padding: 4px 8px;
}
.channel-picker-close:hover { color: var(--paper); }

.channel-picker-list {
    overflow-y: auto;
    padding: 10px 14px 18px;
}

.channel-picker-tile {
    display: flex;
    align-items: center;
    gap: 18px;
    padding: 16px 14px;
    border-radius: 12px;
    text-decoration: none;
    color: var(--paper);
    border-left: 4px solid transparent;
}
.channel-picker-tile:hover { background: rgba(148, 163, 184, 0.08); }
.channel-picker-tile.is-current {
    background: var(--on-air-dim);
    border-left-color: var(--on-air);
}
.channel-picker-num {
    font-family: var(--font-mono);
    font-size: 15px;
    color: var(--muted-2);
    letter-spacing: 0.04em;
    flex: none;
    min-width: 64px;
}
.channel-picker-tile.is-current .channel-picker-num { color: var(--on-air); }
.channel-picker-label {
    font-size: 19px;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---------- Main content: the KPI monitor grid ---------- */

.db-main {
    padding: 36px 40px 50px;
}

.db-panelgrid {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

/* Each row sized to its OWN panel count (--row-count, set inline per row by
   renderPanelGrid() in dashboardWidgets.php), matching the row layout defined
   on /page/:id instead of flattening every panel into one continuous grid. */
.db-panelrow {
    display: flex;
    flex-wrap: wrap;
    gap: 24px;
}
.db-panelrow > * {
    flex: 1 1 calc((100% / var(--row-count, 1)) - 24px);
    min-width: 280px;
}

.db-monitor {
    position: relative;
    background: linear-gradient(180deg, var(--panel-2), var(--panel));
    border: 1px solid var(--line-2);
    border-radius: var(--radius);
    padding: 26px 28px;
    cursor: pointer;
    transition: transform 0.15s ease, border-color 0.15s ease;
}
.db-monitor:hover {
    transform: translateY(-2px);
    border-color: var(--line-2);
}

.db-monitor-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 18px;
}
.db-monitor-label {
    font-size: 17px;
    font-weight: 600;
    color: var(--paper);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.db-freshness-group {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.db-source-icon {
    flex: none;
    display: inline-flex;
    color: var(--muted-2);
}
.db-source-icon svg { width: 13px; height: 13px; }

.db-freshness {
    flex: none;
    font-family: var(--font-mono);
    font-size: 12px;
    letter-spacing: 0.05em;
    padding: 4px 10px;
    border-radius: 999px;
    text-transform: uppercase;
}
.db-freshness.is-fresh  { color: var(--signal); background: rgba(52, 211, 153, 0.12); }
.db-freshness.is-ageing { color: var(--tally);  background: var(--tally-dim); }
.db-freshness.is-stale  { color: var(--on-air); background: var(--on-air-dim); }
.db-freshness.is-none   { color: var(--muted-2); background: rgba(148, 163, 184, 0.1); }

.db-monitor-value-row {
    display: flex;
    align-items: baseline;
    gap: 14px;
    flex-wrap: wrap;
}
.db-monitor-value {
    font-family: var(--font-mono);
    font-weight: 700;
    font-size: 52px;
    color: var(--paper);
    font-variant-numeric: tabular-nums;
}
.db-monitor-suffix {
    font-family: var(--font-mono);
    font-size: 22px;
    color: var(--muted);
}
.db-monitor-trend {
    font-family: var(--font-mono);
    font-size: 16px;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.db-monitor-trend.is-good { color: var(--signal); }
.db-monitor-trend.is-bad  { color: var(--on-air); }
.db-monitor-trend.is-flat { color: var(--muted-2); }

.db-monitor-spark {
    margin-top: 18px;
    width: 100%;
    height: 52px;
    display: block;
}
.db-monitor-spark path {
    fill: none;
    stroke: var(--signal);
    stroke-width: 2.5;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* Chart_Type 3 (Sparkline (bar)) - real bars instead of the line/area path */
.db-monitor-spark-bars rect {
    fill: var(--signal);
}

/* Chart_Type 6/7 (Progress Ring / Progress Bar) - replaces the value-row +
   sparkline entirely on a card, see renderMonitorWidget(). */
.db-monitor-widget {
    display: flex;
    width: 100%;
    justify-content: center;
    align-items: center;
    text-align: center;
    padding: 14px 0;
    --indicator-color: var(--signal);
    --track-color: var(--line-2);
}
/* renderProgressBar()/renderProgressRing() (dashboardWidgets.ext.php) wrap
   their output in .kd-progress-bar-wrap/.kd-progress-ring-wrap - without
   these, that div defaults to block/width:auto, and as a flex item of
   .db-monitor-widget above it shrinks to its own content width (~17px)
   instead of spanning the card, which is what made the bar/ring render as
   a barely-visible sliver. */
.kd-progress-bar-wrap,
.kd-progress-ring-wrap {
    display: flex;
    width: 100%;
    justify-content: center;
    align-items: center;
}
.db-monitor-widget wa-progress-bar {
    width: 100%;
}

.db-monitor-empty {
    color: var(--muted-2);
    font-size: 15px;
    padding: 12px 0 6px;
}

/* "Puff" pulse on value change - channel.js toggles this on a card's value
   when a poll returns a changed figure (see M-Ploy's wxText widget for the
   idea this is based on). */
@keyframes db-puff {
    0%   { transform: scale(1);     filter: brightness(1); }
    30%  { transform: scale(1.03);  filter: brightness(1.35); }
    100% { transform: scale(1);     filter: brightness(1); }
}
.is-updated {
    animation: db-puff 600ms ease-out;
}

.db-monitor-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 10px;
    padding-top: 8px;
    border-top: 1px dashed rgba(148, 163, 184, 0.18);
}
.db-monitor-updated {
    font-family: var(--font-mono);
    font-size: 11.5px;
    color: var(--muted-2);
    white-space: nowrap;
}

/* Chart_Type 8 ("Call to Action") - internal-only clickable link tile, see
   renderCtaCard() (dashboardWidgets.ext.php). Deliberately not .db-monitor -
   a plain outbound link, not a data card, so it's excluded from channel.js's
   .db-monitor[data-kpiid] click-to-detail listener and poll-refresh lookup. */
.db-cta {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 264px;
    box-sizing: border-box;
    background: linear-gradient(160deg, var(--on-air), #b8271d);
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: var(--radius);
    box-shadow: 0 24px 48px -28px rgba(255, 65, 54, 0.6);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.db-cta:hover {
    transform: translateY(-2px);
    box-shadow: 0 28px 56px -24px rgba(255, 65, 54, 0.7);
}
.db-cta-link {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 16px;
    padding: 28px;
    text-align: center;
    text-decoration: none;
    color: #fff;
}
.db-cta-headline {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 21px;
    line-height: 1.25;
}
.db-cta-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 11px 26px;
    border-radius: 999px;
    background: #fff;
    color: var(--on-air);
    font-family: var(--font-body);
    font-weight: 700;
    font-size: 15px;
}
/* Owner-only gear/pencil/trash icons - white-on-red instead of
   .panel-foot-actions' default var(--muted), which is unreadable here. */
.db-cta-foot {
    flex: none;
    display: flex;
    justify-content: center;
    padding: 10px 0 14px;
    border-top: 1px solid rgba(255, 255, 255, 0.18);
}
.db-cta-foot .panel-foot-actions a { color: rgba(255, 255, 255, 0.75); }
.db-cta-foot .panel-configure-link:hover,
.db-cta-foot .panel-remove-btn:hover { color: #fff; background: rgba(255, 255, 255, 0.18); }

/* Owner-only "Configure this widget" gear (renderChannelPanelGrid()'s
   $isOwner branch) - same markup/class names as page.php's editor foot
   actions, just this one icon instead of the full pencil/gear/trash set. */
.panel-foot-actions {
    display: flex;
    align-items: center;
    gap: 4px;
    flex: none;
}
.panel-foot-actions a {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 999px;
    color: var(--muted);
    text-decoration: none;
    transition: background 0.15s ease, color 0.15s ease;
}
.panel-foot-actions svg { width: 13px; height: 13px; }
.panel-configure-link:hover { color: var(--paper); background: rgba(148, 163, 184, 0.14); }

/* ---------- Blocked state (no such channel / private / needs login) ---------- */

.channel-blocked {
    max-width: 520px;
    margin: 90px auto;
    text-align: center;
    padding: 0 20px;
}
.channel-blocked h1 { font-size: 28px; margin-bottom: 14px; }
.channel-blocked p { color: var(--muted); margin: 0; font-size: 17px; }

/* ---------- Responsive ---------- */

@media (max-width: 860px) {
    .channel-live span:last-child { display: none; }
    .channel-fullscreen-btn span:last-child { display: none; }

    .channel-picker { width: 94vw; max-height: 82vh; }
    .channel-picker-label { font-size: 17px; }

    .db-main { padding: 26px 20px 40px; }
    .db-panelrow > * { flex-basis: 100%; }
    .db-monitor-value { font-size: 42px; }
    .db-monitor-suffix { font-size: 18px; }
}

@media (max-width: 480px) {
    .db-channel-toggle { max-width: 34vw; }
}
