/* Vulani AI shared UI theme -- same dark navy + orange visual language as
   Modules/eMapp/app/static/theme.css (decisions/0044), ported here for
   Suite-wide visual consistency across the global nav shell this module
   adds (decisions/0060 item 6). Not required to match eMapp exactly, just
   consistent with the Suite's own established look.
*/

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  background: #0d1f35;
  color: #d0e4f4;
}

/* Suite-wide dark scrollbar (decisions/0088) -- the default OS/browser
   scrollbar (light grey) looks out of place against every module's dark
   background; same light-on-transparent style applied identically in
   Portal/eMapp/Documents/Vulani's own theme files. */
* { scrollbar-width: thin; scrollbar-color: rgba(255,255,255,.25) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: rgba(255,255,255,.25); border-radius: 6px; }
*::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,.4); }

a { color: #f5a623; }

/* ── App header / global nav ── */
#app-header {
  background: linear-gradient(135deg, #0d1f35 0%, #1a3a5c 100%);
  color: white; padding: 10px 18px 8px;
  border-bottom: 2px solid #f5a623;
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 10px;
}
#app-header .brand { display: flex; align-items: center; gap: 12px; }
#app-header .logo {
  width: 36px; height: 36px; border-radius: 50%; background: #f5a623;
  display: flex; align-items: center; justify-content: center;
  font-size: 18px; font-weight: 800; color: #0d1f35; flex-shrink: 0;
}
#app-header h1 { font-size: .95rem; font-weight: 700; margin: 0; }
#app-header .back-link { font-size: .75rem; color: #8aaac8; text-decoration: none; }
#app-header .back-link:hover { color: #f5a623; }
#app-header nav { display: flex; gap: 14px; flex-wrap: wrap; }
#app-header nav a { font-size: .8rem; color: #b8d0e8; text-decoration: none; }
#app-header nav a:hover, #app-header nav a.active { color: #f5a623; }
#app-header .session-info { font-size: .75rem; color: #cdd5e0; text-align: right; }

/* decisions/0077 (supersedes decisions/0071's "keep the nav" reasoning
   below, overtaken by decisions/0075/0076): when embedded in Portal, this
   module's entire own header -- not just the logo/sign-out 0071
   targeted -- is redundant. Its Home/Chat/Dashboard/Briefing/Admin nav no
   longer corresponds to anything reachable from Portal (Dashboard is now
   its own Portal tab, Chat is superseded by the ambient widget per
   decisions/0074, Vulani AI itself is no longer a Portal tab at all per
   decisions/0076) -- in practice this rule now only ever fires on the
   /dashboard route, the one content page from this module still embedded.
   Standalone access (no Portal parent) is unaffected -- full original
   header stays exactly as before, since there's no Portal chrome to defer
   to there. decisions/0074: when embedded in Portal, this module's OWN
   copy of #vulani-widget is also suppressed (see the rule below) -- Portal
   mounts its own ambient copy via this module's /widget route at chrome
   level, so a content page's own copy would just be a second, duplicate
   widget on screen at once. Standalone access keeps its own widget exactly
   as before; only the embedded case changes. */
.vs-embedded #app-header { display: none; }
.vs-embedded .vulani-page form[action='/auth/logout'] { display: none; }

/* David: a real, hand-bumped version visible on screen at all times, even
   embedded (deliberately outside #app-header so the hide rule above
   doesn't take it down too) -- so a stale tab/iframe is distinguishable
   from a genuinely updated one without opening devtools. Content pages
   only (_VERSION_BADGE in main.py), not /widget -- that's meant to be a
   small, clean overlay with nothing but the widget itself. Top-right, not
   bottom-right -- bottom-right collided with the ambient Vulani widget
   bubble (decisions/0074) that floats there across every Portal tab, same
   fix already applied to eMapp's own #emapp-version. */
#vulani-version {
  position: fixed; right: 6px; top: 4px; z-index: 900;
  font-family: 'Consolas', 'Courier New', monospace;
  font-size: .62rem; letter-spacing: .06em;
  color: #6b7f94; opacity: .75; pointer-events: none;
}

/* ── Page body ── */
.vulani-page { padding: 0 18px 24px; }
.vulani-page h1 { font-size: 1.1rem; color: #f5a623; margin: 14px 0 8px; }
.vulani-page h3 {
  font-size: .7rem; color: #f5a623; text-transform: uppercase;
  letter-spacing: .1em; margin: 14px 0 6px; opacity: .8;
}

select, input[type="text"] {
  background: #1a3a5c; border: 1px solid #2a5a8a; color: #d0e4f4;
  padding: 4px 8px; border-radius: 3px; font-size: 12px;
}
select:focus, input[type="text"]:focus { outline: none; border-color: #f5a623; }

button {
  padding: 5px 14px; border: 1px solid #3a5a7a; border-radius: 3px;
  cursor: pointer; font-size: 12px; background: #1e3a58; color: #b8d0e8;
  transition: all .15s;
}
button:hover:not(:disabled) { background: #254870; color: white; border-color: #5a7a9a; }
button:disabled { opacity: .4; cursor: default; }

/* ── KPI / briefing cards ── */
.kpi-row { display: flex; gap: 1rem; margin: 1rem 0; flex-wrap: wrap; }
.kpi-cell {
  border: 1px solid #2a5a8a; background: #112235; padding: .6rem 1.1rem; border-radius: 4px;
  min-width: 140px;
}
.kpi-cell .label { font-size: .72rem; color: #8aaac8; }
.kpi-cell .value { font-size: 1.15rem; font-weight: 700; color: #e8f0f8; }

/* ── Dashboard (decisions/0060 item 4): replicated from the old app's
   real Dashboard.tsx -- KPI row above, then a 2-up chart grid, then the
   worst-variance leaderboard. ── */
.dash-error { color: #ffaaaa; font-size: .8rem; margin: 4px 0; }
.dash-charts-grid {
  display: grid; grid-template-columns: 7fr 5fr; gap: 1rem; margin-bottom: 1rem;
}
@media (max-width: 900px) { .dash-charts-grid { grid-template-columns: 1fr; } }
.dash-card {
  border: 1px solid #2a5a8a; background: #112235; border-radius: 6px;
  padding: 1rem 1.1rem; margin-bottom: 1rem;
}
.dash-card h3 {
  font-size: .78rem; font-weight: 600; color: #d0e4f4; text-transform: none;
  letter-spacing: normal; opacity: 1; margin: 0 0 .8rem;
}
.dash-chart-wrap { position: relative; height: 260px; }
.dash-empty { color: #8aaac8; font-size: .85rem; font-style: italic; }

/* decisions/0090: 30-Day Payment compliance section -- visually separated
   from the budget/spend panels above it since it's a distinct data slice
   (payment-process compliance, not spend-vs-budget). */
#dashboard-payment-section { margin-top: .5rem; border-top: 1px solid #2a5a8a; padding-top: 1rem; }
#dashboard-payment-section h2 { font-size: 1rem; font-weight: 700; color: #e8f0f8; margin: 0 0 .5rem; }

.dash-lb-row { margin-bottom: .7rem; }
.dash-lb-row:last-child { margin-bottom: 0; }
.dash-lb-head {
  display: flex; justify-content: space-between; align-items: center;
  font-size: .82rem; color: #d0e4f4; margin-bottom: 4px;
}
.dash-lb-meta { display: flex; gap: 10px; align-items: center; font-weight: 600; font-size: .78rem; }
.dash-lb-badge { font-weight: 700; width: 3em; flex: 0 0 auto; text-align: right; }
.dash-lb-variance { width: 5.2em; flex: 0 0 auto; text-align: right; }
.dash-lb-bar-track {
  position: relative; height: 10px; background: rgba(255,255,255,.1); border-radius: 6px;
}
.dash-lb-bar-fill { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 6px; transition: width .3s; }
.dash-lb-bar-mark { position: absolute; top: -3px; bottom: -3px; width: 2px; background: rgba(255,255,255,.7); }

.dash-lb-toolbar { margin-bottom: .5rem; }
.dash-lb-toolbar h3 { margin: 0 0 6px; }
.dash-lb-sort { display: flex; gap: 6px; align-items: center; justify-content: flex-end; flex-wrap: wrap; }
.dash-lb-sort-btn, .dash-lb-dir-btn {
  background: #16283c; border: 1px solid #2a5a8a; color: #9fc2de; border-radius: 4px;
  font-size: .72rem; font-weight: 600; padding: 3px 8px; cursor: pointer;
}
.dash-lb-sort-btn.active { background: #1f4a6e; color: #e8f0f8; border-color: #4fd1c5; }
.dash-lb-dir-btn { color: #d0e4f4; }
.dash-lb-dir-btn:hover, .dash-lb-sort-btn:hover { border-color: #4fd1c5; }

.briefing-card {
  border: 1px solid #2a5a8a; background: #112235; padding: .8rem 1.1rem; border-radius: 4px;
  margin: .6rem 0;
}
.briefing-card .title { font-size: .95rem; font-weight: 700; color: #e8f0f8; }
.briefing-card .why { font-size: .82rem; color: #9ab4cc; margin-top: 4px; }
.briefing-card.severity-critical { border-color: #cc3333; }
.briefing-card.severity-important { border-color: #f5a623; }
.briefing-card.severity-today { border-color: #f5a623; }
.briefing-card.severity-informational { border-color: #2a5a8a; }
.briefing-card .card-actions { margin-top: 8px; display: flex; gap: 8px; }

/* ── Chat turn styling, shared by the floating Vulani widget below ──
   Ported from VulaniTranscript.tsx exactly: a role label above plain text,
   no bubble/box background in any shell -- the first version invented
   solid chat-bubble backgrounds (#1a3a5c/#112235) that don't exist in the
   real component at all, which is why fullscreen's glass overlay looked
   like an opaque card instead of translucent glass with the face showing
   through around the text. */
.chat-turn { padding: 4px 10px; margin: 2px 0; font-size: 13px; }
.chat-turn.user { text-align: right; }
.chat-turn-role { font-size: .68rem; font-weight: 600; opacity: .65; margin-bottom: 2px; }
.chat-turn-text { white-space: pre-wrap; }

/* ── Vulani floating widget (decisions/0067) ──
   Ported shell states from the old app's Minimized/Compact/Fullscreen
   (spec §4) -- a persistent avatar/bubble that floats over every page,
   not a page of its own. Guided/BottomSheet aren't separate visual
   shells here (see vulani_widget.js's own comment for why). */
#vulani-widget { position: fixed; z-index: 1000; }

/* decisions/0074/0075/0083: /widget is mounted by Portal as a small,
   corner-anchored overlay iframe (not the full viewport) -- transparent so
   only the bubble/panel show, not a white rectangle. decisions/0083 (David:
   "we dont have a max button to max vulani ino the whole screen") restores
   the expand control here -- Portal now grows the iframe box itself to
   fullscreen on request (Portal/app/static/theme.css's
   .vs-ambient-fullscreen), so there's real room for it after all. This is
   also now the ONLY way to reach fullscreen at all: decisions/0076 retired
   the Vulani AI tab this control originally deferred to. Guided mode stays
   unreachable from here (no trigger for it exists on this page -- it was
   always reached via Briefing's own Discuss button, not this control). */
html:has(body.vulani-ambient), body.vulani-ambient { background: transparent; margin: 0; overflow: hidden; }

/* decisions/0074: when this page is embedded in Portal (any content page
   -- Home/Chat/Admin/Dashboard/Briefing), suppress this module's own copy
   of the widget -- Portal already mounts one via /widget at chrome level,
   so a content page keeping its own would show two at once (the real bug
   this rule fixes, found live). :not(.vulani-ambient) excludes /widget
   itself from this rule -- that page IS Portal's ambient copy and must
   keep showing its widget even though it's also embedded. Standalone
   access (no Portal parent, .vs-embedded absent) is unaffected either way. */
html.vs-embedded body:not(.vulani-ambient) #vulani-widget { display: none; }

#vulani-bubble {
  display: none; position: fixed; right: 24px; bottom: 24px; z-index: 1000;
  width: 64px; height: 64px; border-radius: 50%;
  padding: 0; border: 2px solid #2dd4bf; overflow: hidden;
  box-shadow: 0 12px 32px rgba(0,0,0,.4); cursor: pointer;
}
#vulani-bubble img {
  display: block; width: 100%; height: 100%; border-radius: 50%;
  object-fit: cover; object-position: 50% 20%;
}
#vulani-bubble-dot {
  position: absolute; right: 2px; bottom: 2px; width: 14px; height: 14px;
  border-radius: 50%; background: #2dd4bf; border: 2px solid #0d1f35;
}
#vulani-bubble:hover { transform: scale(1.05); }

#vulani-panel {
  display: none; position: fixed; z-index: 1000;
  background: #0d1f35; border: 1px solid #2a5a8a; border-radius: 10px;
  box-shadow: 0 12px 32px rgba(0,0,0,.5);
  flex-direction: column; overflow: hidden;
}
.vulani-panel-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 8px 12px; border-bottom: 1px solid #1e3a5c; background: #112235;
}
.vulani-panel-title { font-size: .85rem; font-weight: 700; color: #f5a623; flex-shrink: 0; }
/* Ported from VulaniContextBar.tsx: what page context Vulani currently
   has. Clicking opens the trust panel (decisions/0070), matching the real
   component's own behaviour. */
#vulani-context-bar {
  flex: 1; min-width: 0; margin: 0 10px; padding: 0; font-size: .72rem; color: #8aaac8;
  font-style: italic; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  background: none; border: none; text-align: left; cursor: pointer; font-family: inherit;
}
#vulani-context-bar:hover { color: #b8d0e8; text-decoration: underline; }

/* Trust panel (decisions/0070, ported from VulaniTrustPanel.tsx): a
   right-side drawer, spec §11 -- users can see at any time exactly what
   Vulani understands. */
#vulani-trust-backdrop {
  display: none; position: fixed; inset: 0; z-index: 1999; background: rgba(0,0,0,.4);
}
#vulani-trust-backdrop.open { display: block; }
#vulani-trust-panel {
  position: fixed; top: 0; right: -380px; bottom: 0; width: 380px; max-width: 90vw;
  z-index: 2000; background: #0d1f35; border-left: 1px solid #2a5a8a;
  box-shadow: -12px 0 32px rgba(0,0,0,.5); display: flex; flex-direction: column;
  transition: right .25s ease;
}
#vulani-trust-panel.open { right: 0; }
#vulani-trust-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px; border-bottom: 1px solid #1e3a5c; font-weight: 700; color: #f5a623;
}
#vulani-trust-close { background: none; border: none; color: #8aaac8; font-size: 20px; cursor: pointer; padding: 0 6px; }
#vulani-trust-close:hover { color: #fff; }
#vulani-trust-body { flex: 1; overflow-y: auto; padding: 14px 16px; }
.vulani-trust-disclaimer { font-size: .72rem; color: #8aaac8; line-height: 1.5; margin: 0 0 16px; }
.vulani-trust-section-title { font-size: .68rem; font-weight: 700; color: #8aaac8; letter-spacing: .08em; margin: 14px 0 6px; }
.vulani-trust-empty { font-size: .8rem; color: #8aaac8; font-style: italic; }
.vulani-trust-field { display: flex; gap: 8px; font-size: .82rem; padding: 3px 0; }
.vulani-trust-field-key { color: #8aaac8; min-width: 100px; flex-shrink: 0; }
#vulani-video-btn, #vulani-speaker-btn { opacity: .55; }
#vulani-video-btn.active, #vulani-speaker-btn.active { opacity: 1; }
.vulani-panel-mark {
  display: inline-block; width: 20px; height: 20px; border-radius: 50%;
  object-fit: cover; object-position: top center;
  border: 1px solid #2dd4bf; margin-right: 6px; vertical-align: middle;
}
/* decisions/0082: David flagged these as visibly mis-sized. They were
   padding-sized only, and the group mixes emoji glyphs (🎥 🔊) with text
   ones (⤢ –), whose intrinsic widths and baselines differ a lot -- so
   every button came out a different size with its glyph sitting off
   centre, and video/speaker carried their own narrower padding on top of
   that. One fixed square box per control, glyph centred, so the row reads
   as one set of controls regardless of what each glyph is. */
.vulani-panel-controls { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
.vulani-panel-controls button {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0;
  font-size: 13px; line-height: 1; flex-shrink: 0;
}

/* Talking-head avatar (decisions/0068/0070): live Simli video when
   connected, Vulani's real portrait photo otherwise (decisions/0086).
   Sizing/positioning verified against the real reference
   components (VulaniAvatar.tsx's own SIZES table, Compact.tsx,
   Fullscreen.tsx) rather than guessed -- the first two passes at this were
   guesses (a flat aspect-ratio, then a flat pixel height, then
   object-fit:contain) and each one was wrong for a different shell.
   object-fit is always "cover" in the real component, never "contain". */
#vulani-avatar {
  position: relative; width: 100%; background: #081420;
  overflow: hidden; flex-shrink: 0;
  /* Default/compact: VulaniAvatar's own "compact" size -- width:100%,
     aspect-ratio:16/9. Safe here because compact's panel width is a fixed
     380px (see #vulani-widget.vulani-mode-compact #vulani-panel below),
     unlike fullscreen's full-viewport width, which is what broke the
     first attempt at this. */
  aspect-ratio: 16 / 9;
  border-bottom: 1px solid #1e3a5c;
}
#vulani-avatar-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: none; }
#vulani-avatar-fallback {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: top center;
}
#vulani-chat-card { display: flex; flex-direction: column; flex: 1; min-height: 0; }
#vulani-log { flex: 1; overflow-y: auto; padding: 10px; }
#vulani-empty-state { color: #8aaac8; font-size: .85rem; padding: 8px 0; }
/* Ported from VulaniStatusIndicator.tsx's exact color mapping: text is the
   primary cue (spec §17: "never colour alone"), color is secondary. */
.vulani-status-badge {
  display: inline-flex; align-items: center; margin: 4px 10px; padding: 4px 10px;
  border-radius: 10px; font-size: .72rem; font-weight: 600; line-height: 1;
  min-height: 1.1em;
}
.vulani-status-badge.status-ready { background: rgba(20,166,142,.15); color: #2ea88a; }
.vulani-status-badge.status-thinking { background: rgba(245,166,35,.15); color: #f5a623; }
.vulani-status-badge.status-speaking { background: rgba(66,133,244,.15); color: #6ea3f7; }
.vulani-status-badge.status-error { background: rgba(204,51,51,.15); color: #ff8080; }
.vulani-status-badge.status-disconnected { background: rgba(138,170,200,.15); color: #8aaac8; }
#vulani-error {
  color: #ffaaaa; font-size: .75rem; padding: 0 10px;
  min-height: 1.1em;
}
.vulani-input-row { display: flex; gap: 6px; padding: 8px 10px; }
.vulani-input-row input[type="text"] { flex: 1; }
#vulani-mic-btn { flex: 0 0 auto; }
#vulani-mic-btn.listening { background: #cc3333; color: white; border-color: #cc3333; }
.vulani-disclaimer { color: #8aaac8; font-size: .68rem; padding: 0 10px 10px; line-height: 1.4; }

/* Minimized: only the bubble shows. */
#vulani-widget.vulani-mode-minimized #vulani-bubble { display: flex; align-items: center; justify-content: center; }
#vulani-widget.vulani-mode-minimized #vulani-panel { display: none; }

/* Compact: fixed bottom-right panel, matches the old app's own 380px/80vh. */
#vulani-widget.vulani-mode-compact #vulani-panel {
  display: flex; right: 24px; bottom: 24px; width: 380px; max-height: 80vh;
}

/* Guided (decisions/0070, remedy -- supersedes decisions/0067/0068's own
   "folded into fullscreen" call): docked right-side rail, ported from
   Guided.tsx's real values -- 380px wide, no border radius. Real
   Guided.tsx uses top:52 (its own AppHeader's real height) specifically
   so its nav stays visible above the rail; this rebuild's own #app-header
   measures 56px live (Playwright, not guessed) -- top:0 here silently
   covered it entirely, a real defect found only by being asked directly
   why /chat had no visible navigation. The real component's own "current
   task" box needs activeIssue/currentTask store state this rebuild has no
   equivalent of (no client-side store at all) -- not faked here. The
   avatar uses the real "guided" size (4:3 aspect, vs compact's 16:9). */
#vulani-widget.vulani-mode-guided #vulani-panel {
  display: flex; top: 56px; right: 0; bottom: 0; left: auto; width: 380px; max-height: none; border-radius: 0;
  position: fixed;
}
#vulani-widget.vulani-mode-guided #vulani-avatar { aspect-ratio: 4 / 3; }

/* Fullscreen: ported from Fullscreen.tsx's real structure -- "the avatar
   IS the canvas": avatar fills the panel as a background layer
   (VulaniAvatar's "fill" size: inset:0, no aspect-ratio, object-fit:cover),
   and the chat card floats over it as a glass panel pinned to the bottom
   (bottom:24px, max-height:32vh, matching Fullscreen.tsx's own values)
   rather than sitting below it in normal document flow -- that
   stacking-instead-of-overlaying was the actual bug a real signed-in
   screenshot caught (a giant avatar block pushing the whole chat card out
   of view). top:56px (not 0): real Fullscreen.tsx uses top:52 (its own
   AppHeader height) so its nav stays visible above the takeover -- this
   rebuild's own #app-header measures 56px live; the first pass used top:0,
   fully hiding this module's own nav on /chat with no way back to it
   short of minimizing the widget. Found only by being asked directly. */
#vulani-widget.vulani-mode-fullscreen #vulani-panel {
  display: flex; top: 56px; left: 0; right: 0; bottom: 0; width: auto; max-height: none; border-radius: 0;
  position: fixed;
}
/* decisions/0083: the ambient page has no #app-header of its own (56px
   above assumes this module's own standalone header) -- Portal's REAL
   sticky header is 52px (Portal/app/static/theme.css's own #vs-header),
   and this iframe's transparent background lets it show through the gap,
   same effect the original 56px was going for, against the real number. */
body.vulani-ambient #vulani-widget.vulani-mode-fullscreen #vulani-panel { top: 52px; }
#vulani-widget.vulani-mode-fullscreen #vulani-avatar {
  position: absolute; inset: 0; aspect-ratio: unset; border-bottom: none; z-index: 1;
}
/* Ported from Fullscreen.tsx's own top pill exactly: a small floating
   translucent bar over the video, not the full-width opaque header used
   in every other shell (Compact.tsx's own header is a normal in-flow
   bordered bar -- that part of the base rule was already correct). */
#vulani-widget.vulani-mode-fullscreen .vulani-panel-header {
  position: absolute; top: 14px; left: 16px; right: 16px; z-index: 3;
  padding: 8px 14px; border-bottom: none; border-radius: 14px;
  background: linear-gradient(180deg, rgba(8,12,16,.62) 0%, rgba(8,12,16,.42) 100%);
  border: 1px solid rgba(255,255,255,.08);
  box-shadow: 0 4px 24px rgba(0,0,0,.35);
}
#vulani-widget.vulani-mode-fullscreen #vulani-chat-card {
  position: absolute; left: 50%; transform: translateX(-50%); bottom: 24px;
  width: min(900px, calc(100% - 48px)); max-height: 32vh; z-index: 2;
  background: linear-gradient(180deg, rgba(8,12,16,.10) 0%, rgba(8,12,16,.62) 100%);
  border-radius: 20px; border: 1px solid rgba(255,255,255,.08);
  box-shadow: 0 -4px 32px rgba(0,0,0,.35), 0 12px 48px rgba(0,0,0,.4);
}
/* Ported from Fullscreen.tsx lines 85-97 exactly: when video is off the
   canvas goes black (no avatar to show through), so the chat card expands
   to fill from just below the top pill to the bottom, with a solid
   (non-gradient) background -- found by independent review, not
   self-caught; the first pass had only the video-on sizing. */
#vulani-widget.vulani-video-off.vulani-mode-fullscreen #vulani-chat-card {
  top: 66px; bottom: 24px; max-height: none;
  background: rgba(8,12,16,.72);
}

/* BottomSheet (decisions/0070, remedy, ported from BottomSheet.tsx):
   real breakpoint/heights -- collapsed 96px (fits the drag handle + icon
   row), half 55vh, expanded 92vh. Only takes effect under this media
   query, which is exactly how the real app scopes it (spec §4 State 3 on
   tablet portrait + §7 mobile route) -- above 767px, compact mode's
   already-built floating-panel behaviour is untouched. */
#vulani-sheet-handle { display: none; }
/* decisions/0080: every selector below is scoped to body:not(.vulani-
   ambient) -- a real bug found live, David: "no image voice or
   anything???". This media query keys off the WIDGET'S OWN iframe
   viewport width, not the real browser window's -- Portal's ambient
   overlay (Modules/Vulani's /widget route, decisions/0074) is a
   deliberately narrow 420px-wide box on an ordinary desktop browser, which
   still satisfies max-width:767px and so was silently getting the real
   phone's BottomSheet treatment (avatar hidden below "expanded", which
   nothing on the ambient page ever reaches) even though nothing about the
   user's actual screen is mobile. Standalone/embedded-as-a-tab access on
   a real narrow/mobile browser is unaffected -- vulani-ambient is only
   ever present on /widget. */
@media (max-width: 767px) {
  body:not(.vulani-ambient) #vulani-widget.vulani-mode-compact #vulani-panel {
    left: 0; right: 0; bottom: 0; width: auto; max-height: none;
    border-radius: 16px 16px 0 0; transition: height .35s cubic-bezier(.4,0,.2,1);
  }
  body:not(.vulani-ambient) #vulani-widget.vulani-mode-compact.vulani-sheet-collapsed #vulani-panel { height: 96px; }
  body:not(.vulani-ambient) #vulani-widget.vulani-mode-compact.vulani-sheet-half #vulani-panel { height: 55vh; }
  body:not(.vulani-ambient) #vulani-widget.vulani-mode-compact.vulani-sheet-expanded #vulani-panel { height: 92vh; border-radius: 0; }

  body:not(.vulani-ambient) #vulani-widget.vulani-mode-compact #vulani-sheet-handle {
    display: flex; align-items: center; justify-content: center;
    width: 100%; min-height: 44px; padding: 20px 0; background: none; border: none; cursor: pointer;
  }
  body:not(.vulani-ambient) #vulani-sheet-handle span { width: 48px; height: 4px; background: #5a7a9a; opacity: .6; border-radius: 4px; }

  /* Avatar only in expanded (real component: "Avatar -- at top of expanded view"). */
  body:not(.vulani-ambient) #vulani-widget.vulani-mode-compact.vulani-sheet-collapsed #vulani-avatar,
  body:not(.vulani-ambient) #vulani-widget.vulani-mode-compact.vulani-sheet-half #vulani-avatar { display: none; }
  body:not(.vulani-ambient) #vulani-widget.vulani-mode-compact.vulani-sheet-expanded #vulani-avatar { aspect-ratio: unset; max-height: 32vh; }

  /* Transcript/status visible in half + expanded only, matching the real
     component's (half || expanded) guards. */
  body:not(.vulani-ambient) #vulani-widget.vulani-mode-compact.vulani-sheet-collapsed #vulani-log,
  body:not(.vulani-ambient) #vulani-widget.vulani-mode-compact.vulani-sheet-collapsed #vulani-status {
    display: none;
  }
  body:not(.vulani-ambient) #vulani-widget.vulani-mode-compact.vulani-sheet-collapsed .vulani-disclaimer { display: none; }
}

/* ── RBAC ── */
table.rbac-table { width: 100%; border-collapse: collapse; margin: .6rem 0; font-size: 12px; }
table.rbac-table th, table.rbac-table td {
  border: 1px solid #1e3a5c; padding: 6px 10px; text-align: left;
}
table.rbac-table th { background: #1a3a5c; color: #e8f0f8; }
