/* ============================================================
   SaaS shell — Phase 6a.

   Adds: page-root layout, dashboard / workflow-list / usage cards,
         user pill, dev-user selector, plan badges, route toggles.

   Does NOT touch canvas styles. The canvas + drawer + repeat modal
   keep their existing look on the ``#workflow*`` route.
   ============================================================ */

/* --- Phase 10 Slice 4E-1: route-aware host integration (v6) ------
   Geometry is JS-driven via sidebar.js's layout-sync bridge, which
   writes runtime measurements into CSS custom properties on .app:

     --aw-nav-footprint    page-route grid track width
                           (nav width + 2 × --shell-gap)
     --aw-nav-top          workflow-route nav top, anchored at
                           the canvas-toolbar's top edge so the
                           nav and toolbar visually share a row.
                           Same value for rail and expanded — no
                           jump between states, no state-dependent
                           offset.
     --aw-toolbar-left     workflow-route canvas-toolbar left.
                           Default 12 when the nav is dragged out
                           of the toolbar's row. Otherwise clears
                           the nav and (only when the .wf-side
                           chips are actually expanded — hover /
                           focus / .is-open) the chip width too.
                           Collapsed 32-px chip icons don't
                           reserve space.

   Class toggled on .app by the bridge:
     .has-nav-rail         set while .wf-nav is in rail mode.

   PAGE ROUTES   → nav lives in the grid column. Track width tracks
                   --aw-nav-footprint (i.e. follows manual resize
                   and the rail/expanded toggle).
   WORKFLOW ROUTE → nav is a fixed overlay sharing the toolbar's
                   row. The bridge writes toolbar-left to clear
                   the nav AND any expanded side chips. Dragging
                   the nav out of the toolbar's row collapses
                   toolbar-left back to 12 so the zoom controls
                   stay where they belong.

   Why a JS class instead of CSS :has(): the previous draft used
   ``.app:has(.wf-nav.is-rail)`` to drive rail-state track width.
   ``:has()`` invalidation is conservative — every hover that
   bubbles into .app forces a style recompute up the tree, which
   showed up as flicker on the dashboard system-strip / KPI cards.
   The bridge sets .has-nav-rail via MutationObserver instead.

   Why ``.app { transition: grid-template-columns 0s }``: main.css
   ships a 0.18 s grid-track transition for the old nav-hide
   button. That transition is what amplified every CSS-var write
   into a visible page reflow — the page-root cell would animate
   width on each bridge update, and the dashboard cards inside
   would reflow with it. The bridge already only writes
   --aw-nav-footprint when the value truly changes (rail toggle /
   manual resize), but we still need to neutralise the inherited
   transition so the rare legitimate change is instant rather
   than animated.

   Fallbacks below cover first paint and ResizeObserver-less
   environments. */

/* Kill the inherited grid-template-columns transition from main.css.
   See block comment above for why this is the only safe option. */
.app { transition: grid-template-columns 0s; }

/* Default (page route) — sidebar in the grid. */
.app {
  --nav-width: var(--aw-nav-footprint, calc(240px + var(--shell-gap, 12px) * 2));
}
.app.has-nav-rail {
  --nav-width: var(--aw-nav-footprint, calc(52px + var(--shell-gap, 12px) * 2));
}
.app > .wf-nav {
  grid-area: nav;
  /* Mockup is content-sized; align-self: start prevents grid
     stretch — without this the inner .wf-scroll (flex: 1;
     min-height: 0) would grow into the empty space and produce
     the giant blank card. */
  align-self: start;
  /* Shell gaps: 12px top + 12px left + 12px bottom + 0 right (the
     right gap lives in the grid track via --nav-width's 2×
     shell-gap). Top is 12 — not 8 — so the page-route nav.top
     lands at viewport y=72 (grid row 2 starts at 60, plus 12
     margin), matching what the workflow-route bridge writes via
     --aw-nav-top. Without this match, navigating Dashboard ↔
     Workflow nudged the nav vertically by 4px. */
  margin: var(--shell-gap, 12px) 0 var(--shell-gap, 12px) var(--shell-gap, 12px);
}

/* Workflow route — sidebar overlays the canvas. */
body.route-workflow .app { --nav-width: 0; }
body.route-workflow .app.has-nav-rail { --nav-width: 0; }
body.route-workflow .app > .wf-nav {
  position: fixed;
  top: var(--aw-nav-top, 72px);
  left: var(--shell-gap, 12px);
  margin: 0;
  grid-area: auto;
  align-self: auto;
  z-index: 6;
}

/* Rail visual override — make the collapsed nav match the
   canvas-toolbar / toolbar-group rhythm. The component's default
   rail look is a 52-px glass card with a 16-px radius and a
   heavy drop shadow; in AirWanderer's workflow shell that reads
   as a separate "control class" next to the small zoom-toolbar
   buttons. Matching the toolbar-group tokens (white-ish surface,
   8-px radius, soft shadow, light 4-px padding) makes the rail
   feel like part of the same toolbar row.
   Padding/border-radius/box-shadow/background all win via
   selector specificity; width needs ``!important`` because
   sidebar-nav.css uses ``width: 52px !important`` on rail. */
body.route-workflow .app > .wf-nav.is-rail {
  /* Width is a fixed pixel value (not auto) so the rail
     collapse animation can interpolate it. CSS transitions
     cannot animate to/from ``auto``, which was the cause of
     the visible "width collapses before height" glitch: the
     width snapped to its content size while the height
     transitioned over 0.3s. With an explicit 40px both
     dimensions ride the same curve in sidebar-nav.js's
     toggleRail (width/height/padding/transform all .3s
     cubic-bezier(.4,0,.2,1)). 40 = 30 px collapse button +
     4 px padding each side + a 2 px breath. */
  width: 40px !important;
  padding: 4px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.92);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  border: 1px solid var(--border, rgba(0, 0, 0, 0.08));
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
}

/* Canvas toolbar left is driven by the bridge. Top stays at the
   panels.css default (12 px inside the canvas-area) so the
   toolbar position matches what the rest of the app expects.
   Easing and duration explicitly match the chip width
   transition in sidebar-nav.css:
     .wf-help__box / .wf-motion__box / .wf-limits__box {
       transition: width .42s var(--ease);
     }
   where --ease = cubic-bezier(.32, .72, 0, 1). var(--ease)
   doesn't cascade to .canvas-toolbar (it's defined inside
   .wf-nav), so the curve is hard-coded here. Hard-coding both
   the duration and the curve is what stops the desync the user
   reported — the toolbar now glides on the same timeline as
   the chips, not at the default CSS ``ease`` curve. Slice 4E-5
   fix-pass 4 bumped the chip-box width transition from .26s to
   .42s; this rule follows so the toolbar finishes shifting when
   the chip finishes expanding (Slice 4E-7D fix-pass — user-
   reported "zoom control changes position too early"). */
body.route-workflow .canvas-toolbar {
  left: var(--aw-toolbar-left, 262px);
  transition: left .42s cubic-bezier(.32, .72, 0, 1);
}
/* ROUND 29: while the nav's rail motion runs (the bridge sets .is-nav-railmotion on .app for
   its duration) the toolbar glides on the nav's own .32s, not the chips' .42s, so the two
   arrive together */
body.route-workflow .app.is-nav-railmotion .canvas-toolbar {
  transition: top var(--aw-chrome-dur) var(--aw-chrome-ease),
              left var(--aw-chrome-dur) var(--aw-chrome-ease),
              translate var(--aw-chrome-dur) var(--aw-chrome-ease);
}
/* ROUND 29c: the coordinator's nudge of the nav and the help tile's dodge, written at the
   motion's start for the nav's final box, glide on the same clock */
body.route-workflow .app.is-nav-railmotion > .toolbar-group.toolbar-help {
  transition-duration: var(--aw-chrome-dur);
  transition-timing-function: var(--aw-chrome-ease);
}
body.route-workflow .app.has-nav-rail .canvas-toolbar {
  left: var(--aw-toolbar-left, 76px);
}
/* Slice 4E-7D fix-pass: when the user toggles Reduced motion ON,
   the component adds .wf-nav.is-reduced and the global rule in
   sidebar-nav.css:989 kills every transition inside .wf-nav to
   .001ms. The chips snap instantly, but the canvas toolbar lives
   OUTSIDE .wf-nav, so its .42s transition above keeps animating —
   the user sees the toolbar gliding while the chip has already
   snapped to its final width. Mirror the kill here via :has() so
   the toolbar also moves instantly under reduced motion, keeping
   the toolbar locked to the chip cadence in both directions. */
body.route-workflow:has(.wf-nav.is-reduced) .canvas-toolbar {
  transition: none;
}

/* Small-screen reset — overlay everywhere, no chip overflow. */
@media (max-width: 900px) {
  .app { --nav-width: 0; }
  .app.has-nav-rail { --nav-width: 0; }
  .app > .wf-nav {
    position: fixed;
    top: 52px;
    left: 0;
    margin: 0;
    grid-area: auto;
    align-self: auto;
    z-index: 6;
  }
  body.route-workflow .canvas-toolbar {
    left: var(--aw-toolbar-left, 76px);
  }
}

/* --- Route-aware visibility ----------------------------------- */
/*
   ``body.route-workflow``  -> show canvas + drawer + workflow-only
                               header controls; hide page-root.
   ``body.route-page``      -> hide canvas + drawer; show page-root
                               and route the page inside.
   The defaults below assume "page mode" (page-root visible) so
   refresh-on-#dashboard renders correctly even before the router
   has started.
*/
.page-root {
  grid-column: 2 / span 2;        /* canvas + drawer cells */
  /* Phase 10 next slice — the grid lost its `header header header`
     row when the new workflow top-bar component shipped (the bar
     floats fixed over the canvas instead of consuming a layout
     row). The only row is now the nav/canvas/drawer row; page-root
     spans that single row's canvas + drawer columns. */
  grid-row: 1 / span 1;
  /* Vertical scroll only. Horizontal scroll on page-root was
     letting the user pan the whole dashboard sideways because
     some narrow-viewport content (sys-pip wide tile, activity
     chart min-widths) overflows the cell before the responsive
     breakpoints kick in. Clamping overflow-x prevents that
     window-level pan without affecting any internal scroll
     containers — those still have overflow-x:auto on their own
     elements. */
  overflow-y: auto;
  overflow-x: hidden;
  background: var(--bg);
  padding: 28px clamp(16px, 4vw, 48px) 48px;
  display: none;
}

body.route-page .page-root          { display: block; }
body.route-page .canvas-area        { display: none !important; }
body.route-page .app-drawer         { display: none !important; }
/* ``#btn-show-nav`` was previously force-hidden on page routes
   AND lived inside ``.canvas-area`` — net effect: once a user
   collapsed the sidebar on a page route there was no way back.
   The button now lives outside ``.canvas-area`` and visibility
   is gated solely by ``.app.nav-hidden`` so the collapse is
   always reversible from every route. */

body.route-workflow .page-root      { display: none; }
body.route-workflow .nav-pages      { /* still visible; no override */ }

/* The workflow-name input only makes sense on the canvas route. */
body.route-page .workflow-name-input { visibility: hidden; pointer-events: none; }

/* --- Header: user pill + dev-user selector -------------------- */
.user-pill-host {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: 4px;
}
.user-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: #fff;
  font-size: 12px;
  color: var(--text);
}
.user-pill-email {
  max-width: 180px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.user-pill-error {
  color: var(--error);
  font-style: italic;
}

.plan-badge {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: lowercase;
  background: rgba(67, 145, 109, 0.10);
  color: var(--accent);
  border: 1px solid rgba(67, 145, 109, 0.20);
}
.plan-badge.plan-free    { background: #f1f5f9; color: #475569; border-color: #cbd5e1; }
.plan-badge.plan-premium { background: #eef2ff; color: #4338ca; border-color: #c7d2fe; }
.plan-badge.plan-admin   { background: #fef9c3; color: #854d0e; border-color: #fde68a; }
.plan-badge.plan-custom  { background: #fce7f3; color: #9d174d; border-color: #fbcfe8; }
.plan-badge.plan-test    { background: #f0f9ff; color: #075985; border-color: #bae6fd; }

.dev-user-host { display: flex; align-items: center; }
.dev-user-selector {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  color: var(--text-muted);
}
.dev-user-selector-label {
  text-transform: uppercase;
  letter-spacing: 0.5px;
  font-size: 10px;
  font-weight: 600;
}
.dev-user-select.select {
  font-size: 12px;
  padding: 4px 6px;
  height: 30px;
  max-width: 200px;
}

/* --- Sidebar (Phase 6b polish pass) -------------------------- */
/*
   The sidebar is a vertical stack of four blocks:
     1. .nav-rail   — slim utility row above the CTA (collapse toggle).
     2. .nav-cta    — primary New-workflow button, full width.
     3. .nav-section .nav-pages "Pages"           (always visible).
     4. .nav-section .nav-pages "Tools"           (workflow routes only).
     5. .nav-section .workflow-list "Recent workflows" (workflow routes only).

   Every nav row in every section shares the same visual contract:
     - 32px target height
     - 16px icon at flex: 0 0 16px (no horizontal jitter as labels
       grow/shrink)
     - Hover tint + accent text
     - Active state combines a 3px left accent stripe + soft background
       tint + accent text; the stripe sits inside the row's left
       padding so labels never reflow when the active state changes.

   Section boundaries are drawn with consistent ``label`` top padding
   instead of horizontal ``<hr>`` dividers — cleaner, removes the
   "orphaned line" visual when a section is hidden on a route.
*/

/* --- 1. Utility rail (above the CTA) ------------------------- */
.nav-rail {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  height: 24px;
  margin: 2px 0 6px;
}
/* --- 3. Section + label ------------------------------------- */
.nav-section + .nav-section { margin-top: 6px; }

/* --- 4. Nav items (Pages + Tools — unified contract) -------- */
.nav-pages { display: flex; flex-direction: column; gap: 1px; }

/* --- Page header --------------------------------------------- */
.page {
  max-width: 1200px;
  margin: 0 auto;
  animation: pageIn 0.28s cubic-bezier(0.2, 0.8, 0.2, 1);
}
@keyframes pageIn {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}
.page-header { margin-bottom: 24px; }
.page-title {
  margin: 0 0 4px;
  font-size: 24px;
  font-weight: 600;
  color: var(--accent);
  letter-spacing: 0.2px;
}
.page-subtitle { margin: 0; color: var(--text-muted); font-size: 13px; }

/* --- In-page subtab strip (Phase 6b shell) ------------------- */
/* Horizontal nav strip for in-page sub-routes (#library/files,
   #settings/credentials). Each tab is a regular anchor so deep
   links + middle-click + back-button all behave normally — the
   router picks up the hash change. The active tab is set by the
   route handler from ``params.sub``. */
.page-subtabs {
  display: flex;
  gap: 4px;
  margin-bottom: 20px;
  border-bottom: 1px solid var(--border);
}
.page-subtab {
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-muted);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color 0.12s ease, border-color 0.12s ease;
}
.page-subtab:hover { color: var(--text); }
.page-subtab.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
  font-weight: 600;
}

/* --- Cards --------------------------------------------------- */
/* Phase 10 Slice 4 — calmer card surface.
   The previous repeated 2px top-edge gradient accent on every card
   read as decorative noise across a multi-card page; the rule is
   removed. Cards now share one quiet two-layer green-tinted shadow
   that sits one elevation step below the floating shell. */
.card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 16px;
  box-shadow:
    0 6px 18px rgba(32, 56, 45, 0.045),
    0 1px 2px rgba(32, 56, 45, 0.04);
  position: relative;
  transition: box-shadow 0.18s ease, transform 0.18s ease;
}

.card-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 10px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
}
/* Min-height stops the dashboard / usage grid from "popping" from
   one short loading card into a full multi-card layout — the
   reflow on first paint was jarring at common laptop widths.
   Phase 10 Slice 4 — replaced the italic "Loading…" treatment with
   a small shimmer skeleton (skel-bar ghost shapes). */
.card-loading {
  min-height: 96px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 18px;
}
.skel-bar {
  height: 12px;
  border-radius: 4px;
  background: linear-gradient(
    90deg,
    rgba(32, 56, 45, 0.05) 0%,
    rgba(32, 56, 45, 0.10) 50%,
    rgba(32, 56, 45, 0.05) 100%
  );
  background-size: 200% 100%;
  animation: skel-shimmer 1.4s ease-in-out infinite;
}
.skel-bar-lg { width: 60%; }
.skel-bar-md { width: 42%; }
.skel-bar-sm { width: 28%; }
@keyframes skel-shimmer {
  0%   { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}
/* When the loading card is the only child of a 2-col grid (initial
   render before the cards land), span both columns so the empty
   right-hand cell doesn't look like a broken layout. */
.dashboard-grid > .card-loading:only-child,
.usage-grid     > .card-loading:only-child { grid-column: 1 / -1; }

.card-error   { border-color: rgba(176, 72, 72, 0.28); }

/* ============================================================
   DASHBOARD CSS RELOCATED.
   Phase 10 Slice 4A's dashboard styles (~2 180 lines: page-dashboard
   scope tokens, system strip, KPI strip, cockpit, secondary row,
   work row, modal backdrop + shell + summary + chart-frame +
   breakdown, entrance animations, responsive breakpoints) used to
   live here. They were extracted into a dedicated bundle on
   2026-05-15:

       ai-workflow-builder/static/css/dashboard.css

   index.html must link saas-shell.css BEFORE dashboard.css so:
     - The base .page-header / .card / .card-title rules above
       cascade BEFORE the .page-dashboard X overrides.
     - The base .modal-backdrop rule from main.css cascades BEFORE
       dashboard.css augments it with the modal-shell + sub-component
       child rules.

   Touching this gap with another rule risks re-introducing the
   "dashboard styles bleed into Usage / Workflow list" collisions
   that the scope split fixed. If you need to share something with
   the dashboard, factor it into the .card / .page-header / generic
   layout block ABOVE this comment, not below it.
   ============================================================ */


/* --- Dashboard + Usage grid (deterministic 2-col layout) ----- */
/* ``auto-fit minmax(...)`` produced uneven rows at common laptop
   widths (3 cols at 1200px, but cards span 2/2/1/1/2/2 leaving
   trailing empty cells). A fixed 2-col grid keeps the User/Limits
   row and the Actions/Storage row aligned and stretches cards in
   the same row to the same height — natural CSS-grid behavior. */
.dashboard-grid,
.usage-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  align-items: stretch;
}
/* Phase 10 Slice 4 removed the per-card span helpers
   (.card-user / .card-limits / .card-actions / .card-storage /
   .card-recent) — the new dashboard sections (.cmd-band /
   .pulse-card / .dashboard-main-row / .account-card) lay out
   themselves via .page-dashboard .dashboard-grid (flex column).
   The shared .dashboard-grid 2-col rule still applies to .usage-grid. */

@media (max-width: 900px) {
  .dashboard-grid,
  .usage-grid { grid-template-columns: 1fr; }
}

/* --- Generic meta-row helpers (used outside dashboard) ------- */
/* Phase 10 Slice 4 — the dashboard-specific .user-card-* rules
   were removed; the new Account & plan card uses .account-* classes
   defined above. The .meta-label / .meta-value family below stays
   for other views that may use it. */
.meta-label {
  color: var(--text-muted);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  white-space: nowrap;
  flex-shrink: 0;
}
.meta-value {
  color: var(--text);
  font-weight: 500;
  font-size: 13px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex: 1 1 auto;
}
/* Render ID-shaped values (project_id, user_id, run_id...) in a
   monospace face so they read as identifiers, not free text.
   Pairs with the ellipsis rule above. */
.meta-value-mono {
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace);
  font-size: 12px;
}

.limits-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 8px 12px;
}
.limits-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px 0;
}
.feature-tick.on   { color: var(--accent-2); font-weight: 700; }
.feature-tick.off  { color: var(--text-muted); }

.feature-row {
  display: grid;
  grid-template-columns: 24px minmax(0, 200px) minmax(0, 1fr);
  align-items: center;
  gap: 6px 10px;
  padding: 4px 0;
  font-size: 13px;
}
.feature-row .feature-name { color: var(--text); }
.feature-row .feature-hint {
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.upgrade-callout {
  margin-top: 12px;
  padding: 10px 12px;
  background: #fef9c3;
  border: 1px solid #fde68a;
  border-radius: 8px;
  color: #854d0e;
  font-size: 12px;
  line-height: 1.5;
}

.run-status {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.4px;
  background: var(--st-not-started);
  color: #fff;
}
.run-status-running    { background: var(--st-running); }
.run-status-paused     { background: var(--st-waiting); }
.run-status-completed  { background: var(--st-completed); }
.run-status-failed     { background: var(--st-failed); }
.run-status-stopped    { background: var(--st-stopped); }
.run-status-needs_review { background: var(--st-needs-review); }
.run-status-skipped    { background: var(--st-skipped); }

/* --- Workflow list page -------------------------------------- */
.toolbar-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}
.toolbar-row .input { min-width: 240px; flex: 1 1 240px; max-width: 360px; }
.toolbar-row .inline-label { display: inline-flex; align-items: center; gap: 6px; }
.toolbar-row .inline-label span { font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; }
.toolbar-spacer { flex: 1 1 auto; }

.card-table { padding: 0; overflow: hidden; }
.wf-table-host { padding: 0; }
.wf-table-host .empty-inline,
.wf-table-host .exec-banner { padding: 24px; }

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.data-table thead th {
  text-align: left;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
  font-weight: 600;
  padding: 12px 16px;
  background: #f6f8f7;
  border-bottom: 1px solid var(--border);
}
.data-table tbody td {
  padding: 10px 16px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.data-table tbody tr:last-child td { border-bottom: 0; }
.data-table tbody tr.row-clickable { cursor: pointer; transition: background 0.12s ease; }
.data-table tbody tr.row-clickable:hover { background: rgba(67, 145, 109, 0.06); }
.data-table .num         { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.data-table .name-col    { font-weight: 500; color: var(--text); }
/* Actions header stays a normal table-cell so its width is part of
   the column track — applying ``display: flex`` to the <th> would
   pop it out of the table layout and make the header drift from the
   body cells beneath it (the bug that produced the "buttons hang
   outside the header" reports). Only body cells become flex. */
.data-table thead th.actions-col {
  text-align: right;
}
.data-table tbody td.actions-col {
  text-align: right;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: flex-end;
  align-items: center;
  min-height: 32px;
}
.data-table.compact td   { padding: 6px 12px; }
.data-table.compact th   { padding: 8px 12px; }

.empty-inline {
  text-align: center;
  padding: 24px;
  color: var(--text-muted);
}
.empty-inline h3 { color: var(--text); }
.empty-inline p  { margin: 0 0 8px; }

/* --- Usage page ---------------------------------------------- */
/* Activity / Plan / Premium-features cards are full-width rows;
   the by-provider and by-model breakdown tables sit side-by-side
   in the row between them. */
.usage-grid .card-totals,
.usage-grid .card-plan,
.usage-grid .card-features {
  grid-column: 1 / -1;
}
@media (max-width: 900px) {
  .usage-grid .card-totals,
  .usage-grid .card-plan,
  .usage-grid .card-features { grid-column: 1; }
}

/* Token pricing card (owner round 11, report 6) — a full-width row
   between the plan card and the breakdown tables: the user's own
   per-model prices in USD per 1M tokens, editable in place. */
.usage-grid .card-pricing { grid-column: 1 / -1; }
@media (max-width: 900px) {
  .usage-grid .card-pricing { grid-column: 1; }
}
.pricing-intro {
  margin: -2px 0 10px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--text-muted);
}
.pricing-intro b { color: var(--text); font-weight: 600; }
.pricing-table tbody td.num { padding-top: 4px; padding-bottom: 4px; }
.pricing-table .input.pricing-price {
  width: 108px;
  padding: 5px 8px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.pricing-table .input.pricing-price::placeholder { color: var(--text-muted); }
.pricing-table .pricing-remove { padding: 2px 8px; line-height: 1; }
.pricing-table tr.pricing-empty td { padding: 14px 12px; }
.pricing-add,
.pricing-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.pricing-add { margin-top: 10px; }
.pricing-actions { margin-top: 12px; }
.pricing-add .select { width: auto; padding-right: 26px; }
.pricing-add .input { width: 260px; max-width: 100%; }
.pricing-status { font-size: 12px; }
.pricing-status.is-error { color: #b04848; }
.pricing-status.is-ok { color: var(--accent); }

/* By-provider / by-model breakdown tables.
   The earlier ``table-layout: fixed`` + ``width: auto`` attempt
   produced the "PROVIDER MOLEVENTS …" header overlap reported in
   the smoke screenshot: in fixed layout, ``width: auto`` on a
   column is undefined behavior — Chrome collapsed the Model
   column to ~0px and the header text bled into the next cell.
   This pass drops fixed-layout entirely and relies on the
   browser's auto sizing, capping potentially-long text columns
   with ``max-width`` + ellipsis instead. ``.usage-table-wrap``
   is the scroll safety-net for the rare case a future model
   name still exceeds the cap. */
.usage-grid .card { min-width: 0; }
.usage-table-wrap {
  overflow-x: auto;
  max-width: 100%;
  margin: 0 -4px;
}
.usage-table { width: 100%; }
.usage-table thead th { text-transform: uppercase; letter-spacing: 0.4px; }
/* Cap and truncate text-heavy cells (Provider, Model). Numeric
   columns keep auto-sizing so amounts like "$0.0001" stay legible. */
.usage-table tbody td.cell-truncate {
  max-width: 220px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.usage-table tbody td.cell-mono {
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace);
  font-size: 12px;
}
/* Inline mini bar chart inside the By-Model card. Each row gets
   a ``<div class="usage-bar">`` whose width tracks the share of
   total tokens used by that model. Read-only visual — no JS, no
   chart library, just CSS. */
.usage-bar {
  display: block;
  height: 4px;
  margin-top: 4px;
  background: rgba(67, 145, 109, 0.10);
  border-radius: 2px;
  position: relative;
  overflow: hidden;
}
.usage-bar::after {
  content: '';
  display: block;
  height: 100%;
  width: var(--usage-share, 0%);
  background: linear-gradient(90deg, var(--accent), var(--accent-2, var(--accent)));
  border-radius: 2px;
  transition: width 0.25s ease;
}

/* --- Library tabs (Phase 6b slice 3) ------------------------- */
/* Files + Artifacts views share these classes. Bundles slot stays
   on the slice-4 placeholder. ``data-table`` + ``actions-col`` are
   reused from the existing workflow-list styles. */
.lib-card     { padding: 0; }
.lib-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.lib-toolbar-info { color: var(--text-muted); font-size: 12px; flex: 1 1 auto; }
.lib-table-host { padding: 0 16px 16px; }

/* ``table-layout: fixed`` lets us define per-column widths and keeps
   the layout stable across row content. Without it the browser
   redistributes column widths as rows load, which produced the
   "table feels jumpy" effect the user flagged. The filename column
   absorbs the remaining slack via ``width: auto`` and ellipses
   inside. */
.lib-table { table-layout: fixed; width: 100%; }
.lib-table thead th { text-transform: uppercase; letter-spacing: 0.4px; }

/* Files table column widths (5 columns).
   File | Workflow | Size | Retention | Actions */
.lib-table-files col,
.lib-table-files thead th:nth-child(1),
.lib-table-files tbody td:nth-child(1) { width: auto; }
.lib-table-files thead th:nth-child(2),
.lib-table-files tbody td:nth-child(2) { width: 18%; }
.lib-table-files thead th:nth-child(3),
.lib-table-files tbody td:nth-child(3) { width: 80px; }
.lib-table-files thead th:nth-child(4),
.lib-table-files tbody td:nth-child(4) { width: 30%; }
.lib-table-files thead th:nth-child(5),
.lib-table-files tbody td:nth-child(5) { width: 220px; }

/* Artifacts table column widths (7 columns).
   Artifact | Type | Workflow | Run/Block | Size | Retention | Actions */
.lib-table-artifacts thead th:nth-child(1),
.lib-table-artifacts tbody td:nth-child(1) { width: auto; }
.lib-table-artifacts thead th:nth-child(2),
.lib-table-artifacts tbody td:nth-child(2) { width: 90px; }
.lib-table-artifacts thead th:nth-child(3),
.lib-table-artifacts tbody td:nth-child(3) { width: 14%; }
.lib-table-artifacts thead th:nth-child(4),
.lib-table-artifacts tbody td:nth-child(4) { width: 12%; }
.lib-table-artifacts thead th:nth-child(5),
.lib-table-artifacts tbody td:nth-child(5) { width: 80px; }
.lib-table-artifacts thead th:nth-child(6),
.lib-table-artifacts tbody td:nth-child(6) { width: 22%; }
.lib-table-artifacts thead th:nth-child(7),
.lib-table-artifacts tbody td:nth-child(7) { width: 170px; }

/* Filename truncates inside its cell. ``min-width: 0`` lets the
   ellipsis kick in even though the cell is part of a fixed-layout
   table — without it the cell width is honored but the inner
   content can still overflow. */
.lib-filename {
  font-weight: 500;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.lib-hint {
  color: var(--text-muted);
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.lib-link {
  color: var(--accent-2);
  text-decoration: none;
  display: inline-block;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: bottom;
}
.lib-link:hover { text-decoration: underline; }
.lib-runref {
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace);
  font-size: 12px;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lib-btn-danger { color: #b04848; }

/* Retention + pin badge cluster. The flex wrapper means the badges
   wrap as a group with even row height; bare inline-block siblings
   produced uneven rows when individual badges broke onto a new line. */
.lib-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
}
.lib-badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 500;
  line-height: 1.4;
  border: 1px solid transparent;
  background: var(--bg-card);
  color: var(--text-muted);
  white-space: nowrap;
}
.lib-badge-active        { color: #1d6b3a; background: rgba(67, 145, 109, 0.10); border-color: rgba(67, 145, 109, 0.30); }
.lib-badge-expiring,
.lib-badge-expiring_soon { color: #7c2d12; background: rgba(255, 167, 38, 0.12); border-color: rgba(255, 167, 38, 0.32); }
.lib-badge-expired       { color: #991b1b; background: rgba(176, 72, 72, 0.12); border-color: rgba(176, 72, 72, 0.32); }
.lib-badge-deleted,
.lib-badge-purged        { color: #6b7280; background: rgba(107, 114, 128, 0.10); border-color: rgba(107, 114, 128, 0.28); text-decoration: line-through; }
.lib-badge-pinned        { color: var(--accent); background: rgba(67, 145, 109, 0.10); border-color: rgba(67, 145, 109, 0.30); }
.lib-badge-type          { color: var(--text); background: rgba(67, 145, 109, 0.06); border-color: var(--border); }

.lib-pagination {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 0 4px;
  justify-content: flex-end;
  flex-wrap: wrap;
}
.lib-pagination .lib-hint { flex: 1 1 auto; }

/* At narrow widths shrink the action column on the artifacts table
   so the filename column keeps some breathing room. The Files table
   only has a Delete button as the wide-friendly extra, so its
   action column is already on the small side. */
@media (max-width: 1100px) {
  .lib-table-artifacts thead th:nth-child(3),
  .lib-table-artifacts tbody td:nth-child(3),
  .lib-table-artifacts thead th:nth-child(4),
  .lib-table-artifacts tbody td:nth-child(4) { width: 100px; }
}

/* Bundles table column widths (7 columns).
   Bundle | Kind | Source | Size | Status | Expires | Actions */
.lib-table-bundles thead th:nth-child(1),
.lib-table-bundles tbody td:nth-child(1) { width: auto; }
.lib-table-bundles thead th:nth-child(2),
.lib-table-bundles tbody td:nth-child(2) { width: 96px; }
.lib-table-bundles thead th:nth-child(3),
.lib-table-bundles tbody td:nth-child(3) { width: 18%; }
.lib-table-bundles thead th:nth-child(4),
.lib-table-bundles tbody td:nth-child(4) { width: 80px; }
.lib-table-bundles thead th:nth-child(5),
.lib-table-bundles tbody td:nth-child(5) { width: 110px; }
.lib-table-bundles thead th:nth-child(6),
.lib-table-bundles tbody td:nth-child(6) { width: 130px; }
.lib-table-bundles thead th:nth-child(7),
.lib-table-bundles tbody td:nth-child(7) { width: 180px; }

/* Bundle-specific badges: kind (workflow/run/bundle) + bundle
   status states that aren't in the file/artifact palette
   (``creating`` while the export is being persisted; ``failed``
   if the persist step errored). Reuses the active/expired/
   deleted/purged tokens from the shared library palette. */
.lib-badge-workflow      { color: var(--accent); background: rgba(67, 145, 109, 0.10); border-color: rgba(67, 145, 109, 0.30); }
.lib-badge-run           { color: #4338ca; background: #eef2ff; border-color: #c7d2fe; }
.lib-badge-bundle        { color: var(--text-muted); background: var(--bg-card); border-color: var(--border); }
.lib-badge-creating      { color: #075985; background: #f0f9ff; border-color: #bae6fd; }
.lib-badge-failed        { color: #991b1b; background: rgba(176, 72, 72, 0.12); border-color: rgba(176, 72, 72, 0.32); }

/* Import success / error banner inside the bundles toolbar block. */
.exec-banner.success {
  background: rgba(67, 145, 109, 0.08);
  border-color: rgba(67, 145, 109, 0.30);
  color: var(--accent);
}
.lib-banner {
  margin: 0 16px 12px;
  padding: 10px 12px;
  border-radius: 8px;
  font-size: 13px;
}
.lib-bun-file { display: none; }

/* --- Settings / Credentials (Phase 6b slice 5) --------------- */
/* Two stacked cards: existing credentials table on top, an Add
   credential form below. Reuses ``.data-table`` for the list, the
   shared ``.lib-badge`` palette for enabled/disabled state, and a
   small bespoke ``.cred-form`` grid for the form so labels +
   inputs align without dragging in a heavier form framework. */
.cred-card + .cred-card { margin-top: 16px; }

/* Credentials table column widths (7 columns).
   Provider | Label | Key | Default model | Enabled | Added | Actions.
   Long model names + long labels both got the same overflow that
   plagued the library tables before slice 3's fixed-layout pass;
   the same treatment applies here. */
.cred-table {
  table-layout: fixed;
  width: 100%;
}
.cred-table thead th { text-transform: uppercase; letter-spacing: 0.4px; }
.cred-table thead th:nth-child(1),
.cred-table tbody td:nth-child(1) { width: 110px; }
.cred-table thead th:nth-child(2),
.cred-table tbody td:nth-child(2) { width: auto; }
.cred-table thead th:nth-child(3),
.cred-table tbody td:nth-child(3) { width: 150px; }
.cred-table thead th:nth-child(4),
.cred-table tbody td:nth-child(4) { width: 18%; }
.cred-table thead th:nth-child(5),
.cred-table tbody td:nth-child(5) { width: 90px; }
.cred-table thead th:nth-child(6),
.cred-table tbody td:nth-child(6) { width: 110px; }
.cred-table thead th:nth-child(7),
.cred-table tbody td:nth-child(7) { width: 170px; }
/* Default-model + label cells truncate when the value is long
   instead of pushing the Actions column off-screen. */
.cred-table tbody td:nth-child(2),
.cred-table tbody td:nth-child(4) {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cred-mask {
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace);
  font-size: 12px;
  background: rgba(67, 145, 109, 0.06);
  padding: 1px 8px;
  border-radius: 4px;
  color: var(--text);
}
.cred-default-tag {
  color: var(--text-muted);
  font-style: italic;
  font-size: 12px;
}

.cred-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 12px;
}
.cred-form-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}
@media (max-width: 720px) {
  .cred-form-row { grid-template-columns: 1fr; }
}
.cred-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.cred-field-wide { grid-column: 1 / -1; }
.cred-field-enabled {
  flex-direction: row;
  align-items: center;
  gap: 6px;
  align-self: end;
  font-size: 13px;
  color: var(--text);
}
.cred-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
}
.cred-optional {
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  color: var(--text-muted);
}
.cred-form .input,
.cred-form .select {
  font-size: 13px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fff;
  color: var(--text);
  width: 100%;
}
.cred-form .input:focus,
.cred-form .select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px rgba(67, 145, 109, 0.20);
}
.cred-form-actions { display: flex; justify-content: flex-end; }
.cred-form-error { font-size: 13px; padding: 10px 12px; }

/* --- Admin shell (Phase 6c slice 1) ------------------------- */
/* Most admin styling lives inside slice 2–5 view modules; this
   block is the small shared layer the shell itself uses:
   ``.admin-unavailable`` for the non-admin landing card. */
.admin-unavailable {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 14px;
  padding: 24px;
}
.admin-unavailable .hint {
  font-size: 13.5px;
  line-height: 1.55;
  max-width: 520px;
  color: var(--text-muted);
}

/* --- Admin → Users (Phase 6c slice 2) ----------------------- */
/* Two-pane layout: filterable table on the left, sticky read-only
   detail panel on the right. Below 1100px the panel stacks above
   the table so the small-screen flow stays linear. */
.admin-users-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 18px;
  align-items: start;
}
@media (max-width: 1100px) {
  .admin-users-grid { grid-template-columns: minmax(0, 1fr); }
  .admin-detail-panel { position: static !important; max-height: none !important; }
}

.admin-users-main { min-width: 0; }

/* Toolbar: search input, two select filters, two chip toggles,
   a flex-spacer info label, and the refresh button. Wraps on
   narrow widths. */
.admin-users-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.admin-users-search { min-width: 220px; flex: 1 1 220px; max-width: 320px; }
.admin-users-filter {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.admin-users-filter > span {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
  font-weight: 600;
}
.admin-users-info {
  flex: 1 1 auto;
  text-align: right;
  font-size: 12px;
  color: var(--text-muted);
  min-width: 80px;
}
/* Active-filter state for the toolbar chips. The base
   ``.lib-chip.on`` rule is a soft 10% accent tint that's easy to
   miss; in the admin toolbar we want the active state to be
   unambiguous since the filtered count can look identical to the
   unfiltered count (e.g. when every user is a test user). Stronger
   contrast + an explicit check glyph + a tiny "active" outline
   ring make the state obvious at a glance. */
.admin-users-toolbar .lib-chip.on {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  box-shadow: 0 0 0 2px rgba(67, 145, 109, 0.22);
}
.admin-users-toolbar .lib-chip.on::before {
  content: '✓ ';
  font-size: 11px;
  margin-right: 2px;
}
.admin-users-toolbar .lib-chip { user-select: none; }

/* When ANY toolbar filter is active, prefix the info text with
   a small accent dot so admins can tell at a glance that the
   table is filtered — even when the filtered count happens
   to equal the unfiltered count. */
.admin-users-info.filtered {
  color: var(--accent);
  font-weight: 600;
}
.admin-users-info.filtered::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  margin-right: 6px;
  vertical-align: middle;
}

/* Users table layout.
   Auto layout + per-cell ``max-width`` + ellipsis on the User cell.
   The whole table sits inside a horizontal-scroll wrapper so when
   the table's natural min-width exceeds the card (e.g. on narrower
   laptops with the sticky detail panel taking 360px), the table
   scrolls horizontally inside the card instead of clipping the
   right-side columns. */
.admin-users-card { padding: 0; }
.admin-users-card .lib-pagination { padding: 12px 16px; }
.admin-users-table-scroll {
  overflow-x: auto;
  max-width: 100%;
}
.admin-users-table-scroll::-webkit-scrollbar { height: 8px; }
.admin-users-table-scroll::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.10); border-radius: 4px; }
.admin-users-table { width: 100%; min-width: 720px; }
.admin-users-table thead th { text-transform: uppercase; letter-spacing: 0.4px; white-space: nowrap; }
/* Per-column widths used as hints in auto layout. The User
   column has no explicit width so the table gives it whatever
   space is left; ``max-width`` + ellipsis on the inner
   ``.user-email`` clips long emails. */
.admin-users-table thead th:nth-child(2),
.admin-users-table tbody td:nth-child(2) { width: 80px; }
.admin-users-table thead th:nth-child(3),
.admin-users-table tbody td:nth-child(3) { width: 150px; }
.admin-users-table thead th:nth-child(4),
.admin-users-table tbody td:nth-child(4) { width: 90px; }
.admin-users-table thead th:nth-child(5),
.admin-users-table tbody td:nth-child(5) { width: 90px; white-space: nowrap; }
.admin-users-table thead th:nth-child(6),
.admin-users-table tbody td:nth-child(6) { width: 80px; white-space: nowrap; }
.admin-users-table thead th:nth-child(7),
.admin-users-table tbody td:nth-child(7) { width: 110px; white-space: nowrap; }
.admin-users-table thead th:nth-child(8),
.admin-users-table tbody td:nth-child(8) { width: 100px; white-space: nowrap; }
/* Cap the User cell so a long email can't expand the whole
   column past its share of the table. */
.admin-users-table tbody td:first-child {
  max-width: 280px;
}
.admin-users-table .user-email {
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.admin-users-table tbody tr {
  cursor: pointer;
  transition: background 0.12s ease;
}
.admin-users-table tbody tr:hover { background: rgba(67, 145, 109, 0.05); }
.admin-users-table tbody tr.admin-row-selected {
  background: rgba(67, 145, 109, 0.10);
  box-shadow: inset 3px 0 0 var(--accent);
}
.user-email {
  font-weight: 500;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* User flag chips (admin / test / internal). Three muted pills
   that complement the existing ``.plan-pill`` + ``.lib-badge-*``
   palette. */
.user-flags { display: inline-flex; gap: 4px; flex-wrap: wrap; }
.user-flag {
  display: inline-flex;
  align-items: center;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  border: 1px solid transparent;
  white-space: nowrap;
}
.user-flag-admin    { color: #854d0e; background: #fef9c3; border-color: #fde68a; }
.user-flag-test     { color: #075985; background: #f0f9ff; border-color: #bae6fd; }
.user-flag-internal { color: #4338ca; background: #eef2ff; border-color: #c7d2fe; }

/* Detail panel. Sticky on wide screens; pinned 28px from the top
   of the scrolling page-root so it clears the page header without
   needing JS measurement. The panel itself caps its own height
   and scrolls internally when the user has a lot of effective
   limits configured. */
.admin-detail-panel {
  position: sticky;
  top: 28px;
  max-height: calc(100vh - 80px);
  overflow-y: auto;
  overflow-x: hidden;          /* no horizontal scrollbar inside the panel */
  min-width: 0;                /* allow the grid track to shrink content */
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-soft);
}
.admin-detail-panel::-webkit-scrollbar { width: 6px; }
.admin-detail-panel::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.10); border-radius: 3px; }

.admin-detail-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 6px;
  padding: 36px 24px;
  color: var(--text-muted);
}
.admin-detail-empty h3 {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
}
.admin-detail-empty p { margin: 0; font-size: 13px; max-width: 280px; line-height: 1.5; }

.admin-detail { padding: 16px 18px; }
.admin-detail-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}
.admin-detail-title { min-width: 0; flex: 1 1 auto; }
.admin-detail-email {
  font-weight: 600;
  color: var(--text);
  font-size: 14px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.admin-detail-tags { display: flex; gap: 6px; flex-wrap: wrap; flex-shrink: 0; }
.admin-detail-row { padding: 10px 0; border-bottom: 1px dashed var(--border); }
.admin-detail-section {
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
}
.admin-detail-section:last-child { border-bottom: 0; }
.admin-detail-section .card-title { margin-bottom: 8px; }
.admin-detail-meta { grid-template-columns: 1fr; gap: 6px 0; }
.admin-detail-meta .meta-label { width: 110px; }
.admin-detail-activity { grid-template-columns: repeat(3, 1fr); }

/* Effective-limits tiles inside the detail panel. The shared
   ``.limits-grid`` rule uses ``auto-fit minmax(140px, 1fr)``,
   which at the panel's ~324px content width gives 2 columns —
   but the tile content (especially the long snake_case keys we
   used to render verbatim) could overflow the cell and bleed
   into the neighbour. ``min-width: 0`` on the tile lets the
   ellipsis on ``.meta-label`` actually trigger; the JS
   ``humanizeLimitKey`` step also shrinks the worst offenders
   to readable English. */
.admin-detail .limits-grid { gap: 8px 12px; }
.admin-detail .limits-item { min-width: 0; }
.admin-detail .limits-item .meta-label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  letter-spacing: 0.3px;
}
.admin-detail .limits-item .meta-value {
  font-variant-numeric: tabular-nums;
  font-size: 14px;
  color: var(--text);
  font-weight: 600;
}

.admin-detail-foot {
  padding-top: 12px;
  font-size: 11px;
  color: var(--text-muted);
}
.admin-detail-foot .lib-hint { font-size: 11.5px; line-height: 1.5; }

/* --- Admin user actions (Phase 6c slice 3) ---------------------- */
/* Five action rows stacked inside the detail panel's Actions
   section. Each row has: a small uppercase label on the left, a
   controls row (input + save button) below, an optional hint, and
   an optional inline success/error banner. The danger row gets a
   thin top border + warm hint copy so accidental clicks are
   harder. */
.admin-actions { padding-bottom: 8px; }
.admin-action {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px 0;
  border-bottom: 1px dashed var(--border);
}
.admin-action:last-child { border-bottom: none; }
.admin-action-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
}
.admin-action-controls {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.admin-action-select,
.admin-action-input {
  height: 30px;
  font-size: 13px;
  padding: 4px 8px;
  flex: 0 1 auto;
  min-width: 140px;
}
.admin-action-hint {
  font-size: 11.5px;
  color: var(--text-muted);
  line-height: 1.5;
  max-width: 100%;
}
.admin-action-hint code {
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace);
  font-size: 11px;
  padding: 1px 5px;
  border-radius: 4px;
  background: rgba(67, 145, 109, 0.08);
  color: var(--accent);
  border: 1px solid rgba(67, 145, 109, 0.18);
}
.admin-action-hint-inline {
  margin-left: 4px;
  flex: 1 1 auto;
  min-width: 0;
}
.admin-action-msg {
  margin-top: 2px;
  padding: 6px 10px;
  font-size: 12px;
  border-radius: 6px;
  line-height: 1.4;
}

.admin-action-danger {
  margin-top: 6px;
  padding-top: 14px;
  border-top: 2px solid rgba(176, 72, 72, 0.18);
}
.admin-action-danger .admin-action-label { color: #991b1b; }
.admin-action-hint-warn {
  color: #7c2d12;
  background: rgba(255, 167, 38, 0.10);
  border: 1px solid rgba(255, 167, 38, 0.32);
  border-radius: 6px;
  padding: 6px 10px;
}

/* Inline JSON limits editor. Lives inside the Limits action row
   when ``state.limitsExpanded`` is true. The textarea uses the
   monospace stack so JSON is readable. The action button row is
   visually attached underneath the textarea. */
.admin-limits-editor {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 8px;
  padding: 12px;
  background: var(--bg-3, #f4f8f6);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.admin-limits-textarea {
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  height: auto;
  min-height: 160px;
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace);
  font-size: 12.5px;
  line-height: 1.5;
  resize: vertical;
  padding: 8px 10px;
  overflow-x: auto;
}
.admin-limits-actions {
  margin-top: 2px;
}

/* Limit-override chip strip inside the JSON editor. Each chip
   inserts a known canonical key into the textarea, seeded with
   the user's current effective value (or a sane default). Chips
   reuse the ``.lib-chip`` base; the strip wraps so long key
   names don't push the editor sideways. */
.admin-limits-chip-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 4px;
}
.admin-limits-chip-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
}
.admin-limits-chip-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.admin-limits-chip {
  padding: 3px 9px;
  font-size: 11px;
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace);
  white-space: nowrap;
}
.admin-limits-chip:hover {
  color: var(--accent);
  border-color: var(--accent-3, var(--accent));
}

/* --- Session unavailable screen (Phase 6c slice 3) ------------ */
/* Replaces the entire page-root + hides the sidebar Pages nav
   when ``Session.init()`` returns 403 (disabled / purged user).
   The recovery buttons (clear-override / switch-email) are the
   only reachable controls outside the dev-user selector itself. */
body.session-unavailable .nav-section { display: none !important; }

.page-session-unavailable {
  max-width: 560px;
  margin: 80px auto 32px;
}
.session-unavailable-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 32px 36px;
  text-align: left;
}
.session-unavailable-title {
  margin: 0;
  font-family: var(--font-display, var(--font-sans));
  font-size: 22px;
  font-weight: 600;
  color: var(--error, #b04848);
  letter-spacing: 0.2px;
}
.session-unavailable-message {
  margin: 0;
  font-size: 14px;
  line-height: 1.55;
  color: var(--text);
}
.session-unavailable-meta {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 12px;
  background: rgba(0, 0, 0, 0.03);
  border-radius: 8px;
}
.session-unavailable-meta .meta-label {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
}
.session-unavailable-email {
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace);
  font-size: 13px;
  color: var(--text);
  word-break: break-all;
}
.session-unavailable-detail {
  font-size: 12px;
  color: var(--text-muted);
}
.session-unavailable-detail summary {
  cursor: pointer;
  padding: 4px 0;
}
.session-unavailable-detail code {
  display: block;
  padding: 8px 10px;
  margin-top: 6px;
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace);
  font-size: 11.5px;
  color: var(--text);
  background: rgba(0, 0, 0, 0.04);
  border-radius: 6px;
  word-break: break-word;
}
.session-unavailable-actions {
  display: flex;
  gap: 10px;
  margin-top: 6px;
  flex-wrap: wrap;
}

/* Inspector → Environment panel — link out to the new
   #settings/credentials page. Scoped to the new
   ``env-section-title`` class so we don't perturb other
   ``.section-title`` instances inside the drawer. */
.env-section-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.env-manage-link {
  font-size: 11px;
  font-weight: 500;
  color: var(--accent-2);
  text-decoration: none;
  text-transform: none;
  letter-spacing: 0;
}
.env-manage-link:hover { text-decoration: underline; }

/* --- Hard-purge modal (Phase 6c slice 4) ---------------------- */
/* Typed-confirm dialog launched from the Users detail panel's
   Actions → Hard purge row. The scrim covers the entire viewport;
   click-outside is intentionally NOT a dismissal so the dangerous
   action stays explicit (Cancel button + Escape only).  Sits on
   the same z-layer as the chat-mode backdrop. */
.purge-modal-scrim {
  position: fixed;
  inset: 0;
  background: rgba(20, 30, 25, 0.45);
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.purge-modal {
  position: relative;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
  width: min(560px, 100%);
  max-height: 90vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  border: 1px solid rgba(176, 72, 72, 0.32);
}
.purge-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px;
  border-bottom: 1px solid var(--border);
  background: rgba(176, 72, 72, 0.06);
  border-top-left-radius: 12px;
  border-top-right-radius: 12px;
}
.purge-modal-head h2 {
  margin: 0;
  font-size: 17px;
  color: #991b1b;
  font-weight: 600;
}
.purge-modal-close {
  background: none;
  border: 0;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  color: var(--text-muted);
  padding: 2px 6px;
  border-radius: 6px;
}
.purge-modal-close:hover { color: var(--text); background: rgba(0, 0, 0, 0.05); }
.purge-modal-close:disabled { opacity: 0.5; cursor: default; }

.purge-modal-body {
  padding: 16px 20px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.purge-modal-target {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 12px;
  background: rgba(0, 0, 0, 0.03);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.purge-modal-target .meta-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
}
.purge-modal-target-email {
  font-weight: 600;
  font-size: 14px;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.purge-modal-target-id {
  font-size: 11.5px;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.purge-modal-lead {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
}
.purge-modal-lead code {
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace);
  font-size: 11.5px;
  padding: 1px 5px;
  border-radius: 4px;
  background: rgba(67, 145, 109, 0.08);
  color: var(--accent);
  border: 1px solid rgba(67, 145, 109, 0.18);
}
.purge-modal-warn {
  font-size: 12.5px;
  color: #7c2d12;
  background: rgba(255, 167, 38, 0.10);
  border: 1px solid rgba(255, 167, 38, 0.32);
  border-radius: 6px;
  padding: 8px 12px;
  line-height: 1.5;
}
.purge-modal-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.purge-modal-field-label {
  font-size: 12px;
  color: var(--text-muted);
}
.purge-modal-field-label code {
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace);
  font-size: 11.5px;
  padding: 1px 5px;
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.05);
  color: var(--text);
  border: 1px solid var(--border);
}
.purge-confirm-input {
  width: 100%;
  box-sizing: border-box;
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace);
  font-size: 13px;
  padding: 8px 10px;
}
.purge-confirm-input-invalid,
.purge-confirm-input-invalid:focus {
  border-color: #b04848;
  box-shadow: 0 0 0 2px rgba(176, 72, 72, 0.18);
}
.purge-modal-field-error {
  font-size: 11.5px;
  color: #991b1b;
}
.purge-modal-check {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text);
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fafdfb;
  cursor: pointer;
}
.purge-modal-check input[type="checkbox"] {
  margin-top: 3px;
  flex: 0 0 auto;
}
.purge-modal-check-hint {
  display: block;
  font-size: 11.5px;
  color: var(--text-muted);
  line-height: 1.5;
  margin-top: 2px;
}
.purge-modal-check-danger {
  border-color: rgba(176, 72, 72, 0.4);
  background: rgba(176, 72, 72, 0.05);
}
.purge-modal-check-danger strong { color: #991b1b; }
.purge-modal-error {
  margin-top: 2px;
}
.purge-modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 20px;
  border-top: 1px solid var(--border);
  background: #fafdfb;
  border-bottom-left-radius: 12px;
  border-bottom-right-radius: 12px;
}

/* --- Admin -> Audit logs (Phase 6c slice 5) ------------------- */
.admin-audit { display: flex; flex-direction: column; gap: 14px; }
.admin-audit-toolbar {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 4px;
}
.admin-audit-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.admin-audit-filters {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
}
.admin-audit-input {
  height: 30px;
  font-size: 13px;
  padding: 4px 8px;
  min-width: 200px;
  flex: 0 1 240px;
}
.admin-audit-limit {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-muted);
}
.admin-audit-limit .select {
  height: 30px;
  font-size: 13px;
  padding: 2px 6px;
}
.admin-audit-card { padding: 0; overflow: hidden; }
.admin-audit-table-scroll {
  max-height: 64vh;
  overflow-y: auto;
}
.admin-audit-table {
  width: 100%;
  table-layout: auto;
}
.admin-audit-table th,
.admin-audit-table td {
  padding: 8px 12px;
  font-size: 12.5px;
  vertical-align: top;
  border-bottom: 1px solid var(--border);
}
.admin-audit-table tbody tr:hover { background: rgba(67, 145, 109, 0.04); }
.audit-col-time   { white-space: nowrap; width: 110px; color: var(--text-muted); }
.audit-col-actor  { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.audit-col-action { width: 200px; }
.audit-col-target { max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.audit-col-meta   { min-width: 220px; }
.audit-actor-email { color: var(--text); }
.audit-actor-id { color: var(--text-muted); font-size: 11.5px; }
.audit-target-type {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--text-muted);
  margin-right: 6px;
}
.audit-target-id { color: var(--text); font-size: 12px; }

/* Action chip — small pill with bucket-coloured background. The
   bucket modifiers are shared with the chip strip above the table. */
.audit-action-chip {
  display: inline-block;
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace);
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: #fff;
  color: var(--text);
}
.audit-bucket-grant   { background: rgba(67, 145, 109, 0.10);  border-color: rgba(67, 145, 109, 0.32);  color: var(--accent); }
.audit-bucket-warn    { background: rgba(255, 167, 38, 0.10);  border-color: rgba(255, 167, 38, 0.32);  color: #7c2d12; }
.audit-bucket-danger  { background: rgba(176, 72, 72, 0.08);   border-color: rgba(176, 72, 72, 0.32);   color: #991b1b; }
.audit-bucket-neutral { background: rgba(0, 0, 0, 0.04);        border-color: var(--border);             color: var(--text-muted); }
/* Action chips in the toolbar reuse .lib-chip base styling; the
   bucket classes layer color on top when "on". The unselected
   state shows a faint bucket tint so admins can scan the strip. */
.admin-audit-actions .lib-chip { font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace); font-size: 11px; }
.admin-audit-actions .lib-chip.audit-bucket-grant  { color: var(--accent); }
.admin-audit-actions .lib-chip.audit-bucket-warn   { color: #7c2d12; }
.admin-audit-actions .lib-chip.audit-bucket-danger { color: #991b1b; }
.admin-audit-actions .lib-chip.on.audit-bucket-grant  { background: rgba(67, 145, 109, 0.18);  border-color: var(--accent); }
.admin-audit-actions .lib-chip.on.audit-bucket-warn   { background: rgba(255, 167, 38, 0.20);  border-color: rgba(255, 167, 38, 0.6); }
.admin-audit-actions .lib-chip.on.audit-bucket-danger { background: rgba(176, 72, 72, 0.15);   border-color: rgba(176, 72, 72, 0.6); }

.audit-meta-toggle {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--text-muted);
  cursor: pointer;
  text-align: left;
}
.audit-meta-toggle:hover { color: var(--text); }
.audit-meta-preview {
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace);
  font-size: 11px;
  margin-left: 4px;
}
.audit-meta-pre {
  margin: 6px 0 0;
  padding: 8px 10px;
  background: rgba(0, 0, 0, 0.04);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace);
  font-size: 11.5px;
  line-height: 1.5;
  white-space: pre;
  overflow-x: auto;
  max-height: 280px;
}
.admin-audit-foot {
  padding: 10px 14px;
  border-top: 1px solid var(--border);
  background: #fafdfb;
}

/* --- Admin -> Cleanup (Phase 6c slice 5) --------------------- */
.admin-cleanup-card {
  max-width: 720px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 18px 22px;
}
.admin-cleanup-lead {
  margin: 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--text);
}
.admin-cleanup-lead code {
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", monospace);
  font-size: 11.5px;
  padding: 1px 5px;
  border-radius: 4px;
  background: rgba(67, 145, 109, 0.08);
  color: var(--accent);
  border: 1px solid rgba(67, 145, 109, 0.18);
}
.admin-cleanup-last {
  padding: 10px 12px;
  background: rgba(0, 0, 0, 0.03);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 12.5px;
  color: var(--text);
}
.admin-cleanup-last-label {
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  font-size: 10.5px;
  letter-spacing: 0.4px;
  margin-right: 6px;
}
.admin-cleanup-last-time   { font-weight: 600; }
.admin-cleanup-last-actor  { color: var(--accent); }
.admin-cleanup-last-errs   { color: #991b1b; }
.admin-cleanup-last-err    { color: #991b1b; }
.admin-cleanup-actions {
  display: flex;
  gap: 8px;
}
.admin-cleanup-result {
  margin-top: 4px;
  padding: 10px 12px;
  font-size: 12.5px;
  line-height: 1.5;
}
.admin-cleanup-result-note  { margin-top: 6px; color: var(--text-muted); font-size: 12px; }
.admin-cleanup-result-errs  { margin-top: 6px; color: #991b1b; font-size: 12px; }
/* Info banner variant for the dry-run result — reuses the
   exec-banner shell with a softer blue tint. */
.exec-banner.info {
  background: rgba(67, 145, 109, 0.08);
  border: 1px solid rgba(67, 145, 109, 0.32);
  color: var(--accent);
}

/* --- Admin -> Usage (Phase 6c slice 5) ----------------------- */
/* The admin Usage page is a narrow, content-driven layout: the
   page area can be 1100px+ wide but the data is just a small
   totals row + a 5-column table, so we cap the visible content
   width and lock numeric columns to readable sizes. */
.admin-usage {
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-width: 980px;
}

/* Toolbar: small "USER" caption, picker button, optional clear
   button, flex-spacer, refresh. The label is OUTSIDE the button
   instead of inside it so the button is visually clean. */
.admin-usage-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.admin-usage-toolbar-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
}
.admin-usage-toolbar-spacer { flex: 1 1 auto; }

.admin-usage-picker-wrap {
  position: relative;
  flex: 0 0 auto;
}
.admin-usage-picker-btn {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  height: 32px;
  padding: 4px 12px;
  min-width: 240px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 6px;
  cursor: pointer;
  font: inherit;
  text-align: left;
}
.admin-usage-picker-btn:hover { border-color: var(--accent-3, var(--accent)); }
.admin-usage-picker-btn[aria-expanded="true"] {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px rgba(67, 145, 109, 0.16);
}
.admin-usage-picker-current {
  flex: 1 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
  color: var(--text);
}
.admin-usage-picker-caret {
  flex: 0 0 auto;
  color: var(--text-muted);
  font-size: 11px;
}
.admin-usage-picker-pop {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 50;
  width: 340px;
  max-width: calc(100vw - 32px);
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.admin-usage-picker-pop.hidden { display: none; }
.admin-usage-picker-input {
  width: 100%;
  box-sizing: border-box;
  height: 30px;
  font-size: 13px;
  padding: 4px 8px;
}
.admin-usage-picker-list {
  max-height: 320px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.admin-usage-picker-item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  padding: 6px 8px;
  text-align: left;
  background: none;
  border: 0;
  border-radius: 6px;
  cursor: pointer;
  font: inherit;
}
.admin-usage-picker-item:hover,
.admin-usage-picker-item.focused {
  background: rgba(67, 145, 109, 0.08);
}
.admin-usage-picker-email {
  font-size: 13px;
  color: var(--text);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.admin-usage-picker-name { font-size: 11.5px; }
.admin-usage-picker-empty {
  padding: 8px;
  color: var(--text-muted);
  font-size: 12.5px;
  text-align: center;
}

/* Totals card. The stats row is a fixed-gap flex wrap (not a
   stretching grid), so values cluster compactly on the left
   instead of spreading edge-to-edge across the card. */
.admin-usage-totals {
  padding: 14px 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.admin-usage-totals-head { display: flex; align-items: center; }
.admin-usage-totals-head .card-title {
  margin: 0;
  padding: 0;
}
.admin-usage-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 18px 28px;
}
.admin-usage-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 110px;
}
.admin-usage-stat-label {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
}
.admin-usage-stat-value {
  font-size: 18px;
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.admin-usage-totals-note {
  margin: 0;
  padding: 8px 10px;
  background: rgba(0, 0, 0, 0.025);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--text-muted);
}

/* By-user table. Constrained column widths keep email + numbers
   readable instead of stretching across the whole page. */
.admin-usage-table-card { padding: 0; margin-top: 20px;}
.admin-usage-table-title { padding: 14px 18px 6px; }
.admin-usage-table-wrap {
  overflow-x: auto;
}
.admin-usage-table {
  width: 100%;
  table-layout: fixed;
}
.admin-usage-col-user { width: auto; }
.admin-usage-col-num  { width: 130px; }
.admin-usage-col-cost { width: 110px; }
.admin-usage-table th,
.admin-usage-table td {
  padding: 8px 14px;
  font-size: 12.5px;
}
.admin-usage-table th.num,
.admin-usage-table td.num {
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.admin-usage-cell-user {
  max-width: 0; /* prerequisite for ellipsis inside a fixed-layout cell */
}
.admin-usage-cell-email {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
  color: var(--text);
}
.admin-usage-empty { padding: 14px 18px; }

@media (max-width: 1000px) {
  .admin-usage-picker-btn { min-width: 200px; }
  .admin-usage-col-num  { width: 110px; }
  .admin-usage-col-cost { width: 100px; }
  .admin-usage-stats { gap: 14px 22px; }
  .admin-usage-stat { min-width: 96px; }
  .admin-usage-stat-value { font-size: 16px; }
}

/* Audit metadata note — small caption inside the expanded
   metadata block clarifying that values aren't recorded
   (Phase 5 design). */
.audit-meta-note {
  margin: 6px 0 4px;
  font-size: 11.5px;
  font-style: italic;
}

/* --- Phase 8: OIDC sign-in / sign-out header affordances ---------- */
/* The dev-mode build never renders these (renderHeaderUser branches
   on Session.isOidc). Under OIDC the unauth state shows the
   sign-in button in place of the user pill; the auth state shows
   the user pill followed by a small text-style Sign-out link. */
.signin-btn {
  /* Compact primary-style anchor — sits in the same slot the user
     pill would occupy when authenticated, so the header layout
     doesn't shift between OIDC states. */
  text-decoration: none;
}
.signout-btn {
  display: inline-flex;
  align-items: center;
  margin-left: 6px;
  padding: 4px 8px;
  font-size: 12px;
  color: var(--text-muted);
  text-decoration: none;
  border-radius: 6px;
  transition: color 0.15s ease, background 0.15s ease;
}
.signout-btn:hover {
  color: var(--text);
  background: rgba(0, 0, 0, 0.04);
}
