/*
 * Crusoe AI Platform console - the shell's stylesheet.
 *
 * The palette is one deliberate design system for the whole product: everything
 * is a custom property, so a page that needs a colour
 * takes it from here rather than inventing one - eight pages each choosing their
 * own "danger red" is how a console starts looking assembled rather than built.
 *
 * DENSITY IS A FEATURE. This is an operations console: rows are 34px, the type
 * is 13-14px, and padding is tight, because the job is comparing twenty things
 * at once, not reading one.
 */

:root {
  --bg: #0a0e13;
  --panel: #11161d;
  --panel-2: #161d26;
  --panel-3: #1c242f;
  --border: rgba(255, 255, 255, .08);
  --border-strong: rgba(255, 255, 255, .16);
  --text: #e6edf3;
  --text-dim: #8b98a5;
  --text-faint: #5c6773;
  --accent: #ff8552;
  --accent-hover: #ff9a70;
  --accent-soft: rgba(255, 133, 82, .14);
  --ok: #3ddc97;
  --ok-soft: rgba(61, 220, 151, .12);
  --warn: #ffc857;
  --warn-soft: rgba(255, 200, 87, .12);
  --err: #ff5d5d;
  --err-soft: rgba(255, 93, 93, .12);
  --info: #58a6ff;
  --info-soft: rgba(88, 166, 255, .12);
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Inter, sans-serif;

  --topbar-h: 52px;
  --nav-w: 232px;
  --radius: 8px;
  --radius-sm: 6px;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

::selection { background: var(--accent-soft); }

a { color: var(--info); text-decoration: none; }
a:hover { text-decoration: underline; }

[hidden] { display: none !important; }

/* Focus is always visible. An operations console is used from the keyboard more
   than its designers expect, and a focus ring removed "for looks" makes half of
   it unusable. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

/* --------------------------------------------------------------------------
   Sign-in
   -------------------------------------------------------------------------- */

.login {
  min-height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background:
    radial-gradient(900px 500px at 50% -10%, rgba(255, 133, 82, .10), transparent 60%),
    var(--bg);
}

.login-card {
  width: 100%;
  max-width: 380px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 28px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.login-brand { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; }
.login-brand h1 { font-size: 17px; font-weight: 650; letter-spacing: .2px; }
.login-brand p { font-size: 13px; color: var(--text-dim); }

.login-mark, .brand-mark {
  width: 26px; height: 26px; flex: none; border-radius: 7px;
  background: linear-gradient(140deg, var(--accent), #d9532a);
  box-shadow: 0 0 18px rgba(255, 133, 82, .35);
  display: grid; place-items: center;
}
.login-mark svg, .brand-mark svg {
  width: 62%; height: 62%; display: block;
  fill: #fff; opacity: .96;
}

.login-card label { font-size: 12px; color: var(--text-dim); margin-top: 8px; }

.login-error {
  margin-top: 12px;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  background: var(--err-soft);
  border: 1px solid rgba(255, 93, 93, .35);
  color: #ffb3b3;
  font-size: 13px;
}

.login-note {
  margin-top: 14px;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--text-faint);
}

/* --------------------------------------------------------------------------
   Application shell
   -------------------------------------------------------------------------- */

.app { height: 100%; display: flex; flex-direction: column; }

.topbar {
  height: var(--topbar-h);
  flex: none;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 0 14px;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, #10151c, #0c1117);
  position: relative;
  z-index: 20;
}

.brand { display: flex; align-items: center; gap: 10px; flex: none; color: var(--text); }
.brand:hover { text-decoration: none; }
.brand-mark { width: 22px; height: 22px; border-radius: 6px; }
.brand-name { font-weight: 650; font-size: 14.5px; letter-spacing: .2px; white-space: nowrap; }

.topbar-spacer { flex: 1; min-width: 0; }

.scope {
  display: flex; align-items: center; gap: 10px;
  height: 32px; padding: 0 12px;
  background: var(--panel-2);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  color: var(--text);
  font: inherit; font-size: 13px;
  cursor: pointer;
  max-width: 420px;
}
.scope:hover { background: var(--panel-3); }
.scope-label { color: var(--text-faint); font-size: 11px; text-transform: uppercase; letter-spacing: .6px; flex: none; }
.scope-value { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.scope-caret {
  flex: none; width: 0; height: 0;
  border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-top: 5px solid var(--text-faint);
}

.user-chip {
  display: flex; align-items: center; gap: 9px;
  height: 34px; padding: 0 10px 0 6px;
  background: transparent; border: 1px solid transparent; border-radius: 999px;
  color: var(--text); font: inherit; cursor: pointer;
}
.user-chip:hover { background: var(--panel-2); border-color: var(--border); }
.user-avatar {
  width: 24px; height: 24px; flex: none; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent);
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 700; text-transform: uppercase;
}
.user-meta { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.15; min-width: 0; }
.user-email { font-size: 12.5px; max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-role { font-size: 10.5px; color: var(--text-faint); text-transform: uppercase; letter-spacing: .5px; }

@media (max-width: 860px) {
  .brand-name { display: none; }
  .user-meta { display: none; }
}

/* Hamburger: hidden on desktop, shown when the nav becomes an off-canvas drawer
   (<=768px). Three bars drawn from one span + its pseudo-elements. */
.nav-toggle {
  display: none; flex: none; width: 34px; height: 34px; margin-right: 2px;
  align-items: center; justify-content: center;
  background: transparent; border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: var(--text); cursor: pointer;
}
.nav-toggle:hover { background: var(--panel-2); }
.nav-toggle-bars { position: relative; }
.nav-toggle-bars, .nav-toggle-bars::before, .nav-toggle-bars::after {
  content: ""; display: block; width: 16px; height: 2px; border-radius: 2px; background: currentColor;
}
.nav-toggle-bars::before { position: absolute; top: -5px; }
.nav-toggle-bars::after { position: absolute; top: 5px; }
.nav-backdrop { display: none; }

@media (max-width: 768px) {
  .nav-toggle { display: inline-flex; }
  /* Off-canvas drawer: slides over the content instead of squeezing it. */
  .nav {
    position: fixed; top: var(--topbar-h); bottom: 0; left: 0;
    width: 264px; z-index: 45;
    transform: translateX(-100%); transition: transform .18s ease;
    box-shadow: 0 0 44px rgba(0, 0, 0, .55);
  }
  .nav.open { transform: none; }
  .nav-backdrop:not([hidden]) {
    display: block; position: fixed; inset: var(--topbar-h) 0 0 0;
    background: rgba(0, 0, 0, .5); z-index: 44;
  }
  /* Detail-page breadcrumb + actions: wrap to their own lines rather than
     overflowing a narrow viewport, which would scroll the whole app sideways.
     Also reclaim horizontal padding for the wide tables the console is built
     around, and let the scope pill give way before it crowds the user chip. */
  .crumbs { flex-wrap: wrap; row-gap: 8px; padding: 10px 14px; }
  .breadcrumb { flex-basis: 100%; }
  .page-actions { flex-wrap: wrap; }
  .page { padding: 14px; }
  .scope { max-width: 52vw; }
}
@media (prefers-reduced-motion: reduce) { .nav { transition: none; } }

.menu {
  position: absolute; top: calc(var(--topbar-h) - 4px); right: 12px;
  min-width: 190px; padding: 5px;
  background: var(--panel-2); border: 1px solid var(--border-strong);
  border-radius: var(--radius); box-shadow: 0 12px 32px rgba(0, 0, 0, .5);
  z-index: 40;
}
.menu-item {
  display: block; width: 100%; text-align: left;
  padding: 8px 10px; border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--text); font: inherit; font-size: 13px; cursor: pointer;
}
.menu-item:hover { background: var(--panel-3); }

.shell { flex: 1; display: flex; min-height: 0; }

/* --------------------------------------------------------------------------
   Left navigation
   -------------------------------------------------------------------------- */

.nav {
  width: var(--nav-w); flex: none;
  border-right: 1px solid var(--border);
  background: #0d1219;
  overflow-y: auto;
  padding: 12px 8px 24px;
}

.nav-section {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .8px;
  color: var(--text-faint); padding: 14px 10px 6px;
}
.nav-section:first-child { padding-top: 4px; }

.nav-item {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 10px; margin-bottom: 1px;
  border-radius: var(--radius-sm);
  color: var(--text-dim); font-size: 13.5px;
  cursor: pointer;
}
.nav-item:hover { background: var(--panel-2); color: var(--text); text-decoration: none; }
.nav-item.active { background: var(--accent-soft); color: var(--accent); font-weight: 550; }
/* Not pointer-events:none - that would kill the hover that surfaces the
   title tooltip explaining WHY the item is locked. The click is neutralized in
   app.js (aria-disabled anchors early-return) instead. */
.nav-item.disabled { opacity: .38; cursor: default; }
.nav-item.disabled:hover { background: transparent; color: var(--text-dim); }
.nav-icon { width: 18px; text-align: center; flex: none; font-size: 14px; }
.nav-hint { padding: 8px 12px; font-size: 12px; color: var(--text-faint); line-height: 1.45; }

/* --------------------------------------------------------------------------
   Content column
   -------------------------------------------------------------------------- */

.content { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.crumbs {
  flex: none;
  display: flex; align-items: center; gap: 12px;
  padding: 10px 22px;
  border-bottom: 1px solid var(--border);
  background: rgba(13, 18, 25, .6);
}

.breadcrumb { display: flex; align-items: center; gap: 7px; list-style: none; min-width: 0; flex: 1; overflow: hidden; }
.breadcrumb li { display: flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--text-dim); white-space: nowrap; flex: none; }
.breadcrumb li + li::before { content: "/"; color: var(--text-faint); }
/* The trailing (current) crumb is the one long name; let it truncate rather than
   spill past the bar into the page actions. */
.breadcrumb li:last-child { color: var(--text); font-weight: 550; min-width: 0; overflow: hidden; text-overflow: ellipsis; display: block; }

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

.page { flex: 1; min-height: 0; overflow-y: auto; padding: 22px; }
.page:focus { outline: none; }

.page-head { display: flex; align-items: flex-start; gap: 16px; margin-bottom: 18px; }
.page-head h2 { font-size: 19px; font-weight: 620; letter-spacing: .2px; }
.page-head p { font-size: 13px; color: var(--text-dim); margin-top: 3px; max-width: 74ch; }
.page-head .spacer { flex: 1; }
.page-head-title { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* In-product docs affordance (CAI.ui.pageHead docs:) and the reference drawer
   (CAI.ui.helpDrawer / renderMarkdown). */
.docs-link {
  display: inline-flex; align-items: center; gap: 5px;
  height: 22px; padding: 0 9px;
  border: 1px solid var(--border); border-radius: 999px;
  background: transparent; color: var(--text-dim);
  font-size: 11.5px; font-weight: 500; cursor: pointer;
  transition: color .12s, border-color .12s, background .12s;
}
.docs-link:hover { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }
.docs-link-glyph { font-size: 11px; line-height: 1; }

.help-body { max-height: 72vh; overflow-y: auto; }
.md { font-size: 13.5px; line-height: 1.6; color: var(--text); }
.md .md-h { margin: 18px 0 8px; font-weight: 640; letter-spacing: .2px; color: var(--text); }
.md h2.md-h { font-size: 17px; }
.md h3.md-h { font-size: 14.5px; }
.md h4.md-h, .md h5.md-h { font-size: 12.5px; color: var(--text-dim); }
.md > .md-h:first-child { margin-top: 0; }
.md-p { margin: 9px 0; color: var(--text-dim); }
.md-list { margin: 9px 0 9px 20px; color: var(--text-dim); }
.md-list li { margin: 4px 0; }
.md-code {
  margin: 12px 0; padding: 12px 14px;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--radius-sm); overflow-x: auto;
}
.md-code code { font-size: 12.5px; color: var(--text); white-space: pre; font-family: var(--mono, ui-monospace, monospace); }
.md-p code, .md-list code {
  background: var(--panel-3); padding: 1px 5px; border-radius: 4px;
  font-size: 12px; color: var(--accent-hover); font-family: var(--mono, ui-monospace, monospace);
}
.md a { color: var(--info); text-decoration: none; }
.md a:hover { text-decoration: underline; }
.md-table-wrap { overflow-x: auto; margin: 12px 0; }
.md-table { border-collapse: collapse; font-size: 12.5px; }
.md-table th, .md-table td { border: 1px solid var(--border); padding: 6px 11px; text-align: left; white-space: nowrap; }
.md-table th { background: var(--panel-2); color: var(--text); font-weight: 600; }
.md-table td { color: var(--text-dim); }

.section { margin-bottom: 26px; }
.section-head { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.section-head h3 { font-size: 14px; font-weight: 600; }
.section-head .spacer { flex: 1; }
.section-head p { font-size: 12.5px; color: var(--text-dim); }

/* --------------------------------------------------------------------------
   Buttons and inputs
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 32px; padding: 0 13px;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--panel-2); color: var(--text);
  font: inherit; font-size: 13px; font-weight: 500;
  cursor: pointer; white-space: nowrap;
}
.btn:hover:not(:disabled) { background: var(--panel-3); border-color: rgba(255, 255, 255, .24); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn-primary { background: var(--accent); border-color: var(--accent); color: #150b06; font-weight: 600; }
.btn-primary:hover:not(:disabled) { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn-danger { color: #ffb3b3; border-color: rgba(255, 93, 93, .4); background: var(--err-soft); }
.btn-danger:hover:not(:disabled) { background: rgba(255, 93, 93, .2); }
.btn-ghost { background: transparent; border-color: transparent; color: var(--text-dim); }
.btn-ghost:hover:not(:disabled) { background: var(--panel-2); color: var(--text); }
.btn-sm { height: 26px; padding: 0 9px; font-size: 12px; }
.btn-block { width: 100%; margin-top: 18px; height: 36px; }

input[type="text"], input[type="email"], input[type="password"], input[type="number"],
select, textarea {
  width: 100%; height: 34px; padding: 0 11px;
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  font: inherit; font-size: 13.5px;
}
textarea { height: auto; min-height: 90px; padding: 9px 11px; font-family: var(--mono); font-size: 12.5px; line-height: 1.55; }
select { appearance: none; padding-right: 28px; cursor: pointer; }
input::placeholder, textarea::placeholder { color: var(--text-faint); }
input:focus, select:focus, textarea:focus { border-color: var(--accent); outline: none; }
input[type="checkbox"] { width: 15px; height: 15px; accent-color: var(--accent); }

/* --------------------------------------------------------------------------
   Forms (CAI.ui.form)
   -------------------------------------------------------------------------- */

.form { display: flex; flex-direction: column; gap: 14px; }
.form-field { display: flex; flex-direction: column; gap: 5px; }
.form-field > label { font-size: 12px; color: var(--text-dim); }
.form-field .help { font-size: 11.5px; color: var(--text-faint); line-height: 1.45; }
.form-field .field-error { font-size: 12px; color: var(--err); line-height: 1.4; }
.form-field input[aria-invalid="true"],
.form-field select[aria-invalid="true"],
.form-field textarea[aria-invalid="true"] { border-color: var(--err); }
.form-field.checkbox { gap: 6px; }
.form-field.checkbox > .checkbox-row {
  display: flex; align-items: center; gap: 9px;
  color: var(--text); font-size: 13px; cursor: pointer;
}
.form-field.checkbox > .checkbox-row > input { flex: none; margin: 0; }
/* The help sits UNDER the row, aligned with the label rather than the box, so
   the option reads as one sentence with an explanation beneath it. */
.form-field.checkbox > .help { padding-left: 24px; }
/* A field the form has disabled because another choice supersedes it. Dimmed
   rather than hidden: removing it would make the dialog jump, and the user
   needs to see WHY typing is no longer possible. */
.form-field input:disabled { opacity: .45; cursor: not-allowed; }
.form-field.is-superseded > label,
.form-field.is-superseded > .help { opacity: .55; }
.form-field .field-error { font-size: 11.5px; color: #ffb3b3; }

/* A multi-row <select> used as a filterable chooser - today, the Crusoe Cloud
   project picker, which routinely lists dozens. The base `select` rule pins
   height to 34px and hides the native affordance; both are wrong for a list box,
   where `size` has to be free to set the height and the rows need their own
   padding to be clickable targets rather than a dense block of text. */
.form-field select.cc-project-list {
  height: auto; padding: 4px; cursor: default;
}
.form-field select.cc-project-list option { padding: 4px 7px; border-radius: 3px; }
/* Password policy checklist (CAI.ui.passwordPolicy). It occupies a field's
   `help` slot but is not a `.help`, so it styles itself to match one. Unmet
   requirements are MUTED rather than red: while someone is typing, a
   requirement not yet reached is not a mistake, and a dialog that turns red at
   the first keystroke reads as an accusation. */
.pw-policy { display: flex; flex-direction: column; gap: 3px; }
.pw-req {
  display: flex; align-items: baseline; gap: 6px;
  font-size: 11.5px; line-height: 1.45; color: var(--text-faint);
}
.pw-req > .pw-mark { flex: none; width: 10px; text-align: center; }
.pw-req.is-met { color: var(--text-dim); }
.pw-req.is-met > .pw-mark { color: var(--ok); }
.pw-req.pw-sub { padding-left: 16px; }

.form-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 4px; }
.form-error {
  padding: 9px 12px; border-radius: var(--radius-sm);
  background: var(--err-soft); border: 1px solid rgba(255, 93, 93, .35);
  color: #ffb3b3; font-size: 12.5px;
}

/* --------------------------------------------------------------------------
   Tables (CAI.ui.table)
   -------------------------------------------------------------------------- */

.table-wrap {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--panel); overflow: hidden;
}
.table-scroll { overflow-x: auto; }

table.table { width: 100%; border-collapse: collapse; font-size: 13px; }
table.table th {
  text-align: left; font-weight: 550; font-size: 11px;
  text-transform: uppercase; letter-spacing: .6px; color: var(--text-faint);
  padding: 9px 14px; background: var(--panel-2);
  border-bottom: 1px solid var(--border); white-space: nowrap;
}
table.table td {
  padding: 0 14px; height: 34px;
  border-bottom: 1px solid var(--border);
  color: var(--text); vertical-align: middle;
}
table.table tbody tr:last-child td { border-bottom: 0; }

/* Sortable column headers.
   The idle glyph is always present, just faint: a control you can only
   discover by clicking is a control most people never find. It brightens on
   hover and becomes a single direction arrow once the column is the sort. */
table.table th.sortable {
  cursor: pointer; user-select: none;
  /* Room for the arrow, so the label does not shift when the glyph changes
     width between the two-headed idle arrow and a single direction. */
  padding-right: 8px;
}
table.table th.sortable:hover { color: var(--text); background: var(--panel-3); }
table.table th.sortable:focus-visible {
  outline: 2px solid var(--accent); outline-offset: -2px;
}
table.table th .sort-arrow {
  display: inline-block; margin-left: 6px; font-size: 10px;
  width: 8px; text-align: center; color: var(--accent);
}
table.table th .sort-arrow-idle { color: var(--text-faint); opacity: .45; }
table.table th.sortable:hover .sort-arrow-idle { opacity: .9; }
table.table th[aria-sort="ascending"], table.table th[aria-sort="descending"] { color: var(--text); }
table.table tbody tr.clickable { cursor: pointer; }
table.table tbody tr.clickable:hover { background: var(--panel-2); }
table.table td.mono, .mono { font-family: var(--mono); font-size: 12px; }
table.table td.dim { color: var(--text-dim); }
table.table td.actions { text-align: right; white-space: nowrap; }
table.table td.actions .btn + .btn { margin-left: 6px; }
table.table td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------------------
   Tabs (CAI.ui.tabs) - one tabbed spine for every resource detail page.
   -------------------------------------------------------------------------- */

.tabs { display: flex; flex-direction: column; }
.tabstrip {
  display: flex; gap: 2px; flex-wrap: wrap; align-items: flex-end;
  border-bottom: 1px solid var(--border);
  margin-bottom: 22px;
}
.tab {
  appearance: none; background: transparent; border: 0;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  padding: 9px 14px; border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  color: var(--text-dim); font: inherit; font-size: 13px; font-weight: 550;
  cursor: pointer; white-space: nowrap;
}
.tab:hover:not(.active) { color: var(--text); background: var(--panel-2); }
.tab.active { color: var(--accent); border-bottom-color: var(--accent); }
.tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.tabpanel { outline: none; }
.tabpanel[hidden] { display: none; }

/* --------------------------------------------------------------------------
   codeBlock (CAI.ui.codeBlock) - read-only YAML/spec and log panes.
   -------------------------------------------------------------------------- */

.codeblock { display: flex; flex-direction: column; }
.codeblock-bar { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.codeblock-pre {
  margin: 0; padding: 12px;
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-sm);
  overflow: auto; font-size: 12px; line-height: 1.55; color: var(--text);
  white-space: pre; word-break: normal;
}

/* --------------------------------------------------------------------------
   codeEditor (CAI.ui.codeEditor) + the multi-file workspace (deploykit
   sourcePicker "write" mode): tab strip, editor pane, dirty markers.
   -------------------------------------------------------------------------- */

.code-editor .cm-editor { max-height: 480px; }
.editor-workspace { gap: 0; }
.editor-tabs {
  display: flex; align-items: center; gap: 2px; flex-wrap: wrap;
  border-bottom: 1px solid var(--border); padding: 0 2px;
}
.editor-tab {
  appearance: none; background: transparent; color: var(--text-dim);
  border: 1px solid transparent; border-bottom: none;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  padding: 6px 10px; font-size: 12px; cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px;
  max-width: 220px;
}
.editor-tab > .mono { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.editor-tab:hover { color: var(--text); background: var(--panel-2); }
.editor-tab.active {
  color: var(--text); background: var(--panel-2);
  border-color: var(--border);
  /* Sit on the strip's border so the active tab reads as attached to the pane. */
  margin-bottom: -1px; padding-bottom: 7px;
}
.editor-dirty { color: var(--accent); font-size: 10px; line-height: 1; }
.editor-tab-close {
  color: var(--text-faint); font-size: 13px; line-height: 1; padding: 0 2px;
  border-radius: 3px;
}
.editor-tab-close:hover { color: var(--err); background: var(--err-soft); }
.editor-add { margin-left: 4px; }
.editor-pane { padding-top: 10px; }
.editor-pane .cm-editor { max-height: 440px; }

/* --------------------------------------------------------------------------
   State blocks: loading / empty / error. One look for all of them, everywhere.
   -------------------------------------------------------------------------- */

.state {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; padding: 42px 24px; text-align: center;
  color: var(--text-dim); font-size: 13px;
}
.state h4 { font-size: 14px; font-weight: 600; color: var(--text); }
.state p { max-width: 56ch; line-height: 1.5; }
.state .state-icon { font-size: 24px; opacity: .6; }
.state .state-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-top: 4px; }
.state .state-hint { font-size: 12px; color: var(--text-faint); max-width: 56ch; }
.state.error { color: #ffb3b3; }
.state.error h4 { color: #ffd0d0; }
.state .request-id { font-family: var(--mono); font-size: 11px; color: var(--text-faint); }

.spinner {
  width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid var(--border-strong); border-top-color: var(--accent);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spinner { animation-duration: 2.4s; } }

/* Boot splash: the first paint while the session check is in flight. Brand mark
   above a spinner, centered on the app background - never a blank viewport. */
.boot-splash {
  position: fixed; inset: 0; z-index: 50;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 18px;
  background: var(--bg);
}
.boot-splash .login-mark { width: 40px; height: 40px; border-radius: 10px; }

/* --------------------------------------------------------------------------
   Badges
   -------------------------------------------------------------------------- */

.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 1px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 600; letter-spacing: .3px;
  background: var(--panel-3); color: var(--text-dim);
  border: 1px solid var(--border);
}
.badge.ok { background: var(--ok-soft); color: var(--ok); border-color: rgba(61, 220, 151, .3); }
.badge.warn { background: var(--warn-soft); color: var(--warn); border-color: rgba(255, 200, 87, .3); }
.badge.err { background: var(--err-soft); color: var(--err); border-color: rgba(255, 93, 93, .3); }
.badge.info { background: var(--info-soft); color: var(--info); border-color: rgba(88, 166, 255, .3); }
.badge.accent { background: var(--accent-soft); color: var(--accent); border-color: rgba(255, 133, 82, .3); }

/* Status chips (CAI.ui.statusChip): a dot + word, one vocabulary across every
   list. A dot rather than a pill, so a status reads differently from an
   attribute badge sitting next to it in the same row. */
.status-chip {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 12px; font-weight: 550; letter-spacing: .2px;
  color: var(--text-dim); white-space: nowrap;
}
.status-chip .status-dot {
  width: 7px; height: 7px; flex: none; border-radius: 50%;
  background: var(--text-faint);
}
.status-chip.ok { color: var(--ok); }
.status-chip.ok .status-dot { background: var(--ok); box-shadow: 0 0 0 3px var(--ok-soft); }
.status-chip.warn { color: var(--warn); }
.status-chip.warn .status-dot { background: var(--warn); box-shadow: 0 0 0 3px var(--warn-soft); }
.status-chip.err { color: var(--err); }
.status-chip.err .status-dot { background: var(--err); box-shadow: 0 0 0 3px var(--err-soft); }
.status-chip.info { color: var(--info); }
.status-chip.info .status-dot { background: var(--info); box-shadow: 0 0 0 3px var(--info-soft); }
.status-chip.neutral { color: var(--text-dim); }

/* Copy-id (CAI.ui.copyId): a quiet inline button next to a non-secret id. */
.copy-id {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; flex: none; padding: 0; margin-left: 4px;
  border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--text-faint);
  font-size: 12px; line-height: 1; cursor: pointer; vertical-align: middle;
}
.copy-id:hover { background: var(--panel-3); color: var(--text); }
.copy-id.copied { color: var(--ok); }

/* --------------------------------------------------------------------------
   List toolbars: filter box (CAI.ui.listFilter) + bulk-select bar
   (CAI.ui.bulkSelect). Both sit directly above a table.
   -------------------------------------------------------------------------- */

.list-filter { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
.list-filter-icon { color: var(--text-faint); font-size: 14px; flex: none; }
.list-filter-input { max-width: 340px; height: 30px; }
.list-filter-clear {
  flex: none; width: 26px; height: 26px; padding: 0;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--panel-2); color: var(--text-dim);
  font-size: 15px; line-height: 1; cursor: pointer;
}
.list-filter-clear:hover { background: var(--panel-3); color: var(--text); }
.list-filter-count { font-size: 12px; color: var(--text-faint); white-space: nowrap; }
.list-filter-hint {
  font-size: 10.5px; color: var(--text-faint);
  border: 1px solid var(--border); border-radius: 999px;
  padding: 1px 8px; white-space: nowrap; cursor: default;
}

.list-bulkbar {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 10px; padding: 7px 10px 7px 14px;
  background: var(--accent-soft); border: 1px solid rgba(255, 133, 82, .3);
  border-radius: var(--radius);
}
.list-bulkbar .bulk-count { font-size: 13px; font-weight: 600; color: var(--text); }
.bulk-confirm-list { margin: 8px 0 0 18px; font-size: 13px; color: var(--text); line-height: 1.5; }
.bulk-confirm-list li { font-family: var(--mono); font-size: 12px; }
.bulk-confirm-list li.faint { font-family: var(--sans); color: var(--text-faint); }

/* The select column: a narrow, tight leading cell for the checkbox. */
table.table th.select, table.table td.select { width: 36px; padding-right: 0; }
.select-cell { display: inline-flex; align-items: center; justify-content: center; }
input.bulk-check { width: 15px; height: 15px; accent-color: var(--accent); cursor: pointer; vertical-align: middle; }

/* --------------------------------------------------------------------------
   Modals (CAI.ui.modal / CAI.ui.confirm)
   -------------------------------------------------------------------------- */

.modal-backdrop {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(4, 7, 10, .68);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 8vh 20px 24px;
  overflow-y: auto;
}
.modal {
  width: 100%; max-width: 480px;
  background: var(--panel); border: 1px solid var(--border-strong);
  border-radius: 12px; box-shadow: 0 24px 60px rgba(0, 0, 0, .6);
}
.modal.wide { max-width: 720px; }
.modal-head {
  display: flex; align-items: center; gap: 12px;
  padding: 16px 18px; border-bottom: 1px solid var(--border);
}
.modal-head h3 { font-size: 15px; font-weight: 600; flex: 1; }
.modal-close {
  width: 26px; height: 26px; flex: none; border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--text-dim); font-size: 17px; line-height: 1; cursor: pointer;
}
.modal-close:hover { background: var(--panel-3); color: var(--text); }
.modal-body { padding: 18px; }
.modal-body p { font-size: 13.5px; color: var(--text-dim); line-height: 1.55; }
.modal-foot {
  display: flex; justify-content: flex-end; gap: 8px;
  padding: 14px 18px; border-top: 1px solid var(--border);
}

/* --------------------------------------------------------------------------
   Toasts (CAI.ui.toast)
   -------------------------------------------------------------------------- */

.toasts {
  position: fixed; right: 18px; bottom: 18px; z-index: 80;
  display: flex; flex-direction: column-reverse; gap: 9px;
  max-width: min(420px, calc(100vw - 36px));
}
.toast {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 11px 13px;
  background: var(--panel-2); border: 1px solid var(--border-strong);
  border-left: 3px solid var(--text-faint);
  border-radius: var(--radius); box-shadow: 0 10px 30px rgba(0, 0, 0, .5);
  font-size: 13px; line-height: 1.45;
}
.toast.ok { border-left-color: var(--ok); }
.toast.err { border-left-color: var(--err); }
.toast.warn { border-left-color: var(--warn); }
.toast.info { border-left-color: var(--info); }
.toast-body { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.toast-detail { display: block; margin-top: 3px; font-family: var(--mono); font-size: 10.5px; color: var(--text-faint); }
.toast-close {
  border: 0; background: transparent; color: var(--text-faint);
  font-size: 15px; line-height: 1; cursor: pointer; padding: 0 2px;
}
.toast-close:hover { color: var(--text); }

/* --------------------------------------------------------------------------
   Show-once secret (CAI.ui.copyOnce)
   -------------------------------------------------------------------------- */

.copy-once {
  border: 1px solid rgba(255, 200, 87, .35);
  background: var(--warn-soft);
  border-radius: var(--radius);
  padding: 13px 14px;
}
.copy-once .copy-once-label { font-size: 12px; color: var(--warn); font-weight: 600; margin-bottom: 7px; }
.copy-once .copy-once-row { display: flex; align-items: center; gap: 8px; }
.copy-once code {
  flex: 1; min-width: 0;
  font-family: var(--mono); font-size: 12px;
  background: rgba(0, 0, 0, .35); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 7px 9px;
  overflow-x: auto; white-space: nowrap;
}
.copy-once .copy-once-note { margin-top: 8px; font-size: 11.5px; color: var(--text-dim); line-height: 1.45; }

/* --------------------------------------------------------------------------
   Scope picker
   -------------------------------------------------------------------------- */

.scope-picker { display: flex; flex-direction: column; gap: 12px; }
.scope-search { width: 100%; }
.scope-group-label { font-size: 10.5px; text-transform: uppercase; letter-spacing: .8px; color: var(--text-faint); margin-bottom: 6px; }
.scope-list { border: 1px solid var(--border); border-radius: var(--radius); max-height: 320px; overflow-y: auto; }
.scope-hint { font-size: 11.5px; color: var(--text-faint); }
.scope-row {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 12px; border: 0; border-bottom: 1px solid var(--border);
  background: transparent; color: var(--text); font: inherit; font-size: 13px;
  text-align: left; cursor: pointer;
}
.scope-row:last-child { border-bottom: 0; }
.scope-row:hover { background: var(--panel-2); }
.scope-row.selected { background: var(--accent-soft); color: var(--accent); }
.scope-row .scope-row-meta { margin-left: auto; font-size: 11.5px; color: var(--text-faint); font-family: var(--mono); }

/* --------------------------------------------------------------------------
   Command palette (⌘K / Ctrl+K) - unified resource search + project switch.
   -------------------------------------------------------------------------- */

.cmdk { display: flex; flex-direction: column; gap: 10px; }
.cmdk-search { width: 100%; font-size: 14px; padding: 10px 12px; }
.cmdk-status { font-size: 11.5px; color: var(--text-faint); }
.cmdk-results { max-height: 54vh; overflow-y: auto; margin: 0 -4px; padding: 0 4px; }
.cmdk-groups { display: flex; flex-direction: column; gap: 12px; }
.cmdk-group-label {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .8px;
  color: var(--text-faint); margin: 0 2px 4px;
}
.cmdk-list { display: flex; flex-direction: column; gap: 1px; }
.cmdk-row {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 8px 10px; border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--text); font: inherit; font-size: 13px;
  text-align: left; cursor: pointer;
}
.cmdk-row:hover, .cmdk-row.selected { background: var(--accent-soft); color: var(--accent); }
.cmdk-icon { flex: none; width: 18px; text-align: center; color: var(--text-dim); }
.cmdk-row:hover .cmdk-icon, .cmdk-row.selected .cmdk-icon { color: var(--accent); }
.cmdk-row-main { display: flex; flex-direction: column; min-width: 0; }
.cmdk-row-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cmdk-row-sub {
  font-size: 11px; color: var(--text-faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cmdk-row:hover .cmdk-row-sub, .cmdk-row.selected .cmdk-row-sub { color: var(--accent); opacity: .75; }
.cmdk-row-meta {
  margin-left: auto; padding-left: 10px; flex: none;
  font-size: 11px; color: var(--text-faint); font-family: var(--mono);
}
.cmdk-foot {
  display: flex; align-items: center; gap: 14px;
  border-top: 1px solid var(--border); padding-top: 8px;
  font-size: 11px; color: var(--text-faint);
}

/* --------------------------------------------------------------------------
   Quotas - per-project usage bars.
   -------------------------------------------------------------------------- */

.quota-list { display: flex; flex-direction: column; gap: 16px; }
.quota-item { display: flex; flex-direction: column; gap: 6px; }
.quota-item-top { display: flex; align-items: center; gap: 10px; }
.quota-name { font-size: 13px; }
.quota-item-top .spacer { flex: 1; }
.quota-track {
  height: 8px; border-radius: 999px; overflow: hidden;
  background: var(--panel-3); border: 1px solid var(--border);
}
.quota-fill { height: 100%; border-radius: 999px; background: var(--text-faint); transition: width .2s ease; }
.quota-fill.ok { background: var(--ok); }
.quota-fill.warn { background: var(--warn); }
.quota-fill.err { background: var(--err); }
.quota-item-bot { font-size: 12px; color: var(--text-dim); font-family: var(--mono); }

/* --------------------------------------------------------------------------
   Small shared utilities. Kept short on purpose: a utility framework grown in a
   stylesheet nobody owns is how the next page ends up with its own.
   -------------------------------------------------------------------------- */

.stack { display: flex; flex-direction: column; gap: 12px; }
.row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dim { color: var(--text-dim); }
.faint { color: var(--text-faint); }
.small { font-size: 12px; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.card { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; }
.notice {
  border: 1px solid var(--border-strong); background: var(--panel-2);
  border-left: 3px solid var(--info); border-radius: var(--radius);
  padding: 11px 13px; font-size: 12.5px; color: var(--text-dim); line-height: 1.55;
}
.notice.warn { border-left-color: var(--warn); }
.kv { display: grid; grid-template-columns: max-content 1fr; gap: 6px 18px; font-size: 13px; }
.kv dt { color: var(--text-faint); font-size: 12px; }
.kv dd { color: var(--text); overflow-wrap: anywhere; }

/* ---------------------------------------------------------------------------
   Agent chat (the Invoke panel)

   WHY THIS EXISTS. The Invoke panel used to be a FORM with a log under it: the
   composer sat at the top, every answer was appended below it, and after three
   turns you scrolled UP past the whole conversation to type the fourth. The
   labels said "You" and "Agent" over two grey <pre> blocks, and the tool calls
   arrived as a table at the bottom of the card - so the one thing that makes
   this agent interesting, that it went and searched the docs before answering,
   read like an appendix.

   Talking to an agent is a conversation, so it is shaped like one: transcript
   above, composer FIXED at the bottom of the panel, newest turn in view, and
   the tools it reached for shown in the flow of the answer rather than under
   it.

   Everything here is scoped under .chat so it cannot leak into the ordinary
   card/stack layout the rest of the console uses.
   --------------------------------------------------------------------------- */

.chat {
  display: flex;
  flex-direction: column;
  /* Bounded, not page-length: the composer is pinned to the BOTTOM of this box,
     and a box that grows without limit puts it back off-screen - which is the
     whole complaint. 62vh leaves the page's own chrome visible so you never
     lose your place in the console. */
  height: 62vh;
  min-height: 380px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--panel);
  overflow: hidden;
}

.chat-scroll {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 16px 16px 8px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  scroll-behavior: smooth;
}

/* One exchange: the question, then everything the agent did to answer it. */
.chat-turn { display: flex; flex-direction: column; gap: 8px; }

.chat-msg {
  max-width: 78%;
  padding: 10px 13px;
  border-radius: 12px;
  line-height: 1.5;
  font-size: 13.5px;
  /* A model answer is prose with newlines and the occasional code fence. Wrap it
     like prose, keep the newlines, and never let a long token widen the panel. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.chat-msg.from-you {
  align-self: flex-end;
  background: var(--accent-soft);
  border: 1px solid rgba(255, 133, 82, .28);
  color: var(--text);
  border-bottom-right-radius: 4px;
}

.chat-msg.from-agent {
  align-self: flex-start;
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  border-bottom-left-radius: 4px;
}

.chat-msg.is-error {
  background: var(--err-soft);
  border-color: rgba(255, 93, 93, .3);
  color: #ffb3b3;
}

.chat-who {
  font-size: 11px;
  color: var(--text-faint);
  letter-spacing: .02em;
}
.chat-who.mine { align-self: flex-end; }

/* THE WORK, between the question and the answer, because that is when it
   happened. A tool call is not an appendix to the answer; it is the reason the
   answer is any good. */
.chat-work {
  align-self: flex-start;
  max-width: 88%;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 11px;
  border-left: 2px solid var(--accent);
  background: rgba(255, 255, 255, .02);
  border-radius: 0 8px 8px 0;
}

.chat-step {
  display: flex;
  gap: 8px;
  align-items: baseline;
  font-size: 12px;
}
.chat-step .tool {
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  color: var(--accent);
  flex: none;
}
.chat-step .detail {
  color: var(--text-dim);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  /* Bounded: a search tool's summary can be a page of retrieved text, and an
     unbounded one buries the answer that follows it. */
  max-height: 140px;
  overflow: auto;
}

.chat-aside { align-self: flex-start; max-width: 88%; }
.chat-aside > summary {
  font-size: 11.5px;
  color: var(--text-faint);
  cursor: pointer;
  padding: 2px 0;
}
.chat-aside[open] > summary { color: var(--text-dim); }

/* The composer, pinned. This is the whole point. */
.chat-composer {
  flex: none;
  border-top: 1px solid var(--border);
  background: var(--panel-2);
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.chat-composer textarea {
  width: 100%;
  min-height: 44px;
  max-height: 160px;
  resize: vertical;
  font-size: 13.5px;
}

.chat-composer .chat-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.chat-composer .chat-actions .spacer { flex: 1; }

/* A one-line status strip, so "it is thinking" and "it failed" appear where the
   eye already is - next to the button just pressed - instead of above a
   transcript that has scrolled. */
.chat-status { font-size: 11.5px; color: var(--text-faint); min-height: 1em; }
.chat-status.is-error { color: #ffb3b3; }

/* The session strip. Small, always visible, because which conversation you are
   in changes what the agent remembers - and on somebody else's session it
   changes whose history you are writing to. */
.chat-session {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 11.5px;
  color: var(--text-faint);
}
.chat-session input { font-size: 12px; padding: 3px 7px; min-width: 220px; }

/* A session someone else owns, opened read-only. The bar is deliberately loud:
   the difference between reading a customer's conversation and appending to it
   is invisible otherwise. */
.chat-readonly {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 8px 12px;
  background: var(--warn-soft);
  border-bottom: 1px solid rgba(255, 200, 87, .3);
  color: var(--warn);
  font-size: 12px;
}
.chat-readonly .grow { flex: 1; }

/* THE CLONE BAR IS NOT A WARNING. Same strip, opposite message: the amber bar
   above says "this belongs to someone else, be careful", and this one says
   "this copy is yours, break it". Colouring both amber taught operators to
   dismiss the colour, which is the one thing the amber bar needs them not to
   do. */
/* THE STREAMING CARET. A bubble that is still being written gets a blinking
   block after its last character, which is the one signal that separates "still
   thinking" from "that was the whole answer". Drawn with ::after so it costs no
   node and cannot end up inside a text selection or a copy. */
.chat-msg.is-streaming::after {
  content: "\u258B";
  margin-left: 1px;
  opacity: .75;
  animation: chat-caret 1.05s steps(2, start) infinite;
}

@keyframes chat-caret {
  0%, 49%   { opacity: .75; }
  50%, 100% { opacity: 0; }
}

/* A caret that blinks forever is worse than none for anyone who set
   prefers-reduced-motion: it is a persistent moving element, not a transition.
   Keep the mark, drop the animation. */
@media (prefers-reduced-motion: reduce) {
  .chat-msg.is-streaming::after { animation: none; opacity: .55; }
}

.chat-readonly.is-clone {
  background: var(--accent-soft);
  border-bottom: 1px solid var(--border);
  color: var(--fg-dim);
}

@media (max-width: 720px) {
  .chat { height: 70vh; }
  .chat-msg { max-width: 92%; }
}

/* The rewind control, on the question it would take you back to.
   Hidden until the session is a copy: the API refuses a rewind on a live
   conversation, and an action that is going to be refused should not be on
   screen offering itself. */
.chat-turnbar { display: flex; justify-content: flex-end; }

.chat-rewind {
  background: none;
  border: 1px solid var(--border);
  color: var(--text-faint);
  font-size: 11px;
  padding: 1px 8px;
  border-radius: 999px;
  cursor: pointer;
  line-height: 1.6;
}
.chat-rewind:hover {
  color: var(--accent);
  border-color: rgba(255, 133, 82, .4);
  background: var(--accent-soft);
}

/* Files a tool produced during a turn (CAI.toolfiles): images inline, the rest
   as downloads. Sits under the tool step it belongs to. */
.chat-files { display: flex; flex-wrap: wrap; gap: 10px; margin: 6px 0 2px 0; align-items: flex-start; }
.chat-file { display: flex; flex-direction: column; gap: 4px; max-width: 100%; }
.chat-file-img { max-width: min(100%, 460px); max-height: 340px; border-radius: 6px; border: 1px solid var(--border, #333); background: #fff; }

