/* Customizable widget dashboard (E4). Uses MudBlazor theme variables so it follows light/dark. */

.dashboard-tabbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}

.dashboard-tabs {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}

.dashboard-tab {
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--mud-palette-lines-default);
    background: var(--mud-palette-surface);
    color: var(--mud-palette-text-secondary);
    border-radius: 999px;
    padding: 6px 16px;
    font-size: 0.875rem;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.15s ease;
    white-space: nowrap;
}

.dashboard-tab:hover {
    border-color: var(--mud-palette-primary);
    color: var(--mud-palette-text-primary);
}

.dashboard-tab.active {
    background: var(--mud-palette-primary);
    border-color: var(--mud-palette-primary);
    color: var(--mud-palette-primary-text);
}

.dashboard-actions {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Gridstack item chrome */
.grid-stack-item-content.widget-card {
    display: flex;
    flex-direction: column;
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
    inset: 4px; /* gridstack margin gutter */
    transition: box-shadow 0.18s ease, border-color 0.18s ease;
}

.grid-stack-item-content.widget-card:hover {
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.14);
}

/* Header identity icon */
.widget-header-icon {
    display: inline-flex;
    color: var(--mud-palette-primary);
}
.widget-header-icon.widget-drag-handle { cursor: move; color: var(--mud-palette-text-secondary); }

/* Thin scrollbars inside the widget bodies that are allowed to scroll at all. */
.widget-body--list::-webkit-scrollbar, .widget-eventlist::-webkit-scrollbar { width: 6px; height: 6px; }
.widget-body--list::-webkit-scrollbar-thumb, .widget-eventlist::-webkit-scrollbar-thumb {
    background: var(--mud-palette-lines-default); border-radius: 3px;
}

.dashboard-editing .grid-stack-item-content.widget-card {
    border-style: dashed;
    border-color: var(--mud-palette-primary);
}

.widget-header {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 10px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
    min-height: 40px;
}

.widget-title {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--mud-palette-text-primary);
    text-transform: uppercase;
    letter-spacing: 0.02em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.widget-header-spacer { flex: 1; }

.widget-drag-handle {
    cursor: move;
    display: inline-flex;
    color: var(--mud-palette-text-secondary);
}

/* bug-001b / bug-002 — a widget does not scroll. `overflow: auto` here put a scrollbar on every tile
   whose content brushed its edge, and two of the three scrollbars in the QA captures were not even
   content: WidgetPulse and the door-grant sweep are `position:absolute; left:0; right:0` bars that
   animate to `translateX(55%)`, i.e. deliberately past the right edge, and an `auto` box turns that
   into a horizontal scrollbar for the 1.15s the animation runs — and then leaves the bar there.
   Clipping is the correct answer for both. List-shaped widgets opt back in via .widget-body--list. */
.widget-body {
    flex: 1;
    min-height: 0;
    padding: 12px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    justify-content: center;
    /* `safe` so a tile that somehow still overflows spills off the BOTTOM only — centred overflow puts
       the first line above the box where nothing can reach it. Ignored by engines that lack it. */
    justify-content: safe center;
    position: relative; /* anchors live-feedback flash bars (WidgetPulse) to the body top */
}

/* The list-shaped widgets (feeds, queues, audit tails) — scrolling IS the right behaviour there.
   Vertical only: horizontal scroll is never right in a tile this size, and the pulse bars would
   reintroduce it. */
.widget-body--list {
    overflow-y: auto;
    overflow-x: hidden;
    /* A list centred in its box overflows in BOTH directions — that is why the QA capture shows the
       live feed clipped at the TOP as well as the bottom, with the first row unreachable. Lists start
       at the top. */
    justify-content: flex-start;
    /* A part-row at the bottom edge is how a scroll list says "there is more"; fading it reads as
       continuation instead of a sliced row. */
    mask-image: linear-gradient(to bottom, #000 calc(100% - 14px), transparent 100%);
    -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 14px), transparent 100%);
}

/* Rows in a scrolling list keep their height; the default flex-shrink squeezes them to fit and is how
   a feed ends up with half-height rows. */
.widget-body--list > * { flex: 0 0 auto; }

/* Stat tiles */
.widget-stat-row {
    display: flex;
    /* Flex items default to min-width:auto, so a three-column stat row could not shrink below its
       widest label and pushed the tile wider than itself. Shrink first (min-width:0 below), wrap
       second — never overflow. */
    flex-wrap: wrap;
    gap: 4px 8px;
    justify-content: space-around;
    align-items: flex-start;
    width: 100%;
    min-width: 0;
}

.widget-stat { text-align: center; flex: 1 1 62px; min-width: 0; }

/* bug-001c/002b — a KPI that drills through is an <a>, so it has to stop looking like body text and start
   looking like something you can click. The figure keeps its own colour (severity is carried in it), so
   the affordance is the label underline and a small lift rather than a link colour. */
.widget-stat--link {
    display: block;
    text-decoration: none;
    color: inherit;
    border-radius: 6px;
    padding: 2px 4px;
    transition: background-color 120ms ease, transform 120ms ease;
}

.widget-stat--link:hover,
.widget-stat--link:focus-visible {
    background-color: var(--mud-palette-action-default-hover);
    transform: translateY(-1px);
}

.widget-stat--link:hover .widget-stat-label,
.widget-stat--link:focus-visible .widget-stat-label {
    text-decoration: underline;
}

.widget-stat--link:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 1px;
}

.widget-stat-value {
    font-size: 1.9rem;
    font-weight: 700;
    line-height: 1.1;
}

.widget-stat-label {
    font-size: 0.7rem;
    color: var(--mud-palette-text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    line-height: 1.25;
    overflow-wrap: anywhere;
}

/* The TILE is the sizing context, not the viewport: three stat columns in a 3-wide tile and the same
   three in a 5-wide tile are different problems, and a viewport media query cannot tell them apart.
   Numbers step down with the tile so the content keeps fitting instead of demanding a scrollbar. */
.grid-stack-item-content.widget-card,
.popout-widget-card {
    container-type: inline-size;
    container-name: vhwidget;
}

@container vhwidget (max-width: 300px) {
    .widget-stat-value { font-size: 1.5rem; }
    .widget-clock-time { font-size: 2rem; }
    .widget-bignum { font-size: 1.9rem; }
}

@container vhwidget (max-width: 210px) {
    .widget-stat-value { font-size: 1.25rem; }
    .widget-stat-label { font-size: 0.62rem; letter-spacing: 0; }
    .widget-clock-time { font-size: 1.6rem; }
    .widget-bignum { font-size: 1.5rem; }
}

/* Gauge (site health) */
.widget-gauge {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 8px;
}

.widget-gauge-label {
    position: absolute;
    display: flex;
    flex-direction: column;
    align-items: center;
    font-size: 0.7rem;
    color: var(--mud-palette-text-secondary);
}

.widget-gauge-pct {
    font-size: 1.2rem;
    font-weight: 700;
    color: var(--mud-palette-text-primary);
}

/* Clock */
.widget-clock { text-align: center; }
.widget-clock-time { font-size: 2.6rem; font-weight: 700; line-height: 1; color: var(--mud-palette-text-primary); }
.widget-clock-ampm { font-size: 1rem; font-weight: 500; margin-left: 4px; color: var(--mud-palette-text-secondary); }
.widget-clock-date { font-size: 0.85rem; color: var(--mud-palette-text-secondary); margin-top: 4px; }

.widget-welcome { width: 100%; }
.widget-greeting { width: 100%; }
.widget-sparkline { width: 100%; }

/* Multi-site rollup */
.widget-rollup { display: flex; flex-direction: column; gap: 6px; width: 100%; }
.widget-rollup-row { display: flex; align-items: center; gap: 8px; font-size: 0.8rem; }
.widget-rollup-name { flex: 0 0 35%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.widget-rollup-bar { flex: 1; }
.widget-rollup-val { flex: 0 0 auto; color: var(--mud-palette-text-secondary); font-variant-numeric: tabular-nums; }

/* Door control grid */
.widget-doorgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 8px; width: 100%; }
.widget-door { border: 1px solid var(--mud-palette-lines-default); border-radius: 8px; padding: 8px; display: flex; flex-direction: column; gap: 6px; position: relative; overflow: hidden; }
/* Green wash over a door tile when an access grant happens at that door (keyed per grant → replays). */
.door-tile-flash {
    position: absolute; inset: 0; border-radius: 8px; pointer-events: none; z-index: 1;
    background: var(--mud-palette-success);
    animation: door-tile-grant 1.2s ease-out forwards;
}
@keyframes door-tile-grant {
    0%   { opacity: 0.40; }
    100% { opacity: 0; }
}
.widget-door-head { display: flex; align-items: center; gap: 6px; }
.door-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.widget-door-name { font-size: 0.8rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.widget-door-actions { display: flex; gap: 4px; }
.widget-door-actions .mud-button-root { min-width: 0; flex: 1; padding: 2px 6px; }
.widget-notes { width: 100%; white-space: pre-wrap; word-break: break-word; font-size: 0.9rem; color: var(--mud-palette-text-primary); }
.widget-unknown { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; height: 100%; }

/* Big number (panels online) */
.widget-bignum { text-align: center; font-size: 2.4rem; font-weight: 700; line-height: 1; color: var(--mud-palette-text-primary); }
.widget-bignum-of { font-size: 1.1rem; font-weight: 500; color: var(--mud-palette-text-secondary); }

/* Donut chart widget */
.widget-chart { display: flex; align-items: center; justify-content: center; gap: 12px; }
.widget-chart-legend { display: flex; flex-direction: column; gap: 6px; font-size: 0.8rem; color: var(--mud-palette-text-secondary); }
.widget-chart-legend .legend-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 6px; }

/* Event list (door monitor) */
.widget-eventlist { display: flex; flex-direction: column; gap: 2px; width: 100%; }
.widget-event { display: flex; gap: 8px; align-items: baseline; padding: 3px 4px; border-radius: 4px; font-size: 0.8rem; }
.widget-event:hover { background: var(--mud-palette-action-default-hover); }
.widget-event.is-alarm { color: var(--mud-palette-error); font-weight: 600; }
.widget-event-time { color: var(--mud-palette-text-secondary); font-variant-numeric: tabular-nums; flex-shrink: 0; }
.widget-event-desc { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Live feed / list extras */
.live-feed .widget-event { animation: widget-fadein 0.25s ease; }
@keyframes widget-fadein { from { opacity: 0; transform: translateY(-3px); } to { opacity: 1; transform: none; } }

.sev-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }

.widget-event .mud-icon-root { flex-shrink: 0; }

.widget-allclear {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; height: 100%;
}

/* Camera placeholder */
.widget-camera-placeholder {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; height: 100%;
    border: 1px dashed var(--mud-palette-lines-default); border-radius: 8px; min-height: 120px;
}

.dashboard-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 48px 0;
    text-align: center;
}

/* Pop-out windows */
.popout-shell {
    min-height: 100vh;
    background: var(--mud-palette-background);
    color: var(--mud-palette-text-primary);
    display: flex;
    flex-direction: column;
}

.popout-header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
    background: var(--mud-palette-surface);
}

.popout-title { font-weight: 600; font-size: 0.95rem; }
.popout-spacer { flex: 1; }

.popout-body { flex: 1; padding: 12px; overflow: auto; }

.popout-single-widget {
    display: flex;
    align-items: stretch;
    justify-content: stretch;
}

.popout-widget-card {
    display: flex;
    flex-direction: column;
    width: 100%;
    min-height: 360px;
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 12px;
    overflow: hidden;
}

/* ============================================================
   Polish pass — cleaner cards, calmer header chrome
   ============================================================ */

.grid-stack-item-content.widget-card {
    border-radius: 14px;
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.06), 0 1px 3px rgba(16, 24, 40, 0.04);
    transition: box-shadow 0.18s ease, border-color 0.18s ease, transform 0.18s ease;
}
.grid-stack-item-content.widget-card:hover {
    box-shadow: 0 8px 24px rgba(16, 24, 40, 0.12);
    transform: translateY(-1px);
}

/* Header: a touch of tint, identity icon in a soft tinted square */
.widget-header {
    padding: 8px 10px 8px 8px;
    background: linear-gradient(180deg, rgba(127, 127, 127, 0.05), transparent);
}
.widget-header-icon {
    width: 26px;
    height: 26px;
    border-radius: 7px;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--mud-palette-primary) 14%, transparent);
}
.widget-header-icon.widget-drag-handle { background: transparent; }
.widget-title {
    text-transform: none;
    letter-spacing: 0;
    font-size: 0.85rem;
    font-weight: 600;
}

/* Action buttons sit back until you hover the card (less visual noise) */
.widget-header .mud-icon-button { opacity: 0.45; transition: opacity 0.15s ease; }
.grid-stack-item-content.widget-card:hover .widget-header .mud-icon-button { opacity: 0.9; }
.widget-header .mud-icon-button:hover { opacity: 1; }

/* Stat tiles: primary-toned numbers read as "the answer" */
.widget-stat-value { letter-spacing: -0.01em; }

/* Event rows a touch roomier */
.widget-event { padding: 4px 6px; border-radius: 6px; }

/* ============================================================
   Reusable live-feedback flash bar (WidgetPulse) — the generalized
   green grant sweep, in success / error / warning / info.
   ============================================================ */

.widget-pulse {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 4px;
    border-radius: 2px;
    pointer-events: none;
    z-index: 3;
    animation: widget-pulse-sweep 1.15s ease-out forwards;
}
.widget-pulse-success { background: linear-gradient(90deg, transparent, var(--mud-palette-success), transparent); box-shadow: 0 0 10px color-mix(in srgb, var(--mud-palette-success) 70%, transparent); }
.widget-pulse-error   { background: linear-gradient(90deg, transparent, var(--mud-palette-error), transparent);   box-shadow: 0 0 10px color-mix(in srgb, var(--mud-palette-error) 70%, transparent); }
.widget-pulse-warning { background: linear-gradient(90deg, transparent, var(--mud-palette-warning), transparent); box-shadow: 0 0 10px color-mix(in srgb, var(--mud-palette-warning) 70%, transparent); }
.widget-pulse-info    { background: linear-gradient(90deg, transparent, var(--mud-palette-info), transparent);    box-shadow: 0 0 10px color-mix(in srgb, var(--mud-palette-info) 70%, transparent); }
@keyframes widget-pulse-sweep {
    0%   { opacity: 0; transform: translateX(-55%) scaleX(0.35); }
    20%  { opacity: 1; }
    100% { opacity: 0; transform: translateX(55%) scaleX(1.1); }
}

/* Count-up emphasis: a stat number briefly scales + tints when it changes live */
.widget-stat-value.is-bumped { animation: stat-bump 0.5s ease-out; }
@keyframes stat-bump {
    0%   { transform: scale(1); }
    35%  { transform: scale(1.18); color: var(--mud-palette-primary); }
    100% { transform: scale(1); }
}

/* ============================================================
   Door monitor — live access-granted visual feedback
   ============================================================ */

.door-monitor { position: relative; width: 100%; }

/* The green bar that sweeps across on a live access-granted event */
.door-flash {
    position: absolute;
    top: -4px;
    left: 0;
    right: 0;
    height: 4px;
    border-radius: 2px;
    background: linear-gradient(90deg, transparent 0%, var(--mud-palette-success) 50%, transparent 100%);
    box-shadow: 0 0 10px color-mix(in srgb, var(--mud-palette-success) 70%, transparent);
    pointer-events: none;
    z-index: 3;
    animation: door-grant-sweep 1.15s ease-out forwards;
}
@keyframes door-grant-sweep {
    0%   { opacity: 0; transform: translateX(-55%) scaleX(0.35); }
    20%  { opacity: 1; }
    100% { opacity: 0; transform: translateX(55%) scaleX(1.1); }
}

/* Granted rows: green left accent + a one-shot background flash as they arrive */
.widget-event.is-grant { box-shadow: inset 3px 0 0 var(--mud-palette-success); }
.widget-event.is-grant .widget-event-desc { color: var(--mud-palette-success-darken, var(--mud-palette-text-primary)); }
.live-feed .widget-event.is-grant { animation: grant-row-flash 1.15s ease-out; }
@keyframes grant-row-flash {
    0%   { background: rgba(76, 175, 80, 0.30); }
    100% { background: transparent; }
}

/* ============================================================
   Widget detail modal (drill-down opens here, not a new screen)
   ============================================================ */

.widget-detail-body {
    min-height: 340px;
    max-height: 68vh;
    overflow: auto;
    display: flex;
    flex-direction: column;
    padding: 4px 2px;
}
.widget-detail-body > * { flex: 1 1 auto; width: 100%; }

/* ============================================================
   Widget honesty states (Wave 2 / T2.1): error / stale / as-of
   ============================================================ */
.widget-state-center { display: flex; align-items: center; justify-content: center; min-height: 64px; }
.widget-error {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    padding: 10px 12px; min-height: 56px;
    color: var(--v-color-status-fault, var(--mud-palette-error));
    background: var(--v-color-status-fault-subtle, transparent);
    border-radius: 8px;
}
.widget-error .mud-typography { color: var(--mud-palette-text-primary); }
.widget-stale {
    display: inline-flex; align-items: center; gap: 6px; margin-bottom: 6px;
    color: var(--v-color-status-attention, var(--mud-palette-warning));
}
.widget-asof { margin-top: 6px; opacity: 0.7; text-align: right; }
