/* ======================================================================
   Agent Floor — single-SVG architectural floor plan.

   NOTE: global stylesheet (linked from _Host.cshtml). Same reason as
   fleet-ops.css — the .razor.css scoped pipeline was unreliably failing
   to apply on this page. The inline-SVG floor still renders without CSS,
   but the header chrome / tooltip / cards view depend on these rules,
   so they have to load globally. Class names are page-specific
   (.floor-*, .desk, .cubicle, .room, .speech-*, .agent-tooltip, .ws-*)
   so cross-page bleed is minimal.

   The page renders one giant SVG. CSS handles:
     - Theme tokens (light / dark "office")
     - Status-driven screen color + bloom
     - View transforms: plan (default), iso (3D tilt), cards (HTML grid)
     - Hover tooltip styling
     - Header chrome (controls, comms ticker, HUD)
   ====================================================================== */

.floor-shell {
    /* Floor base — wood plank palette (light "morning office") */
    --floor-base-a: #d8c5a3;
    --floor-base-b: #b89876;
    --floor-plank:  rgba(60, 35, 15, 0.18);

    /* Cubicle dividers — gray fabric */
    --cubicle-wall: #c9c5be;

    /* Screen colors per status — vivid because they're the focal point */
    --screen-working:    #1aa756;
    --screen-blocked:    #d8930b;
    --screen-recovering: #e23232;
    --screen-idle:       #2c3e55;
    --screen-offline:    #14171c;

    position: relative;
    min-height: 100%;
    padding-bottom: 4rem;
}

/* ── Header bar ──────────────────────────────────────────────────── */

.floor-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.6rem 0 1rem;
    flex-wrap: wrap;
    border-bottom: 1px solid var(--bs-border-color);
    margin-bottom: 1rem;
}
.floor-bar-title { display: flex; gap: 0.75rem; align-items: center; }
.floor-icon {
    width: 44px; height: 44px;
    border-radius: 10px;
    background: linear-gradient(135deg, var(--brand-primary, #0d6efd), color-mix(in srgb, var(--brand-primary, #0d6efd) 70%, #000));
    color: #fff;
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 4px 12px color-mix(in srgb, var(--brand-primary, #0d6efd) 40%, transparent);
}
.floor-clock {
    font-variant-numeric: tabular-nums;
    color: #16a34a; font-weight: 600;
}
.floor-bar-controls {
    display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
}

/* View toggle */
.view-toggle {
    display: inline-flex;
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    padding: 2px;
}
.view-btn {
    display: inline-flex; align-items: center; gap: 0.3rem;
    background: transparent; border: 0;
    color: var(--bs-secondary-color);
    font-size: 0.78rem; font-weight: 500;
    padding: 0.3rem 0.7rem;
    border-radius: 999px;
    cursor: pointer;
    transition: all 0.15s ease;
}
.view-btn:hover { color: var(--bs-body-color); }
.view-btn.active {
    background: var(--brand-primary, #0d6efd);
    color: #fff;
    box-shadow: 0 3px 8px color-mix(in srgb, var(--brand-primary, #0d6efd) 35%, transparent);
}

/* Live + World view buttons get a special accent treatment so they read as
   the "premium" experiences. Live's gradient hints at the animated motion
   you get when you click it; World's faded indicating it's not ready. */
.view-btn-live.active {
    background: linear-gradient(135deg, #0ea5e9, #6366f1, #a855f7);
    box-shadow: 0 4px 14px rgba(99, 102, 241, 0.4);
}
.view-btn-disabled {
    opacity: 0.5;
    cursor: not-allowed;
}
.view-btn-tag {
    display: inline-block;
    padding: 0.05rem 0.4rem;
    border-radius: 999px;
    font-size: 0.55rem;
    font-weight: 800;
    letter-spacing: 0.06em;
    background: linear-gradient(135deg, #0ea5e9, #a855f7);
    color: #fff;
    margin-left: 0.15rem;
}
.view-btn-tag-soon {
    background: var(--bs-tertiary-bg);
    color: var(--bs-secondary-color);
    border: 1px solid var(--bs-border-color);
}
.view-btn.active .view-btn-tag { background: rgba(255,255,255,0.25); }

/* search */
.floor-search {
    display: flex; align-items: center; gap: 0.4rem;
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    padding: 0.25rem 0.75rem;
    transition: box-shadow 0.15s ease, border-color 0.15s ease;
}
.floor-search:focus-within {
    border-color: var(--brand-primary, #0d6efd);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--brand-primary, #0d6efd) 18%, transparent);
}
.floor-search input {
    border: 0; outline: 0; background: transparent;
    color: var(--bs-body-color); font-size: 0.85rem; width: 160px;
}
.floor-search i { color: var(--bs-secondary-color); font-size: 0.85rem; }

/* status filter chips */
.floor-filters { display: flex; gap: 0.3rem; flex-wrap: wrap; }
.filter-chip {
    display: inline-flex; align-items: center; gap: 0.35rem;
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    color: var(--bs-secondary-color);
    border-radius: 999px;
    padding: 0.25rem 0.65rem;
    font-size: 0.75rem;
    cursor: pointer;
    transition: all 0.12s ease;
}
.filter-chip:hover { border-color: var(--brand-primary, #0d6efd); color: var(--bs-body-color); }
.filter-chip.active {
    border-color: transparent; color: #fff;
    background: var(--brand-primary, #0d6efd);
    box-shadow: 0 4px 10px color-mix(in srgb, var(--brand-primary, #0d6efd) 35%, transparent);
}
.filter-chip .chip-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.chip-working    .chip-dot { background: #22c55e; }
.chip-blocked    .chip-dot { background: #f59e0b; }
.chip-recovering .chip-dot { background: #ef4444; }
.chip-idle       .chip-dot { background: #6b7280; }
.chip-offline    .chip-dot { background: #9ca3af; }
.chip-all        .chip-dot { background: var(--brand-primary, #0d6efd); }
.filter-chip.active .chip-dot { background: rgba(255,255,255,0.9); }
.chip-count {
    font-variant-numeric: tabular-nums; font-weight: 600;
    margin-left: 0.15rem; opacity: 0.85;
}

.ctrl-btn {
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    color: var(--bs-body-color);
    border-radius: 999px;
    width: 34px; height: 34px;
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    transition: all 0.12s ease;
}
.ctrl-btn:hover { border-color: var(--brand-primary, #0d6efd); color: var(--brand-primary, #0d6efd); }
.ctrl-btn:disabled { opacity: 0.55; cursor: not-allowed; }

.spin { animation: rot 1s linear infinite; }
@keyframes rot { to { transform: rotate(360deg); } }

.db-offline-chip {
    display: inline-flex; align-items: center; gap: 0.35rem;
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
    border: 1px solid var(--bs-warning-border-subtle, #ffe69c);
    background: var(--bs-warning-bg-subtle, #fff3cd);
    color: var(--bs-warning-text-emphasis, #664d03);
    font-size: 0.78rem; font-weight: 600;
    white-space: nowrap;
}

/* ── Comms ticker ─────────────────────────────────────────────────── */

.comms-ticker {
    display: flex; align-items: center; gap: 0.75rem;
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--brand-primary, #0d6efd) 12%, var(--bs-body-bg)),
        var(--bs-body-bg) 65%);
    border: 1px solid var(--bs-border-color);
    border-radius: 12px;
    padding: 0.45rem 0.75rem;
    margin-bottom: 1rem;
    overflow: hidden;
}
.comms-icon {
    font-size: 0.72rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--brand-primary, #0d6efd);
    white-space: nowrap; flex-shrink: 0;
}
.comms-track {
    display: flex; gap: 0.5rem; overflow-x: auto;
    scrollbar-width: thin; padding-bottom: 0.15rem;
}
.comms-track::-webkit-scrollbar { height: 4px; }
.comms-track::-webkit-scrollbar-thumb { background: var(--bs-border-color); border-radius: 2px; }
.comms-pill {
    display: inline-flex; align-items: center; gap: 0.3rem;
    padding: 0.18rem 0.55rem;
    background: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    font-size: 0.76rem; white-space: nowrap; flex-shrink: 0;
}
.comms-dot { width: 8px; height: 8px; border-radius: 50%; }
.comms-arrow { color: var(--brand-primary, #0d6efd); font-weight: 700; }

/* ── HUD ──────────────────────────────────────────────────────────── */

.floor-hud {
    position: sticky;
    top: 0.5rem; z-index: 20;
    display: flex; gap: 0.5rem;
    margin: 0 0 0.75rem auto;
    width: fit-content;
    padding: 0.5rem 0.75rem;
    background: color-mix(in srgb, var(--bs-body-bg) 85%, transparent);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border: 1px solid var(--bs-border-color);
    border-radius: 14px;
    box-shadow: 0 6px 20px rgba(0,0,0,0.08);
}
.hud-stat {
    display: flex; flex-direction: column; align-items: flex-start;
    padding: 0 0.6rem; min-width: 70px;
    border-right: 1px solid var(--bs-border-color);
}
.hud-stat:last-child { border-right: 0; }
.hud-num {
    font-size: 1.15rem; font-weight: 700; line-height: 1;
    font-variant-numeric: tabular-nums;
}
.hud-label {
    font-size: 0.62rem;
    text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--bs-secondary-color);
    margin-top: 0.2rem;
}
.hud-money .hud-num { color: var(--brand-primary, #0d6efd); }

/* ── Floor stage (the SVG container) ─────────────────────────────── */

.floor-stage {
    position: relative;
    width: 100%;
    overflow: hidden;
    border-radius: 16px;
    border: 1px solid var(--bs-border-color);
    /* Edge fade — gives the floor "depth" against the page */
    box-shadow:
        inset 0 0 60px rgba(0,0,0,0.10),
        0 8px 24px rgba(0,0,0,0.08);
    background:
        radial-gradient(ellipse at top, rgba(255,255,255,0.4), transparent 60%),
        var(--floor-base-a);
    perspective: 2400px;
    perspective-origin: center 30%;
}

.floor-svg {
    display: block;
    width: 100%;
    height: auto;
    transition: transform 0.6s cubic-bezier(.4,.0,.2,1);
    transform-origin: center center;
}

/* ── View modes ──────────────────────────────────────────────────── */

/* PLAN — default top-down; nothing extra. */

/* ISO — tilt the SVG. The floor leans back, giving 3D office depth. */
.view-iso .floor-svg {
    transform: rotateX(54deg) rotateZ(0deg) scale(0.95);
    transform-origin: center 35%;
    /* drop shadow for the whole tilted plate */
    filter: drop-shadow(0 32px 40px rgba(0,0,0,0.28));
}
.view-iso .floor-stage {
    /* a bit of vertical headroom for the tilted plate */
    padding: 2rem 0;
}

/* When iso, the cubicle nameplates rotate flat to the floor — keep readable */
.view-iso .cubicle-label text { font-weight: 700; }

/* ── Cubicle (SVG group) state-driven styling ────────────────────── */

.cubicle {
    cursor: pointer;
    transition: filter 0.18s ease, opacity 0.2s ease;
    /* Block native drag + text-select inside SVG groups. Without these,
       click-and-drag on a cubicle triggers the browser's "drag image"
       behavior on SVG content, which makes hover feel like the user is
       trying to drag the desk. */
    user-select: none;
    -webkit-user-select: none;
    -webkit-user-drag: none;
    -webkit-tap-highlight-color: transparent;
}
/* IMPORTANT — do NOT use a transform (translate, scale) here. The cubicle
   <g> is the same element that owns mouseenter/mouseleave; if the visual
   bounds shift on hover, the cursor falls outside the new bounds → leave
   fires → no-hover state restores → cursor inside again → enter fires.
   Loop = "flicker / drag attempt" feel. Use filter or color changes
   only, which never move the hit-test geometry. */
.cubicle:hover {
    filter: brightness(1.05) drop-shadow(0 4px 10px rgba(0, 0, 0, 0.18));
}
.cubicle:focus-visible { outline: none; }
.cubicle:focus-visible .cubicle-floor {
    stroke: var(--brand-primary, #0d6efd);
    stroke-width: 2;
}

/* Screen color per status */
.status-working    .cubicle-screen { fill: var(--screen-working);    }
.status-blocked    .cubicle-screen { fill: var(--screen-blocked);    }
.status-recovering .cubicle-screen { fill: var(--screen-recovering); }
.status-idle       .cubicle-screen { fill: var(--screen-idle);       }
.status-offline    .cubicle-screen { fill: var(--screen-offline);    }

/* LED color + animation */
.status-working    .cubicle-led { fill: #22c55e; animation: led-pulse 1.6s ease-in-out infinite; }
.status-blocked    .cubicle-led { fill: #f59e0b; animation: led-pulse 2s ease-in-out infinite; }
.status-recovering .cubicle-led { fill: #ef4444; animation: led-pulse 1.1s ease-in-out infinite; }
.status-idle       .cubicle-led { fill: #6b7280; }
.status-offline    .cubicle-led { fill: #475467; opacity: 0.5; }
@keyframes led-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.35; } }

/* Working cubicles: subtle screen flicker (working chip animation) */
.status-working .cubicle-screen { animation: screen-flicker 5s ease-in-out infinite; }
@keyframes screen-flicker {
    0%, 92%, 100% { fill: var(--screen-working); }
    93%   { fill: color-mix(in srgb, var(--screen-working) 55%, white); }
    94%   { fill: var(--screen-working); }
    97%   { fill: color-mix(in srgb, var(--screen-working) 70%, white); }
    98%   { fill: var(--screen-working); }
}

/* Bloom intensity by status */
.status-offline .cubicle-bloom { opacity: 0.3; }
.status-working .cubicle-bloom { animation: bloom-pulse 3s ease-in-out infinite; transform-origin: 110px 80px; }
@keyframes bloom-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.7; } }

/* Recovering: spin a slow halo */
.status-recovering .cubicle-bloom { animation: bloom-rotate 4s linear infinite; transform-origin: 110px 80px; }
@keyframes bloom-rotate { to { transform: rotate(360deg); } }

/* Offline cubicles dim everything */
.status-offline .cubicle-floor,
.status-offline .cubicle-head,
.status-offline .cubicle-mug,
.status-offline .cubicle-plant { opacity: 0.55; }

/* Orchestrator polish */
.is-orchestrator .cubicle-head {
    filter: drop-shadow(0 0 4px rgba(246,193,67,0.85));
}
.cubicle-crown { animation: crown-glow 3s ease-in-out infinite; transform-origin: center; transform-box: fill-box; }
@keyframes crown-glow {
    0%, 100% { filter: drop-shadow(0 0 1px rgba(246, 193, 67, 0.4)); }
    50%      { filter: drop-shadow(0 0 5px rgba(246, 193, 67, 1)); }
}

/* Search dim */
.cubicle.dimmed { opacity: 0.18; }
.is-searching .cubicle.dimmed { filter: grayscale(70%); }
.is-searching .cubicle:not(.dimmed) .cubicle-floor { stroke: var(--brand-primary, #0d6efd); stroke-width: 2; }

/* Status filter dim — same trick */
.floor-shell.filter-working    .cubicle:not(.status-working)    { opacity: 0.18; }
.floor-shell.filter-blocked    .cubicle:not(.status-blocked)    { opacity: 0.18; }
.floor-shell.filter-recovering .cubicle:not(.status-recovering) { opacity: 0.18; }
.floor-shell.filter-idle       .cubicle:not(.status-idle)       { opacity: 0.18; }
.floor-shell.filter-offline    .cubicle:not(.status-offline)    { opacity: 0.18; }

/* ── Hover tooltip ───────────────────────────────────────────────── */

/* Pinned to the top-right of the stage instead of following the cursor.
   Cursor-following caused a flicker loop: tooltip catches up to cursor →
   cursor is now over tooltip → mouseleave fires on cubicle → tooltip
   hides → cursor over cubicle again → mouseenter → repeat at ~60fps.
   pointer-events: none guarantees the cursor passes through the tooltip
   even when it overlaps; combined with a fixed corner position, no
   flicker is possible. */
.agent-tooltip {
    position: absolute;
    top: 4.25rem;
    right: 1rem;
    z-index: 30;
    width: 320px;
    max-width: calc(100% - 2rem);
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 14px;
    padding: 0.85rem;
    box-shadow: 0 18px 44px rgba(15, 23, 42, 0.18),
                0 4px 10px rgba(15, 23, 42, 0.08);
    pointer-events: none;
    font-size: 0.82rem;
    animation: tt-in 0.16s ease-out;
}
@keyframes tt-in {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: translateY(0); }
}

.tt-head {
    display: flex; gap: 0.6rem; align-items: center;
    margin-bottom: 0.5rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--bs-border-color);
}
.tt-avatar {
    width: 36px; height: 36px;
    border-radius: 50%;
    color: #fff; font-weight: 700;
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
    box-shadow: 0 2px 6px rgba(0,0,0,0.2);
}
.tt-name { font-weight: 700; font-size: 0.9rem; color: var(--bs-body-color); }
.tt-role { font-size: 0.72rem; color: var(--bs-secondary-color); }
.tt-status {
    margin-left: auto; flex-shrink: 0;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.tt-status-working    { background: rgba(34, 197, 94, 0.15); color: #15803d; }
.tt-status-blocked    { background: rgba(245, 158, 11, 0.15); color: #b45309; }
.tt-status-recovering { background: rgba(239, 68, 68, 0.15); color: #b91c1c; }
.tt-status-idle       { background: rgba(107, 114, 128, 0.15); color: #4b5563; }
.tt-status-offline    { background: rgba(156, 163, 175, 0.18); color: #6b7280; }

[data-bs-theme="dark"] .tt-status-working    { color: #4ade80; }
[data-bs-theme="dark"] .tt-status-blocked    { color: #fbbf24; }
[data-bs-theme="dark"] .tt-status-recovering { color: #fca5a5; }

.tt-task {
    display: flex; gap: 0.4rem; align-items: flex-start;
    background: var(--bs-tertiary-bg);
    padding: 0.4rem 0.55rem;
    border-radius: 8px;
    line-height: 1.35;
}
.tt-task-icon { flex-shrink: 0; }
.tt-quiet { color: var(--bs-secondary-color); font-style: italic; justify-content: center; }
.tt-age { font-size: 0.72rem; color: var(--bs-secondary-color); margin-top: 0.25rem; padding-left: 0.25rem; }

.tt-stats { display: flex; gap: 0.4rem; margin-top: 0.5rem; }
.tt-stat {
    flex: 1;
    display: flex; flex-direction: column;
    padding: 0.4rem;
    background: var(--bs-tertiary-bg);
    border-radius: 8px;
    align-items: center;
}
.tt-stat-num {
    font-size: 0.95rem; font-weight: 700; line-height: 1;
    font-variant-numeric: tabular-nums;
}
.tt-stat-lbl {
    font-size: 0.62rem; text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--bs-secondary-color);
    margin-top: 0.2rem;
}
.tt-hint {
    text-align: center;
    font-size: 0.66rem;
    color: var(--bs-secondary-color);
    margin-top: 0.4rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

/* ── Cards view ──────────────────────────────────────────────────── */

.cards-stage { display: flex; flex-direction: column; gap: 1.5rem; }
.card-room {
    border: 1px solid hsla(var(--room-hue, 220), 50%, 55%, 0.4);
    border-radius: 14px;
    background: linear-gradient(180deg,
        hsla(var(--room-hue, 220), 70%, 92%, 0.18),
        transparent 50%);
    overflow: hidden;
}
.card-room-head {
    display: flex; gap: 0.6rem; align-items: center;
    padding: 0.65rem 1rem;
    background: hsla(var(--room-hue, 220), 60%, 50%, 0.08);
    border-bottom: 1px solid hsla(var(--room-hue, 220), 50%, 55%, 0.25);
    font-weight: 600;
    font-size: 0.95rem;
}
.card-room-icon { font-size: 1.2rem; }
.card-room-count {
    margin-left: auto;
    font-size: 0.72rem;
    color: var(--bs-secondary-color);
    text-transform: uppercase; letter-spacing: 0.05em;
}
.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 0.65rem;
    padding: 0.85rem;
}
.agent-card {
    position: relative;
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-rows: auto auto;
    gap: 0 0.65rem;
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 12px;
    padding: 0.6rem 0.7rem;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.agent-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 10px 20px rgba(0,0,0,0.08);
    border-color: var(--brand-primary, #0d6efd);
}
.agent-card.dimmed { opacity: 0.25; }
.agent-card.is-orchestrator { border-color: rgba(246,193,67,0.55); box-shadow: inset 3px 0 0 #f6c143; }

.ac-led {
    position: absolute; top: 8px; right: 8px;
    width: 8px; height: 8px; border-radius: 50%;
}
.status-working .ac-led    { background: #22c55e; box-shadow: 0 0 8px #22c55e; animation: led-pulse 1.6s ease-in-out infinite; }
.status-blocked .ac-led    { background: #f59e0b; box-shadow: 0 0 8px #f59e0b; animation: led-pulse 2s ease-in-out infinite; }
.status-recovering .ac-led { background: #ef4444; box-shadow: 0 0 8px #ef4444; animation: led-pulse 1.1s ease-in-out infinite; }
.status-idle .ac-led       { background: #6b7280; }
.status-offline .ac-led    { background: #9ca3af; opacity: 0.4; }

/* "On a call" chip — orthogonal to status: a live voice call is in progress.
   Shown next to the status LED (cards view) and status text (ops view). */
.oncall-chip {
    display: inline-flex; align-items: center; gap: 0.28em;
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    font-size: 0.62rem; font-weight: 700;
    letter-spacing: 0.04em; text-transform: uppercase;
    color: #ede9fe;
    background: rgba(139, 92, 246, 0.28);
    border: 1px solid rgba(139, 92, 246, 0.65);
    box-shadow: 0 0 8px rgba(139, 92, 246, 0.45);
    animation: oncall-pulse 2s ease-in-out infinite;
    white-space: nowrap;
}
.oncall-chip .bi { font-size: 0.66rem; line-height: 1; }
/* Cards view: the card is position:relative with the LED pinned top-right —
   park the chip just left of it. Darker text on the light card background. */
.agent-card .oncall-chip {
    position: absolute; top: 4px; right: 22px;
    color: #6d28d9;
    background: rgba(139, 92, 246, 0.14);
}
@keyframes oncall-pulse {
    0%, 100% { opacity: 1;    box-shadow: 0 0 8px  rgba(139, 92, 246, 0.45); }
    50%      { opacity: 0.72; box-shadow: 0 0 14px rgba(139, 92, 246, 0.75); }
}

.ac-avatar {
    grid-row: 1 / span 2;
    width: 42px; height: 42px;
    border-radius: 50%;
    color: #fff; font-weight: 700;
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 2px 6px rgba(0,0,0,0.2);
    flex-shrink: 0;
}
.ac-meta { min-width: 0; }
.ac-name { font-weight: 600; font-size: 0.88rem; line-height: 1.2; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ac-role { font-size: 0.7rem; color: var(--bs-secondary-color); margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ac-task {
    grid-column: 2; margin-top: 0.4rem;
    font-size: 0.74rem;
    color: var(--bs-body-color);
    background: var(--bs-tertiary-bg);
    padding: 0.25rem 0.45rem;
    border-radius: 6px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ac-stats {
    grid-column: 1 / -1;
    display: flex; gap: 0.3rem; margin-top: 0.5rem;
    flex-wrap: wrap;
}
.ac-pill {
    display: inline-flex; align-items: center; gap: 0.15rem;
    padding: 0.05rem 0.4rem;
    border-radius: 999px;
    font-size: 0.68rem;
    background: var(--bs-tertiary-bg);
    color: var(--bs-secondary-color);
    border: 1px solid var(--bs-border-color);
}
.ac-fail { background: rgba(239,68,68,0.1); color: #b91c1c; border-color: rgba(239,68,68,0.3); }

/* ── Loading + empty ─────────────────────────────────────────────── */

.floor-loading {
    display: flex; align-items: center; justify-content: center;
    min-height: 240px;
}
.floor-empty {
    text-align: center;
    padding: 4rem 1rem;
    border: 1px dashed var(--bs-border-color);
    border-radius: 14px;
}

/* ── Responsive ──────────────────────────────────────────────────── */

@media (max-width: 768px) {
    .view-toggle { width: 100%; justify-content: center; }
    .floor-bar-controls { gap: 0.35rem; }
    .floor-search input { width: 100%; }
    .floor-search { flex: 1; }
    .floor-hud { width: 100%; flex-wrap: wrap; }
    /* Iso doesn't read well on tiny screens — fall back to plan */
    .view-iso .floor-svg { transform: none; filter: none; }
}

/* ──────────────────────────────────────────────────────────────────
   WORLD VIEW (B) — three.js voxel office. The canvas fills the stage;
   a help-strip overlays the bottom-left explaining controls.
   ────────────────────────────────────────────────────────────────── */

.world-stage {
    /* Override the wood-floor radial gradient — the 3D scene paints its
       own backdrop. We just want a clean dark frame around the canvas. */
    background: #0b0f17;
    box-shadow:
        inset 0 0 80px rgba(0, 0, 0, 0.55),
        0 12px 28px rgba(0, 0, 0, 0.35);
    overflow: hidden;
    /* Keep the stage tall enough that the 3D scene has room to breathe. */
    min-height: 70vh;
    position: relative;
}
.world-stage::before { display: none; }   /* time-of-day tint doesn't apply in 3D */

.world-canvas {
    display: block;
    width: 100%;
    height: 100%;
    min-height: 70vh;
    cursor: grab;
    /* Touch/drag UX — let the canvas own pointer events; never select text. */
    touch-action: none;
    user-select: none;
    -webkit-user-select: none;
    -webkit-tap-highlight-color: transparent;
}
.world-canvas:active { cursor: grabbing; }

.world-help {
    position: absolute;
    bottom: 1rem;
    left: 1rem;
    z-index: 5;
    padding: 0.55rem 0.85rem;
    border-radius: 999px;
    font-size: 0.74rem;
    color: rgba(255, 255, 255, 0.78);
    background: rgba(11, 15, 23, 0.7);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border: 1px solid rgba(255, 255, 255, 0.08);
    pointer-events: none;
}
.world-help strong {
    color: #ffffff;
    font-weight: 700;
}

/* World button on the view toggle: subtle 3D-cube gradient. */
.view-btn-world.active {
    background: linear-gradient(135deg, #f59e0b, #ec4899, #6366f1);
    box-shadow: 0 4px 14px rgba(236, 72, 153, 0.4);
}

/* ──────────────────────────────────────────────────────────────────
   LIVE VIEW (A) — animated work-flow particles, click-to-zoom camera,
   time-of-day floor tint. Layered on top of the existing Plan render.
   ────────────────────────────────────────────────────────────────── */

/* Smooth zoom: when the camera flies to a cubicle, the .floor-content
   group transforms with a soft cubic-bezier. transform-origin is 0,0
   so the C# math does its own translate + scale. */
.view-live .floor-content,
.floor-content {
    transform-origin: 0 0;
    transition: transform 0.7s cubic-bezier(.22, 1, .36, 1);
}

/* While zoomed, dim every cubicle EXCEPT the focused one — the user is
   in "spotlight on this agent" mode. */
.view-live.is-zoomed .cubicle:not(.zoomed-target) { opacity: 0.35; }
.view-live.is-zoomed .cubicle.zoomed-target {
    /* Ring around the focused cubicle so it pops in the zoom. */
    filter: drop-shadow(0 0 12px rgba(99, 102, 241, 0.7));
}

/* ── Comms-flow layer ─────────────────────────────────────────────
   For each (orchestrator → executor) edge, two stacked SVG paths:
     .comms-line   — a fat low-opacity glow stroke (the "trail")
     .comms-dashes — animated dashed stroke on top (the "packets")
   Plus a pulsing circle at the destination so the eye knows where
   the work is arriving. */
.comms-flow-layer {
    pointer-events: none; /* never intercept clicks meant for cubicles */
}
.comms-line {
    fill: none;
    stroke: url(#comms-grad);
    stroke-width: 6;
    stroke-linecap: round;
    opacity: 0.35;
}
.comms-dashes {
    fill: none;
    stroke: url(#comms-grad);
    stroke-width: 2.5;
    stroke-linecap: round;
    stroke-dasharray: 6 14;
    animation: comms-flow 1.4s linear infinite;
}
@keyframes comms-flow {
    to { stroke-dashoffset: -40; }
}
.comms-arrival {
    fill: #a855f7;
    filter: drop-shadow(0 0 8px rgba(168, 85, 247, 0.85));
    animation: comms-arrival 1.5s ease-in-out infinite;
}
@keyframes comms-arrival {
    0%, 100% { r: 5; opacity: 0.95; }
    50%      { r: 10; opacity: 0.4; }
}

/* ── Zoom buttons (HTML overlay) ──────────────────────────────── */
.zoom-back-btn,
.zoom-open-btn {
    position: absolute;
    top: 1rem;
    z-index: 40;
    display: inline-flex;
    align-items: center;
    padding: 0.45rem 0.85rem;
    border-radius: 999px;
    font-size: 0.82rem;
    font-weight: 600;
    text-decoration: none;
    border: 1px solid var(--bs-border-color);
    background: color-mix(in srgb, var(--bs-body-bg) 92%, transparent);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    color: var(--bs-body-color);
    cursor: pointer;
    box-shadow: 0 6px 18px rgba(0,0,0,0.12);
    transition: transform 0.12s ease, box-shadow 0.18s ease;
    animation: zoom-btn-in 0.4s cubic-bezier(.22, 1, .36, 1) backwards;
}
.zoom-back-btn { left: 1rem; }
.zoom-open-btn { left: 11rem; }
.zoom-back-btn:hover,
.zoom-open-btn:hover {
    transform: translateY(-1px);
    box-shadow: 0 10px 22px rgba(0,0,0,0.18);
    border-color: var(--brand-primary, #0d6efd);
    color: var(--brand-primary, #0d6efd);
}
@keyframes zoom-btn-in {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ── Time-of-day floor tint ──────────────────────────────────────
   Only applies in Live view. Each bucket layers a gentle wash on top
   of the wood floor so the same office "feels" like morning vs night.
   The night bucket dims further so monitor-glow becomes the focal
   light source. Set by C# from JS interop on first render. */
.view-live[data-time-bucket="morning"] .floor-stage::before,
.view-live[data-time-bucket="day"] .floor-stage::before,
.view-live[data-time-bucket="afternoon"] .floor-stage::before,
.view-live[data-time-bucket="evening"] .floor-stage::before,
.view-live[data-time-bucket="night"] .floor-stage::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 1;
    border-radius: inherit;
    transition: background 0.8s ease;
}
.view-live[data-time-bucket="morning"]   .floor-stage::before { background: linear-gradient(180deg, rgba(186, 220, 255, 0.18), rgba(255, 240, 220, 0.06)); }
.view-live[data-time-bucket="day"]       .floor-stage::before { background: linear-gradient(180deg, rgba(255, 250, 220, 0.06), transparent); }
.view-live[data-time-bucket="afternoon"] .floor-stage::before { background: linear-gradient(180deg, rgba(255, 200, 140, 0.18), rgba(255, 180, 110, 0.10)); }
.view-live[data-time-bucket="evening"]   .floor-stage::before { background: linear-gradient(180deg, rgba(120, 100, 160, 0.20), rgba(60, 50, 100, 0.18)); }
.view-live[data-time-bucket="night"]     .floor-stage::before {
    background:
        radial-gradient(ellipse at center, rgba(20, 25, 60, 0.15), rgba(8, 10, 30, 0.55));
}

/* In night mode, push monitor screens slightly brighter so they read as
   the dominant light source. */
.view-live[data-time-bucket="night"] .cubicle-screen { filter: brightness(1.25) saturate(1.1); }
.view-live[data-time-bucket="night"] .cubicle-bloom  { opacity: 1.1; }

/* ── Dark mode: night office ─────────────────────────────────────── */

[data-bs-theme="dark"] .floor-shell {
    --floor-base-a: #2c241b;
    --floor-base-b: #1a140d;
    --floor-plank:  rgba(255, 240, 220, 0.06);
    --cubicle-wall: #4a4640;

    --screen-working:    #21c265;
    --screen-blocked:    #f0a410;
    --screen-recovering: #ef3b3b;
    --screen-idle:       #283344;
    --screen-offline:    #0a0d12;
}

[data-bs-theme="dark"] .floor-stage {
    background:
        radial-gradient(ellipse at top, rgba(255,255,255,0.06), transparent 60%),
        var(--floor-base-a);
    box-shadow:
        inset 0 0 80px rgba(0,0,0,0.45),
        0 12px 28px rgba(0,0,0,0.45);
}

[data-bs-theme="dark"] .floor-hud {
    background: color-mix(in srgb, #0c1018 70%, transparent);
}

[data-bs-theme="dark"] .agent-tooltip {
    box-shadow: 0 18px 50px rgba(0,0,0,0.6), 0 4px 10px rgba(0,0,0,0.3);
}

/* =====================================================================
   Lane C — "Living Office" ambient micro-animations.

   All of these run purely off CSS/SVG: no JS, no extra DOM churn, no
   data dependency. They activate on the existing Plan/Iso/Live views.
   Style policy: each animation is < 5% opacity contribution so a floor
   full of them never feels chaotic. Reduced-motion users get static.
   ===================================================================== */

/* Floating dust motes — drift diagonally, fade in and out. The mote
   count + positions come from C# (DustMotes helper). */
.floor-dust { pointer-events: none; }
.floor-dust circle {
    opacity: 0;
    animation: dust-drift 14s linear infinite;
    transform-box: fill-box;
    transform-origin: center;
    will-change: transform, opacity;
}
@keyframes dust-drift {
    0%   { opacity: 0;    transform: translate( 0px,  0px); }
    20%  { opacity: 0.55; }
    80%  { opacity: 0.45; }
    100% { opacity: 0;    transform: translate(34px, -22px); }
}
/* In bright day, dust is barely there; in evening/night it's the
   visible "atmosphere." */
[data-time-bucket="day"]       .floor-dust circle { opacity: 0; animation-duration: 22s; }
[data-time-bucket="afternoon"] .floor-dust circle { animation-duration: 18s; }
[data-time-bucket="evening"]   .floor-dust circle { filter: drop-shadow(0 0 2px rgba(255, 220, 180, 0.45)); }
[data-time-bucket="night"]     .floor-dust circle { filter: drop-shadow(0 0 3px rgba(180, 200, 255, 0.6)); }

/* Room spend glow — opacity scales with the room's share of today's
   spend (--spend-intensity is set on the .room <g> from C#). The
   actual ellipse is in the SVG; this just animates a gentle breathe. */
.room-spend-bloom {
    opacity: calc(var(--spend-intensity, 0.1) * 1);
    mix-blend-mode: screen;
    animation: room-breathe 6s ease-in-out infinite;
    pointer-events: none;
}
@keyframes room-breathe {
    0%, 100% { transform: scale(1);     filter: blur(0px); }
    50%      { transform: scale(1.04);  filter: blur(0.6px); }
}

/* Mug steam — two puffs offset, rising + fading. Only puffs while the
   agent is Working or Idle (Blocked/Offline mugs are "cold"). */
.cubicle-steam { opacity: 0; pointer-events: none; }
.cubicle.status-working .cubicle-steam,
.cubicle.status-idle    .cubicle-steam,
.cubicle.status-recovering .cubicle-steam { opacity: 1; }
.cubicle-steam .steam-puff {
    transform-box: fill-box;
    transform-origin: center bottom;
    animation: steam-rise 2.6s ease-out infinite;
    opacity: 0;
}
.cubicle-steam .steam-puff-b {
    animation-delay: 1.3s;
    opacity: 0;
}
@keyframes steam-rise {
    0%   { opacity: 0;    transform: translate(0, 0) scale(0.6); }
    20%  { opacity: 0.8; }
    100% { opacity: 0;    transform: translate(0, -12px) scale(1.4); }
}

/* Plant leaves — gentle 4-degree sway, slightly different period
   per cubicle via :nth-of-type modulo so the floor doesn't sync. */
.cubicle-plant-leaves {
    transform-box: fill-box;
    transform-origin: 0 100%;
    animation: plant-sway 4.5s ease-in-out infinite;
}
.cubicle:nth-of-type(2n) .cubicle-plant-leaves { animation-duration: 5.3s; animation-delay: 0.6s; }
.cubicle:nth-of-type(3n) .cubicle-plant-leaves { animation-duration: 4.0s; animation-delay: 1.2s; }
@keyframes plant-sway {
    0%, 100% { transform: rotate(-4deg); }
    50%      { transform: rotate( 4deg); }
}

/* Keyboard glow — pulses green under the keyboard ONLY while working.
   Reinforces the "typing right now" cue. */
.cubicle-keyboard-glow { opacity: 0; pointer-events: none; }
.cubicle.status-working .cubicle-keyboard-glow {
    opacity: 0.85;
    animation: keyboard-typing 0.55s ease-in-out infinite;
}
.cubicle.status-recovering .cubicle-keyboard-glow {
    opacity: 0.6;
    animation: keyboard-typing 1.4s ease-in-out infinite;
    /* Recovering glow is red — repurpose the radial-gradient via a hue rotate. */
    filter: hue-rotate(-110deg);
}
@keyframes keyboard-typing {
    0%, 100% { opacity: 0.35; transform: scaleX(0.95); }
    50%      { opacity: 0.95; transform: scaleX(1.05); }
}

/* Tilted keyboard "key-press" tick — barely-there nudge so the keyboard
   reads as "alive" without a sprite sheet. */
.cubicle.status-working .cubicle-keyboard {
    animation: keyboard-press 0.45s ease-in-out infinite;
    transform-box: fill-box;
    transform-origin: center;
}
@keyframes keyboard-press {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(0.4px); }
}

/* Comms-flow particles. The SVG defines <circle r=4 fill=url(...)>;
   animateMotion handles the path travel. This rule just adds glow. */
.comms-particles circle {
    filter: drop-shadow(0 0 4px rgba(168, 85, 247, 0.9));
}

/* Reduced-motion: kill the ambient layer entirely so it stays calm. */
@media (prefers-reduced-motion: reduce) {
    .floor-dust circle,
    .cubicle-steam .steam-puff,
    .cubicle-plant-leaves,
    .cubicle.status-working .cubicle-keyboard-glow,
    .cubicle.status-working .cubicle-keyboard,
    .room-spend-bloom,
    .comms-particles circle,
    .comms-dashes { animation: none !important; }
}

/* =====================================================================
   Lane B — Mission Control "Ops" view.

   Dark command-center aesthetic — every card is a glowing console.
   Heavy use of monospaced type, neon-cyan accents, hex-grid background,
   sweeping radar cone. Forces dark colors regardless of theme so the
   "ops floor" reads correctly even when the rest of the app is light.
   ===================================================================== */

.view-btn-ops.active {
    background: linear-gradient(135deg, #0c2340, #0ea5e9, #22d3ee);
    box-shadow: 0 4px 14px rgba(14, 165, 233, 0.5);
}
.view-btn-sim.active {
    background: linear-gradient(135deg, #fb923c, #ec4899, #8b5cf6);
    box-shadow: 0 4px 14px rgba(236, 72, 153, 0.45);
}

.ops-stage {
    /* Force dark surface regardless of app theme — "war room" lighting. */
    --ops-bg-0: #060c14;
    --ops-bg-1: #0a1424;
    --ops-grid: rgba(34, 211, 238, 0.08);
    --ops-line: rgba(34, 211, 238, 0.28);
    --ops-text: #cbd5e1;
    --ops-text-dim: #64748b;
    --ops-accent: #22d3ee;
    --ops-accent-soft: rgba(34, 211, 238, 0.18);
    --ops-warn: #f59e0b;
    --ops-fail: #ef4444;
    --ops-ok: #22c55e;

    position: relative;
    background:
        radial-gradient(ellipse at top, rgba(8, 47, 73, 0.6), transparent 55%),
        radial-gradient(ellipse at bottom right, rgba(15, 23, 42, 0.6), transparent 60%),
        linear-gradient(180deg, var(--ops-bg-1), var(--ops-bg-0));
    color: var(--ops-text);
    font-family: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
    border-radius: 14px;
    padding: 1rem 1rem 0;
    min-height: 70vh;
    overflow: hidden;
    box-shadow: 0 18px 60px rgba(0, 0, 0, 0.45), inset 0 0 0 1px rgba(34, 211, 238, 0.1);
}

/* Hex-grid background — SVG-encoded, tiled. */
.ops-grid-bg {
    position: absolute; inset: 0; pointer-events: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='52' height='30' viewBox='0 0 52 30'%3E%3Cpath d='M13 1 L26 1 L33 14 L26 27 L13 27 L6 14 Z M39 1 L52 1 L52 27 L39 27 L32 14 Z M-7 14 L0 1 L0 27 Z' fill='none' stroke='%2322d3ee' stroke-opacity='0.10' stroke-width='1'/%3E%3C/svg%3E");
    background-size: 52px 30px;
    opacity: 0.7;
    mix-blend-mode: screen;
}

/* CRT scan-lines — very subtle. Adds the "this is a screen" effect. */
.ops-scanlines {
    position: absolute; inset: 0; pointer-events: none; z-index: 1;
    background-image: repeating-linear-gradient(
        180deg,
        rgba(255, 255, 255, 0) 0px,
        rgba(255, 255, 255, 0) 2px,
        rgba(0, 0, 0, 0.05) 3px,
        rgba(0, 0, 0, 0.05) 4px
    );
    mix-blend-mode: multiply;
    opacity: 0.6;
}

/* Rotating radar scope — range rings + crosshair, a sweeping afterglow wedge
   with a crisp leading "hand", a soft centre glow, and a blip that pings as
   the sweep crosses it. */
.ops-radar {
    position: absolute;
    top: 50%; left: 50%;
    width: min(720px, 80%);
    aspect-ratio: 1;
    transform: translate(-50%, -50%);
    pointer-events: none;
    opacity: 0.7;
    z-index: 0;
    border-radius: 50%;
    box-shadow: inset 0 0 90px rgba(34, 211, 238, 0.10), 0 0 34px rgba(34, 211, 238, 0.07);
}
/* soft scope glow at the centre */
.ops-radar::before {
    content: ""; position: absolute; inset: 0; border-radius: 50%;
    background: radial-gradient(circle at 50% 50%, rgba(34, 211, 238, 0.12), transparent 62%);
}
/* a contact blip that flashes when the sweep passes (~1–2 o'clock) */
.ops-radar::after {
    content: ""; position: absolute;
    top: 35%; left: 63%; width: 9px; height: 9px; border-radius: 50%;
    background: rgba(52, 255, 196, 0.95);
    box-shadow: 0 0 10px rgba(52, 255, 196, 0.9);
    animation: ops-radar-ping 4.5s linear infinite;
}
.ops-radar-rings {
    position: absolute; inset: 0;
    border-radius: 50%;
    background:
        radial-gradient(circle, transparent 0 21%, var(--ops-line) 21% 21.4%, transparent 21.4%),
        radial-gradient(circle, transparent 0 38%, var(--ops-line) 38% 38.4%, transparent 38.4%),
        radial-gradient(circle, transparent 0 55%, var(--ops-line) 55% 55.4%, transparent 55.4%),
        radial-gradient(circle, transparent 0 75%, var(--ops-line) 75% 75.4%, transparent 75.4%),
        /* crosshair axes */
        linear-gradient(to right, transparent calc(50% - 0.5px), var(--ops-line) calc(50% - 0.5px) calc(50% + 0.5px), transparent calc(50% + 0.5px)),
        linear-gradient(to bottom, transparent calc(50% - 0.5px), var(--ops-line) calc(50% - 0.5px) calc(50% + 0.5px), transparent calc(50% + 0.5px));
    opacity: 0.5;
}
.ops-radar-sweep {
    position: absolute; inset: 0;
    border-radius: 50%;
    /* bright leading edge fading into a long afterglow trail */
    background: conic-gradient(from 0deg,
        rgba(34, 211, 238, 0.50) 0deg,
        rgba(34, 211, 238, 0.14) 42deg,
        rgba(34, 211, 238, 0) 130deg,
        rgba(34, 211, 238, 0) 360deg);
    animation: ops-radar-spin 4.5s linear infinite;
    transform-origin: 50% 50%;
}
/* the crisp sweep "hand" at the leading edge (centre → top) */
.ops-radar-sweep::after {
    content: ""; position: absolute;
    top: 0; left: 50%; width: 2px; height: 50%;
    transform: translateX(-50%);
    background: linear-gradient(to bottom, rgba(34, 211, 238, 0.95), rgba(34, 211, 238, 0));
    box-shadow: 0 0 8px rgba(34, 211, 238, 0.7);
}
@keyframes ops-radar-spin {
    to { transform: rotate(360deg); }
}
@keyframes ops-radar-ping {
    0%, 12%  { opacity: 0; transform: scale(0.6); }
    16%      { opacity: 1; transform: scale(1.25); }   /* flash as the sweep crosses it */
    45%      { opacity: 0.25; transform: scale(1); }
    100%     { opacity: 0; transform: scale(0.9); }
}

/* Top strip */
.ops-strip {
    position: relative; z-index: 3;
    display: flex; justify-content: space-between; align-items: center;
    gap: 1rem; flex-wrap: wrap;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--ops-accent-soft);
    margin-bottom: 0.75rem;
}
.ops-strip-title {
    display: flex; align-items: center; gap: 0.55rem;
    font-size: 0.95rem; font-weight: 700;
    letter-spacing: 0.18em;
    color: var(--ops-accent);
    text-shadow: 0 0 12px rgba(34, 211, 238, 0.4);
}
.ops-strip-sub {
    font-size: 0.7rem; font-weight: 500;
    color: var(--ops-text-dim);
    letter-spacing: 0.12em;
    margin-left: 0.4rem;
}
.ops-strip-stats { display: flex; gap: 1rem; flex-wrap: wrap; font-variant-numeric: tabular-nums; }
.ops-stat {
    display: inline-flex; flex-direction: column; align-items: center;
    padding: 0 0.65rem; border-left: 1px solid var(--ops-accent-soft);
    line-height: 1.05;
}
.ops-stat:first-child { border-left: 0; }
.ops-stat-num { font-size: 1.2rem; font-weight: 700; color: var(--ops-text); }
.ops-stat-lbl { font-size: 0.6rem; letter-spacing: 0.15em; color: var(--ops-text-dim); text-transform: uppercase; }
.ops-stat.working .ops-stat-num { color: var(--ops-ok); }
.ops-stat.blocked .ops-stat-num { color: var(--ops-warn); }
.ops-stat.blocked.is-on .ops-stat-num {
    color: var(--ops-fail);
    animation: ops-pulse 0.9s ease-in-out infinite;
}
.ops-stat.fail .ops-stat-num { color: var(--ops-fail); }
.ops-stat.done .ops-stat-num { color: #38bdf8; }
.ops-stat.spend .ops-stat-num { color: #fcd34d; }

/* LED dots */
.ops-led {
    width: 10px; height: 10px; border-radius: 50%;
    box-shadow: 0 0 8px currentColor;
    flex-shrink: 0;
}
.ops-led-ok       { background: var(--ops-ok);    color: var(--ops-ok);    }
.ops-led-alarm    { background: var(--ops-fail);  color: var(--ops-fail);  animation: ops-pulse 0.65s ease-in-out infinite; }
.ops-led-working  { background: var(--ops-ok);    color: var(--ops-ok);    animation: ops-pulse 1.6s ease-in-out infinite; }
.ops-led-blocked  { background: var(--ops-warn);  color: var(--ops-warn);  animation: ops-pulse 0.7s ease-in-out infinite; }
.ops-led-recovering { background: var(--ops-fail); color: var(--ops-fail); animation: ops-pulse 0.5s ease-in-out infinite; }
.ops-led-idle     { background: #475569;          color: #475569; }
.ops-led-offline  { background: #1e293b;          color: #1e293b; }

@keyframes ops-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50%      { opacity: 0.55; transform: scale(0.85); }
}

/* Klaxon banner */
.ops-klaxon {
    position: relative; z-index: 3;
    display: flex; align-items: center; gap: 0.7rem;
    padding: 0.55rem 0.9rem;
    margin-bottom: 0.85rem;
    border: 1px solid var(--ops-fail);
    border-radius: 8px;
    background:
        repeating-linear-gradient(45deg,
            rgba(239, 68, 68, 0.18) 0 12px,
            rgba(239, 68, 68, 0.06) 12px 24px);
    color: #fecaca;
    font-size: 0.82rem;
    box-shadow: 0 0 20px rgba(239, 68, 68, 0.35);
    animation: ops-klaxon-flash 1.4s ease-in-out infinite;
}
.ops-klaxon i { color: var(--ops-fail); font-size: 1.2rem; }
.ops-klaxon-link {
    margin-left: auto;
    color: #fecaca; text-decoration: none;
    border: 1px solid rgba(254, 202, 202, 0.4);
    padding: 0.18rem 0.6rem; border-radius: 6px;
    font-weight: 600; font-size: 0.78rem;
}
.ops-klaxon-link:hover { background: rgba(254, 202, 202, 0.18); }
@keyframes ops-klaxon-flash {
    0%, 100% { box-shadow: 0 0 20px rgba(239, 68, 68, 0.35); }
    50%      { box-shadow: 0 0 40px rgba(239, 68, 68, 0.65); }
}

/* Console grid */
.ops-console-grid {
    position: relative; z-index: 2;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
    gap: 0.85rem;
    padding-bottom: 1rem;
}

.floor-card {
    position: relative;
    background: linear-gradient(180deg, rgba(15, 23, 42, 0.85), rgba(2, 6, 23, 0.85));
    border: 1px solid var(--ops-accent-soft);
    border-radius: 10px;
    padding: 0.7rem 0.8rem 0.55rem;
    overflow: hidden;
    cursor: pointer;
    transition: transform 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    isolation: isolate;
}
.floor-card:hover {
    transform: translateY(-2px);
    border-color: var(--ops-accent);
    box-shadow: 0 8px 28px rgba(34, 211, 238, 0.28),
                inset 0 0 0 1px rgba(34, 211, 238, 0.45);
}
.floor-card.dimmed { opacity: 0.35; }
.floor-card.is-orchestrator {
    border-color: rgba(246, 193, 67, 0.55);
    box-shadow: 0 0 18px rgba(246, 193, 67, 0.18);
}
.floor-card.status-working    { border-left: 3px solid var(--ops-ok); }
.floor-card.status-blocked    {
    border-left: 3px solid var(--ops-warn);
    animation: floor-card-blocked-pulse 1.6s ease-in-out infinite;
}
.floor-card.status-recovering {
    border-left: 3px solid var(--ops-fail);
    animation: floor-card-recovering 0.6s ease-in-out infinite;
}
.floor-card.status-idle       { border-left: 3px solid #475569; }
.floor-card.status-offline    { border-left: 3px solid #1e293b; opacity: 0.7; }
@keyframes floor-card-blocked-pulse {
    0%, 100% { box-shadow: 0 0 0 rgba(245, 158, 11, 0); }
    50%      { box-shadow: 0 0 20px rgba(245, 158, 11, 0.4); }
}
@keyframes floor-card-recovering {
    0%, 100% { transform: translateX(0); }
    25%      { transform: translateX(-1px); }
    75%      { transform: translateX(1px); }
}

/* Sweep line that travels down the card — "we're scanning you" cue. */
.floor-card-sweep {
    position: absolute; left: 0; right: 0; top: -100%;
    height: 30%;
    background: linear-gradient(180deg, transparent, rgba(34, 211, 238, 0.16) 50%, transparent);
    pointer-events: none;
    animation: floor-card-sweep-fall 4.5s linear infinite;
    z-index: 1;
}
.floor-card.status-working .floor-card-sweep { animation-duration: 2.8s; }
.floor-card.status-idle    .floor-card-sweep,
.floor-card.status-offline .floor-card-sweep { animation-duration: 8s; opacity: 0.35; }
@keyframes floor-card-sweep-fall {
    0%   { top: -100%; }
    100% { top: 110%; }
}

.floor-card-head {
    display: flex; align-items: center; gap: 0.45rem;
    margin-bottom: 0.2rem;
    position: relative; z-index: 2;
}
.floor-card-name {
    font-size: 0.82rem; font-weight: 700;
    letter-spacing: 0.1em;
    color: var(--ops-text);
}
.floor-card-crown { color: #fcd34d; font-size: 0.85rem; }
.floor-card-dept {
    margin-left: auto;
    font-size: 0.6rem; letter-spacing: 0.18em;
    color: var(--ops-text-dim);
}
.floor-card-meta {
    display: flex; justify-content: space-between;
    font-size: 0.66rem; letter-spacing: 0.06em;
    color: var(--ops-text-dim);
    margin-bottom: 0.5rem;
    position: relative; z-index: 2;
}
.floor-card-status {
    font-weight: 700;
    color: var(--ops-accent);
}
.floor-card.status-blocked    .floor-card-status { color: var(--ops-warn); }
.floor-card.status-recovering .floor-card-status { color: var(--ops-fail); }
.floor-card.status-idle       .floor-card-status { color: #94a3b8; }
.floor-card.status-offline    .floor-card-status { color: #475569; }

.floor-card-now {
    display: flex; align-items: baseline; gap: 0.45rem;
    padding: 0.35rem 0.55rem;
    border: 1px dashed var(--ops-accent-soft);
    border-radius: 6px;
    background: rgba(34, 211, 238, 0.06);
    margin-bottom: 0.45rem;
    position: relative; z-index: 2;
    font-size: 0.78rem;
}
.floor-card-now-lbl {
    color: var(--ops-accent);
    font-weight: 700;
    letter-spacing: 0.15em;
    font-size: 0.62rem;
}
.floor-card-now-val { color: var(--ops-text); flex: 1; }
.floor-card-now-quiet { color: var(--ops-text-dim); }
.floor-card-now-age {
    margin-left: auto;
    font-size: 0.6rem;
    color: var(--ops-text-dim);
    font-variant-numeric: tabular-nums;
}

.floor-card-task {
    font-size: 0.78rem;
    margin-bottom: 0.4rem;
    color: var(--ops-text);
    position: relative; z-index: 2;
}
.floor-card-task-dia {
    color: var(--ops-accent);
    margin-right: 0.3rem;
}
.floor-card-task-empty { color: var(--ops-text-dim); font-style: italic; }

.floor-card-ticker {
    border-top: 1px dashed rgba(34, 211, 238, 0.12);
    padding: 0.4rem 0;
    font-size: 0.7rem;
    color: var(--ops-text-dim);
    line-height: 1.45;
    min-height: 3.6em;
    position: relative; z-index: 2;
}
.floor-card-ticker-row {
    font-variant-numeric: tabular-nums;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.floor-card-ticker-row:first-child { color: var(--ops-text); }
.floor-card-ticker-empty { color: var(--ops-text-dim); font-style: italic; }

.floor-card-foot {
    display: flex; gap: 0.4rem;
    padding-top: 0.4rem;
    border-top: 1px solid var(--ops-accent-soft);
    position: relative; z-index: 2;
}
.ops-foot-pill {
    display: inline-flex; align-items: center; gap: 0.2rem;
    padding: 0.12rem 0.45rem;
    border-radius: 999px;
    font-size: 0.66rem;
    font-weight: 600;
    background: rgba(34, 211, 238, 0.08);
    color: var(--ops-text);
    font-variant-numeric: tabular-nums;
}
.ops-foot-done { background: rgba(34, 197, 94, 0.15); color: #86efac; }
.ops-foot-fail { background: rgba(239, 68, 68, 0.18); color: #fecaca; }
.ops-foot-spend { background: rgba(252, 211, 77, 0.12); color: #fde68a; margin-left: auto; }

/* Timeline scrubber */
.ops-timeline {
    position: sticky;
    bottom: 0;
    background: linear-gradient(180deg, rgba(2, 6, 23, 0.4), rgba(2, 6, 23, 0.95));
    border-top: 1px solid var(--ops-accent-soft);
    padding: 0.45rem 0.5rem 0.55rem;
    margin: 0 -1rem;
    z-index: 4;
}
.ops-timeline-head {
    display: flex; justify-content: space-between;
    font-size: 0.62rem;
    letter-spacing: 0.18em;
    color: var(--ops-text-dim);
    margin-bottom: 0.3rem;
}
.ops-timeline-now { color: var(--ops-accent); }
.ops-timeline-bars {
    display: flex; gap: 1px;
    align-items: flex-end;
    height: 44px;
    border-bottom: 1px solid var(--ops-accent-soft);
}
.ops-tl-bar {
    flex: 1 1 0;
    background: linear-gradient(180deg, #22d3ee, #0ea5e9);
    border-radius: 2px 2px 0 0;
    position: relative;
    min-height: 4px;
    transition: height 0.4s ease;
}
.ops-tl-fail {
    position: absolute; left: 0; right: 0; top: 0;
    background: var(--ops-fail);
    border-radius: 2px 2px 0 0;
}
/* The last bar (most recent minute) gets a brighter "live" tint. */
.ops-tl-bar:last-child {
    background: linear-gradient(180deg, #67e8f9, #22d3ee);
    box-shadow: 0 0 8px rgba(34, 211, 238, 0.7);
}

.ops-stage.is-alarmed {
    box-shadow: 0 18px 60px rgba(239, 68, 68, 0.35),
                inset 0 0 0 1px rgba(239, 68, 68, 0.55);
}

@media (prefers-reduced-motion: reduce) {
    /* The Mission-Control radar sweep + blip are a deliberate, requested
       centerpiece of the Ops view — keep them animating even when the OS
       requests reduced motion (Windows "Animation effects" off, etc.). */
    .floor-card-sweep,
    .ops-led-alarm,
    .ops-led-working,
    .ops-led-blocked,
    .ops-led-recovering,
    .floor-card.status-blocked,
    .floor-card.status-recovering,
    .ops-klaxon { animation: none !important; }
}

/* =====================================================================
   Lane A — Sim City pixel-art view.

   Only the wrapper styling lives here — all rendering happens inside the
   <canvas> via agent-sim.js. The wrapper sets the canvas dimensions and
   styles the help / legend overlays.
   ===================================================================== */
.sim-stage {
    position: relative;
    width: 100%;
    height: min(78vh, 820px);
    border-radius: 14px;
    overflow: hidden;
    background: #0a1226;
    box-shadow: 0 14px 50px rgba(0, 0, 0, 0.35), inset 0 0 0 1px rgba(255, 255, 255, 0.04);
}
.sim-canvas {
    width: 100%;
    height: 100%;
    display: block;
    /* Smooth/vector rendering (no pixelation) — matches the polished
       illustration aesthetic of the redesigned renderer. */
    image-rendering: auto;
    cursor: grab;
}
.sim-canvas:active { cursor: grabbing; }

.sim-help {
    position: absolute;
    bottom: 12px;
    left: 12px;
    padding: 0.45rem 0.75rem;
    background: rgba(15, 23, 42, 0.7);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-radius: 8px;
    color: #cbd5e1;
    font-size: 0.72rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    pointer-events: none;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
}
.sim-help strong { color: #e2e8f0; }
.sim-clock {
    margin-left: 0.5rem;
    padding: 0.05rem 0.4rem;
    border-radius: 4px;
    background: rgba(34, 211, 238, 0.18);
    color: #67e8f9;
    text-transform: uppercase;
    font-size: 0.62rem;
    letter-spacing: 0.12em;
}

.sim-legend {
    position: absolute;
    top: 12px;
    right: 12px;
    display: flex;
    gap: 0.75rem;
    padding: 0.45rem 0.75rem;
    background: rgba(15, 23, 42, 0.7);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-radius: 8px;
    color: #cbd5e1;
    font-size: 0.7rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    pointer-events: none;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
}
.sim-legend span { display: inline-flex; align-items: center; gap: 0.3rem; }
.sim-dot {
    width: 8px; height: 8px; border-radius: 50%;
    box-shadow: 0 0 6px currentColor;
}
.sim-dot-working    { background: #22c55e; color: #22c55e; }
.sim-dot-blocked    { background: #f59e0b; color: #f59e0b; }
.sim-dot-recovering { background: #ef4444; color: #ef4444; }
.sim-dot-idle       { background: #64748b; color: #64748b; }
.sim-dot-offline    { background: #1f2937; color: #1f2937; }

/* =====================================================================
   Plan-view polish — architectural-blueprint paper aesthetic.

   When the user picks "Plan," we want it to feel like a working
   architect's drawing, not just a flat SVG. Layered tints + a fine
   grid overlay sell that vibe without touching the SVG content.
   ===================================================================== */
.view-plan .floor-stage {
    position: relative;
    background:
        /* Subtle vertical paper gradient */
        linear-gradient(180deg, #f6f1e6 0%, #ece4d2 100%);
    border-radius: 14px;
    box-shadow:
        inset 0 0 0 1px rgba(120, 80, 30, 0.18),
        0 18px 50px rgba(60, 40, 20, 0.18);
    padding: 8px;
}
.view-plan .floor-stage::before {
    /* Fine 12px grid overlay — reads as drafting paper. */
    content: '';
    position: absolute; inset: 0;
    background-image:
        linear-gradient(rgba(120, 80, 30, 0.06) 1px, transparent 1px),
        linear-gradient(90deg, rgba(120, 80, 30, 0.06) 1px, transparent 1px);
    background-size: 12px 12px;
    border-radius: inherit;
    pointer-events: none;
}
.view-plan .floor-stage::after {
    /* Vignette + subtle "tape" corners */
    content: '';
    position: absolute; inset: 0;
    border-radius: inherit;
    pointer-events: none;
    background:
        radial-gradient(ellipse at center, transparent 50%, rgba(60, 40, 20, 0.20) 100%);
}

[data-bs-theme="dark"] .view-plan .floor-stage {
    background:
        linear-gradient(180deg, #18243a 0%, #0c172a 100%);
    box-shadow:
        inset 0 0 0 1px rgba(80, 140, 220, 0.20),
        0 18px 50px rgba(5, 12, 30, 0.55);
}
[data-bs-theme="dark"] .view-plan .floor-stage::before {
    background-image:
        linear-gradient(rgba(120, 180, 255, 0.07) 1px, transparent 1px),
        linear-gradient(90deg, rgba(120, 180, 255, 0.07) 1px, transparent 1px);
}
[data-bs-theme="dark"] .view-plan .floor-stage::after {
    background:
        radial-gradient(ellipse at center, transparent 50%, rgba(0, 0, 0, 0.55) 100%);
}

/* World stage — full-bleed cinematic canvas, no chrome bleeding in. */
.world-stage {
    height: min(80vh, 880px) !important;
    border-radius: 14px;
    overflow: hidden;
    background: #06091a;
    box-shadow: 0 18px 60px rgba(0,0,0,0.50), inset 0 0 0 1px rgba(255,255,255,0.04);
}
.world-canvas {
    width: 100%;
    height: 100%;
    display: block;
    cursor: grab;
}
.world-canvas:active { cursor: grabbing; }
.world-help {
    position: absolute;
    bottom: 12px;
    left: 12px;
    padding: 0.45rem 0.75rem;
    background: rgba(15, 23, 42, 0.7);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-radius: 8px;
    color: #cbd5e1;
    font-size: 0.72rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    pointer-events: none;
    font-family: 'Inter', system-ui, sans-serif;
}
.world-help strong { color: #e2e8f0; }

/* Model status badge in the top-right corner of the World stage.
   Updated by agent-world.js as the GLB load resolves so the user always
   sees which character model is currently in use without DevTools. */
.world-model-badge {
    position: absolute;
    top: 12px;
    right: 12px;
    padding: 0.4rem 0.7rem;
    background: rgba(15, 23, 42, 0.78);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.10);
    color: #cbd5e1;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 0.7rem;
    pointer-events: none;
    z-index: 30;
    transition: border-color 0.25s ease, color 0.25s ease;
}
.world-model-badge:empty { display: none; }
.world-model-badge[data-kind="loaded"]    { border-color: rgba(34, 197, 94, 0.55); color: #86efac; }
.world-model-badge[data-kind="fallback"]  { border-color: rgba(59, 130, 246, 0.55); color: #93c5fd; }
.world-model-badge[data-kind="primitive"] { border-color: rgba(245, 158, 11, 0.55); color: #fcd34d; }
.world-model-badge[data-kind="loading"]   { border-color: rgba(99, 102, 241, 0.55); color: #c4b5fd; }

/* World controls — floating glass panel, top-right, character + theme picker */
.world-controls {
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 30;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 10px 12px;
    background: rgba(15, 23, 42, 0.78);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(99, 102, 241, 0.35);
    border-radius: 10px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
    color: #cbd5e1;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    font-size: 0.72rem;
    /* Sit ABOVE the model badge so they don't fight for the same corner */
    margin-top: 32px;
    transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.4s ease;
}
/* #11 — folded state: slide off to a thin tab on the right edge; a left accent
   bar hints it's there. Hover (or the JS mouseenter) springs it back. */
.world-controls.folded {
    transform: translateX(calc(100% - 10px));
    opacity: 0.6;
}
.world-controls.folded::before {
    content: "";
    position: absolute;
    left: -1px;
    top: 8px;
    bottom: 8px;
    width: 3px;
    border-radius: 3px;
    background: rgba(99, 102, 241, 0.9);
}
.world-controls.folded:hover {
    transform: none;
    opacity: 1;
}
.world-ctrl-build {
    font-size: 0.58rem;
    letter-spacing: 0.08em;
    color: #fbbf24;
    text-transform: uppercase;
    opacity: 0.8;
    margin-bottom: 2px;
}
.world-ctrl-row {
    display: flex;
    flex-direction: column;
    gap: 3px;
}
.world-ctrl-row > span {
    font-size: 0.62rem;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: #94a3b8;
    font-weight: 600;
}
.world-ctrl-row > select {
    background: #1e293b;
    color: #f1f5f9;
    border: 1px solid rgba(99, 102, 241, 0.40);
    border-radius: 6px;
    padding: 4px 8px;
    font-size: 0.78rem;
    min-width: 220px;
    cursor: pointer;
}
.world-ctrl-row > select:focus {
    outline: none;
    border-color: #818cf8;
    box-shadow: 0 0 0 2px rgba(129, 140, 248, 0.30);
}
/* Header row: build tag on the left, hide (×) button on the right. */
.world-ctrl-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
.world-ctrl-hide {
    background: transparent;
    border: none;
    color: #94a3b8;
    cursor: pointer;
    padding: 0 2px;
    line-height: 1;
    font-size: 0.72rem;
}
.world-ctrl-hide:hover { color: #f1f5f9; }
/* "Honor each agent's own character" — a horizontal checkbox row, distinct from
   the stacked label/select rows above it. */
.world-ctrl-check {
    flex-direction: row !important;
    align-items: center;
    gap: 7px !important;
    cursor: pointer;
}
.world-ctrl-check > input { cursor: pointer; margin: 0; }
.world-ctrl-check > span {
    text-transform: none !important;
    letter-spacing: 0 !important;
    font-size: 0.72rem !important;
    color: #cbd5e1 !important;
    font-weight: 500 !important;
}
/* Collapsed state — a single round glass button in the top-right corner. */
.world-controls-toggle {
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 30;
    margin-top: 32px;
    width: 34px;
    height: 34px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(15, 23, 42, 0.78);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(99, 102, 241, 0.35);
    border-radius: 9px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
    color: #cbd5e1;
    cursor: pointer;
    transition: color 0.2s ease, border-color 0.2s ease;
}
.world-controls-toggle:hover {
    color: #f1f5f9;
    border-color: #818cf8;
}

/* =====================================================================
   Neural HQ view — luminous orb constellation in a cathedral void.
   ===================================================================== */
.view-btn-neural.active {
    background: linear-gradient(135deg, #4f46e5, #a855f7, #ec4899);
    box-shadow: 0 4px 14px rgba(168, 85, 247, 0.55);
}

.neural-stage {
    position: relative;
    width: 100%;
    height: min(80vh, 880px) !important;
    border-radius: 14px;
    overflow: hidden;
    background: radial-gradient(ellipse at center, #0a0e1e 0%, #050712 100%);
    box-shadow:
        0 18px 60px rgba(0, 0, 0, 0.55),
        inset 0 0 80px rgba(99, 102, 241, 0.10),
        inset 0 0 0 1px rgba(168, 85, 247, 0.18);
}
.neural-canvas {
    width: 100%;
    height: 100%;
    display: block;
    cursor: grab;
}
.neural-canvas:active { cursor: grabbing; }

/* =====================================================================
   Floor chat — 3D-anchored panel.

   The anchor div is positioned by JS (translate3d every frame from
   agent-world.js). Inside that anchor we render the actual chat panel
   which is itself transformed (-100%, -100%) so it floats above + to
   the right of the anchor point rather than centered on it.
   ===================================================================== */
/* Universal floor chat — fixed bottom-right of the floor shell. Slides in
   from the right edge with a soft entrance animation. Visible from EVERY
   view (World, Neural, Sim, Plan, Iso, Ops, Cards) since it's mounted at
   the .floor-shell level outside any view branch. */
.floor-chat-panel-fixed {
    position: fixed;
    right: 1.25rem;
    bottom: 1.25rem;
    z-index: 200;
    width: 400px;
    max-width: calc(100vw - 2.5rem);
    max-height: calc(100vh - 5rem);
    display: flex;
    flex-direction: column;
    background: linear-gradient(180deg, #1e293b 0%, #0b1220 100%);
    color: #f1f5f9;
    border-radius: 16px;
    border: 1px solid rgba(129, 140, 248, 0.55);
    box-shadow:
        0 28px 80px rgba(0, 0, 0, 0.70),
        0 14px 28px rgba(0, 0, 0, 0.50),
        0 0 0 1px rgba(99, 102, 241, 0.45),
        0 0 40px rgba(99, 102, 241, 0.22);
    font-family: 'Inter', system-ui, -apple-system, "Segoe UI", sans-serif;
    overflow: hidden;
    animation: fcf-slide-in 0.28s cubic-bezier(.22, 1, .36, 1);
}
@keyframes fcf-slide-in {
    from { opacity: 0; transform: translateX(24px) translateY(8px); }
    to   { opacity: 1; transform: translateX(0)    translateY(0); }
}

/* Status-tinted top accent stripe — visually identifies the agent at a glance. */
.floor-chat-panel-fixed.status-working    { border-top: 3px solid #22c55e; }
.floor-chat-panel-fixed.status-blocked    { border-top: 3px solid #f59e0b; }
.floor-chat-panel-fixed.status-recovering { border-top: 3px solid #ef4444; }
.floor-chat-panel-fixed.status-idle       { border-top: 3px solid #6c8aaa; }
.floor-chat-panel-fixed.status-offline    { border-top: 3px solid #475569; }

/* Header */
.fc-head {
    display: flex; align-items: center; gap: 0.55rem;
    padding: 0.65rem 0.65rem 0.5rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.fc-avatar {
    width: 32px; height: 32px;
    border-radius: 50%;
    color: #fff;
    font-weight: 700;
    font-size: 0.72rem;
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
    flex-shrink: 0;
}
.fc-id { flex: 1; min-width: 0; }
.fc-name {
    font-weight: 700;
    font-size: 0.92rem;
    line-height: 1.1;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fc-crown { color: #fcd34d; }
.fc-sub {
    display: flex; align-items: center; gap: 0.3rem;
    font-size: 0.7rem;
    color: #94a3b8;
    margin-top: 0.1rem;
}
.fc-status {
    width: 6px; height: 6px;
    border-radius: 50%;
    box-shadow: 0 0 8px currentColor;
}
.fc-status-working    { background: #22c55e; color: #22c55e; animation: fc-pulse 1.4s ease-in-out infinite; }
.fc-status-blocked    { background: #f59e0b; color: #f59e0b; animation: fc-pulse 0.7s ease-in-out infinite; }
.fc-status-recovering { background: #ef4444; color: #ef4444; animation: fc-pulse 0.5s ease-in-out infinite; }
.fc-status-idle       { background: #6c8aaa; color: #6c8aaa; }
.fc-status-offline    { background: #475569; color: #475569; }
@keyframes fc-pulse { 0%,100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.5; transform: scale(0.8); } }

.fc-open, .fc-close {
    display: inline-flex; align-items: center; justify-content: center;
    width: 28px; height: 28px;
    border-radius: 6px;
    background: transparent;
    border: 0;
    color: #94a3b8;
    cursor: pointer;
    text-decoration: none;
    transition: background 0.15s ease, color 0.15s ease;
    flex-shrink: 0;
}
.fc-open:hover, .fc-close:hover {
    background: rgba(255, 255, 255, 0.08);
    color: #e2e8f0;
}

/* "Working on …" banner under the head — only when agent has an active task */
.fc-current {
    display: flex; align-items: center; gap: 0.4rem;
    padding: 0.35rem 0.7rem;
    background: rgba(34, 197, 94, 0.10);
    border-bottom: 1px solid rgba(34, 197, 94, 0.20);
    font-size: 0.72rem;
    color: #86efac;
}
.fc-pulse {
    width: 6px; height: 6px;
    border-radius: 50%;
    background: #22c55e;
    box-shadow: 0 0 8px #22c55e;
    animation: fc-pulse 1.0s ease-in-out infinite;
}

/* Message body */
.fc-body {
    padding: 0.5rem 0.6rem;
    max-height: 320px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, 0.12) transparent;
}
.fc-body::-webkit-scrollbar { width: 6px; }
.fc-body::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.12); border-radius: 3px; }

.fc-line { display: flex; }
.fc-line-user { justify-content: flex-end; }
.fc-line-agent { justify-content: flex-start; }
.fc-bubble {
    max-width: 84%;
    padding: 0.45rem 0.65rem;
    border-radius: 10px;
    font-size: 0.82rem;
    line-height: 1.4;
    word-wrap: break-word;
}
.fc-line-agent .fc-bubble {
    background: rgba(255, 255, 255, 0.06);
    color: #e2e8f0;
    border-top-left-radius: 4px;
}
.fc-line-user .fc-bubble {
    background: linear-gradient(135deg, #4f46e5, #6366f1);
    color: #fff;
    border-top-right-radius: 4px;
    box-shadow: 0 2px 8px rgba(99, 102, 241, 0.35);
}
.fc-bubble strong { color: #fff; }
.fc-bubble em { color: #c4b5fd; font-style: normal; font-weight: 500; }
.fc-bubble code {
    background: rgba(0, 0, 0, 0.35);
    color: #c4b5fd;
    padding: 0 0.25rem;
    border-radius: 3px;
    font-size: 0.78em;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
}
.fc-link {
    color: #67e8f9;
    text-decoration: none;
    border-bottom: 1px dotted rgba(103, 232, 249, 0.45);
}
.fc-link:hover { color: #a5f3fc; border-bottom-color: #a5f3fc; }

/* "Agent is thinking" typing-dots animation */
.fc-typing { display: inline-flex; gap: 0.2rem; align-items: center; padding: 0.55rem 0.7rem; }
.fc-typing span {
    width: 6px; height: 6px;
    border-radius: 50%;
    background: #94a3b8;
    animation: fc-typing 1.0s ease-in-out infinite;
}
.fc-typing span:nth-child(2) { animation-delay: 0.15s; }
.fc-typing span:nth-child(3) { animation-delay: 0.30s; }
@keyframes fc-typing {
    0%, 80%, 100% { opacity: 0.3; transform: translateY(0); }
    40%           { opacity: 1;   transform: translateY(-3px); }
}

/* Watched-tasks footer — visible only when chat has spawned tasks */
.fc-watched {
    display: flex; align-items: center; gap: 0.4rem;
    padding: 0.3rem 0.7rem;
    background: rgba(99, 102, 241, 0.12);
    border-top: 1px solid rgba(99, 102, 241, 0.22);
    font-size: 0.7rem;
    color: #c4b5fd;
}
.fc-watched i { color: #a78bfa; }

/* Blocked banner */
.fc-blocked {
    padding: 0.5rem 0.7rem;
    background: rgba(244, 114, 90, 0.14);
    border-top: 1px solid rgba(244, 114, 90, 0.28);
    font-size: 0.74rem;
    color: #fecaca;
}
.fc-blocked-head { margin-bottom: 0.4rem; }
.fc-blocked-head strong { color: #fff; }
.fc-blocked-why { color: #fca5a5; margin-left: 0.25rem; }
.fc-blocked-actions { display: flex; flex-wrap: wrap; gap: 0.35rem; align-items: center; }
.fc-blocked-actions .btn { font-size: 0.7rem; padding: 0.15rem 0.5rem; }
.fc-orphan-note { color: #fca5a5; font-style: italic; width: 100%; margin-top: 0.1rem; }

/* Input */
.fc-input {
    display: flex; gap: 0.35rem;
    padding: 0.5rem 0.55rem 0.6rem;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
}
.fc-input input {
    flex: 1;
    min-width: 0;
    padding: 0.4rem 0.65rem;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.10);
    background: rgba(0, 0, 0, 0.30);
    color: #e2e8f0;
    font-size: 0.82rem;
    outline: none;
    transition: border-color 0.15s ease;
    font-family: inherit;
}
.fc-input input:focus { border-color: #6366f1; }
.fc-input input::placeholder { color: #64748b; }
.fc-input button {
    display: inline-flex; align-items: center; justify-content: center;
    width: 38px;
    border-radius: 8px;
    border: 0;
    background: linear-gradient(135deg, #4f46e5, #6366f1);
    color: #fff;
    cursor: pointer;
    transition: transform 0.12s ease, box-shadow 0.18s ease;
}
.fc-input button:not(:disabled):hover {
    transform: translateY(-1px);
    box-shadow: 0 6px 14px rgba(99, 102, 241, 0.45);
}
.fc-input button:disabled {
    opacity: 0.5; cursor: not-allowed;
}

@media (prefers-reduced-motion: reduce) {
    .fc-status-working,
    .fc-status-blocked,
    .fc-status-recovering,
    .fc-pulse,
    .fc-typing span {
        animation: none !important;
    }
    .floor-chat-panel { animation: none !important; }
}

/* ── Immersive floor: hide the app chrome ─────────────────────────────────────────────────────
   When the floor "fullscreen" button is on, .floor-shell gets .floor-immersive (a fixed, full-viewport
   overlay). The app sidebar sits in its own stacking context and otherwise peeks through at top-left, so
   hide it while immersive. This MUST live in a static, linked stylesheet (agent-floor.css) — the same rule
   in MainLayout's <HeadContent> never rendered because the app has no <HeadOutlet>. :has() scopes it to the
   immersive element existing, so it self-restores the instant you exit fullscreen or navigate away. */
html:has(.floor-shell.floor-immersive) .ap-sidebar,
html:has(.floor-shell.floor-immersive) .ap-mobile-header {
    display: none !important;
}

/* ── Council Room: immersive fullscreen + floating toggle (v3) ─────────────
   Same CSS-overlay approach as the floor: #council-stage gets .floor-immersive
   via floorUi.toggleFullscreen('#council-stage'); the button lives INSIDE the
   stage so it stays reachable to exit. */
.council-fs-btn {
    position: absolute;
    top: 10px;
    left: 10px;
    z-index: 6;
    width: 34px;
    height: 34px;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    background: rgba(10, 14, 22, 0.55);
    color: #dfe5f0;
    display: flex;
    align-items: center;
    justify-content: center;
    backdrop-filter: blur(4px);
    cursor: pointer;
    transition: background 0.15s ease;
}
.council-fs-btn:hover { background: rgba(30, 40, 60, 0.8); }
#council-stage.floor-immersive {
    position: fixed !important;
    inset: 0 !important;
    z-index: 1050;
    height: 100vh !important;
    min-height: 100vh !important;
    border-radius: 0 !important;
}
html:has(#council-stage.floor-immersive) .ap-sidebar,
html:has(#council-stage.floor-immersive) .ap-mobile-header {
    display: none !important;
}
/* The floating council chat is a SIBLING of the stage (unlike the Agent
   Floor, where the panel lives inside the element that goes immersive), so
   at its normal z-index 200 it vanished under the z-1050 fullscreen overlay.
   Lift it above the overlay while immersive. */
html:has(#council-stage.floor-immersive) .floor-chat-panel-fixed {
    z-index: 1060 !important;
}

/* ──────────────────────────────────────────────────────────────────
   Phone-sized screens — the viewport-fixed stage heights assume a
   desktop window; on a phone the browser chrome + page header leave
   too little room, so shrink every 3D/sim stage.
   ────────────────────────────────────────────────────────────────── */
@media (max-width: 767.98px) {
    .world-stage {
        min-height: 55vh;
        /* Base rule pins height with !important — must out-!important it. */
        height: 55vh !important;
    }
    .world-canvas { min-height: 55vh; }
    .sim-stage { height: min(60vh, 820px); }
    .neural-stage { height: min(60vh, 880px) !important; }
    /* The help strip explains MOUSE controls (drag/scroll/right-drag) —
       meaningless on touch, and it covers the scene on a small canvas. */
    .world-help { display: none; }
    /* Floating controls panel: span the stage width instead of hugging the
       right edge, and let its 220px-min selects shrink with it. */
    .world-controls { left: 12px; right: 12px; }
    .world-ctrl-row > select { min-width: 0; width: 100%; }
}

/* ── Mobile: floor header + HUD strips (<768px) ─────────────────────────
   The title row, view toggle, and the sticky stat HUD are single-line flex
   strips sized for desktop — on a phone they ran past the right edge and
   made the whole page pan. Wrap them and let the HUD stats share the row. */
@media (max-width: 767.98px) {
    .floor-bar { flex-wrap: wrap; row-gap: 0.5rem; }
    /* Let the title row WRAP instead of squeezing: with the sleeping/awake
       chip + back-to-sleep button present, the fixed row crushed the title
       text into a ~6-line column that shoved the whole floor below the fold.
       Wrapped, the chips drop to their own compact row under the title. */
    .floor-bar-title { min-width: 0; flex-wrap: wrap; row-gap: 0.3rem; }
    .floor-bar-title h3 { font-size: 1.05rem; white-space: nowrap; }
    .floor-bar-title small { white-space: nowrap; }
    .floor-quiet-chip, .floor-awake-chip, .floor-oncall-chip, .floor-weekend-chip, .floor-sleep-btn {
        font-size: 0.7rem;
        padding: 0.16rem 0.5rem;
    }
    .floor-bar-controls { flex-wrap: wrap; row-gap: 0.35rem; }
    .floor-hud {
        position: static;            /* sticky + fit-content fought the narrow page */
        width: 100%;
        flex-wrap: wrap;
        margin: 0 0 0.6rem 0;
    }
    .hud-stat { min-width: 0; flex: 1 1 40%; border-right: 0; }
}
