/* Qubis OS — dashboard, memory, settings, the shared modal, onboarding and auth.
   Split out of style.css on 2026-09-10; see the header there for the seam and
   why the <link> order in index.html is load-bearing. */

/* ---------- dashboard ---------- */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 14px; }
.stat-card { background: var(--color-surface); border-radius: var(--radius-md); box-shadow: var(--shadow-sm); padding: 18px; animation: fadeUp 0.5s ease both; }
.stat-card-label { font-size: 12px; color: var(--color-neutral-400); display: flex; align-items: center; gap: 7px; }
.stat-card-label i { color: var(--color-accent-300); }
.stat-card-value { font-size: 24px; font-weight: 500; margin-top: 8px; letter-spacing: -0.01em; font-family: var(--font-heading); }
.stat-card-detail { font-size: 12px; color: var(--color-neutral-500); margin-top: 8px; line-height: 1.55; }
/* A card that navigates: the same card, but a <button>, so the reset below is
   the whole difference between the two. */
.stat-card-link { border: none; text-align: left; width: 100%; font: inherit; color: inherit; cursor: pointer; }
.stat-card-link:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }

.panel { background: var(--color-surface); border-radius: var(--radius-md); box-shadow: var(--shadow-sm); padding: 20px; }
.panel-title { font-size: 13px; font-weight: 500; margin-bottom: 14px; }
/* A panel that can be shut is <details class="panel"> with the title as its
   <summary> — the Agents tab (index.html) and the follow-ups list
   (automations.js). Shut, the title is the entire card, and the margin it
   carries to separate it from content there is none of doubles the card's own
   padding; so it only applies while there is something below it. */
details.panel > summary.panel-title { cursor: pointer; }
details.panel:not([open]) > summary.panel-title { margin-bottom: 0; }
.panel-note { font-size: 13px; color: var(--color-neutral-500); margin: -4px 0 12px; line-height: 1.6; max-width: 68ch; }

.routing-bars { display: flex; flex-direction: column; gap: 12px; }
.routing-bar-row { display: flex; align-items: center; gap: 10px; }
.routing-bar-label { width: 140px; font-size: 12.5px; color: var(--color-neutral-300); flex-shrink: 0; }
.routing-bar-track { flex: 1; height: 6px; border-radius: 3px; background: color-mix(in srgb, var(--color-text) 8%, transparent); overflow: hidden; }
/* The allowance row's figure is "$41.20 / $25.00", not "21%": the generic
   percentage column wrapped it onto three lines. */
.meter-allowance .routing-bar-pct { white-space: nowrap; min-width: max-content; }
.meter-over { margin: 8px 0; padding: 8px 10px; border-radius: var(--radius-sm); font-size: 12px; line-height: 1.45; background: color-mix(in srgb, var(--warn) 12%, var(--color-surface)); border: 1px solid color-mix(in srgb, var(--warn) 45%, transparent); }
.routing-bar-fill { height: 100%; border-radius: 3px; background: linear-gradient(90deg, var(--color-accent-700), var(--color-accent)); transition: width 0.6s ease; }
.routing-bar-pct { width: 40px; text-align: right; font-size: 12.5px; color: var(--color-neutral-400); }

/* ---------- memory (memory.js) ---------- */
.memory-toolbar { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.memory-toolbar > input[type="search"] { flex: 1 1 260px; max-width: 460px; }
.memory-list { display: flex; flex-direction: column; gap: 10px; }
.memory-item {
  display: flex; gap: 14px; align-items: flex-start; background: var(--color-surface); border: 1px solid var(--color-divider);
  border-radius: var(--radius-md); padding: 14px 16px; animation: msgIn 0.25s ease both;
}
.memory-item-main { min-width: 0; flex: 1; }
.memory-item-subject { font-weight: 500; font-size: 14.5px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.memory-item-content { color: var(--color-neutral-300); font-size: 13.5px; margin-top: 4px; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }
.memory-item-meta { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 8px; font-size: 12px; color: var(--color-neutral-500); }
.memory-item-actions { display: flex; gap: 6px; align-items: center; flex: none; }
.memory-item-actions .icon-btn-flat { width: 30px; height: 30px; padding: 0; font-size: 16px; }
/* Compaction's summaries, folded: long, system-written, rarely what a person came for. */
.memory-summaries { margin-top: 6px; }
.memory-summaries > summary { cursor: pointer; font-size: 13px; color: var(--color-neutral-400); padding: 6px 0; }
.memory-summaries .memory-item { margin-top: 8px; }
/* App-wide, not the memory page's: every list that can come back empty uses it. */
.empty-state { color: var(--color-neutral-500); font-size: 14px; padding: 30px; text-align: center; }

/* ---------- settings ---------- */
.demo-banner {
  background: color-mix(in srgb, var(--warn) 10%, transparent); border: 1px solid color-mix(in srgb, var(--warn) 30%, transparent);
  color: var(--warn); padding: 10px 14px; border-radius: var(--radius-md); font-size: 12.5px; margin-bottom: 14px;
}
.connector-notice { background: color-mix(in srgb, var(--signal) 10%, transparent); border-color: color-mix(in srgb, var(--signal) 30%, transparent); color: var(--signal); }
.connector-notice.error { background: color-mix(in srgb, var(--warn) 10%, transparent); border-color: color-mix(in srgb, var(--warn) 30%, transparent); color: var(--warn); }

.org-info { display: flex; flex-direction: column; }
.org-info-row { display: flex; padding: 8px 0; border-bottom: 1px solid var(--color-divider); font-size: 14px; }
.org-info-row:last-child { border-bottom: none; }
.org-info-value { margin-left: auto; text-align: right; }
.org-info-label { width: 150px; color: var(--color-neutral-400); flex-shrink: 0; }

.connector-grid { display: flex; flex-direction: column; gap: 10px; }
.connector-card { display: flex; align-items: center; gap: 12px; border: 1px solid var(--color-divider); border-radius: var(--radius-md); padding: 12px 14px; }
.connector-check { font-size: 20px; width: 20px; text-align: center; flex-shrink: 0; }
.connector-check.yes { color: var(--signal); }
.connector-check.no { color: var(--color-neutral-500); }
/* The built-in sample connector: its own state on purpose — never the green
   check, which is reserved for a real account (settings.js renderConnectors). */
.connector-check.sample { color: var(--color-accent); }
.connector-badge {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em; margin-left: 8px;
  padding: 1px 6px; border-radius: 999px; vertical-align: 1px;
  color: var(--color-accent); border: 1px solid color-mix(in srgb, var(--color-accent) 45%, transparent);
}
/* Where a Connect button would sit, for the types whose real connector is not
   built or still behind vendor review: a label, not a control — an empty slot
   there reads as a broken screen, a dead button would be worse. */
.connector-coming-soon { font-size: 11.5px; color: var(--color-neutral-500); flex-shrink: 0; white-space: nowrap; }
/* The live "does it still work" line under a connected card, filled in by
   verifyConnectorHealth(): neutral while asking, green when the vendor said
   yes, warn when it said no. */
.connector-health { font-size: 11.5px; color: var(--color-neutral-500); margin-top: 2px; }
.connector-health.ok { color: var(--signal); }
.connector-health.bad { color: var(--warn); }
.connector-card-main { min-width: 0; flex: 1; }
.connector-card-name { font-size: 13.5px; }
.connector-card-detail { font-size: 11.5px; color: var(--color-neutral-500); margin-top: 1px; }
/* A plan's price beside its name (billing.js). */
.plan-price { font-weight: 500; margin-left: 6px; }

/* The right-hand end of a plan or invoice row: badge, and whatever acts on it. */
.plan-row-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.invoice-links { display: flex; gap: 6px; }

.provider-table { display: flex; flex-direction: column; gap: 10px; }

.provider-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; font-size: 14px; }
.provider-row label { display: flex; align-items: center; gap: 12px; cursor: pointer; flex: 1; min-width: 0; }
.provider-row input[type="checkbox"] { accent-color: var(--color-accent); width: 16px; height: 16px; flex: none; }
.provider-row select {
  background: transparent; color: var(--color-text); border: 1px solid var(--color-divider);
  border-radius: 6px; padding: 5px 8px; font-size: 12.5px;
}
.provider-active-badge, .badge-pill {
  font-size: 11px; border-radius: 999px; padding: 3px 10px; border: 1px solid var(--color-divider); color: var(--color-neutral-400); flex: none;
}
.provider-active-badge.yes, .badge-pill.yes { border-color: color-mix(in srgb, var(--signal) 55%, transparent); color: var(--signal); }
/* The key-check verdict is a sentence from the vendor, not a label: block-level
   on its own line so it wraps under the provider instead of running into the
   jurisdiction text and crushing the badge column. :empty keeps the unclicked
   state from reserving a blank line. The button and badge never wrap — a
   two-line "Check / key" reads as two controls. */
.provider-row > span:first-child { flex: 1; min-width: 0; }
[data-key-check] { white-space: nowrap; }
.provider-active-badge { white-space: nowrap; }
.provider-check-result { display: block; margin-top: 4px; max-width: 60ch; }
.provider-check-result:empty { display: none; }

/* ---------- modal (core.js notice()/ask()) ---------- */
/* Above the auth and onboarding overlays (z-index 100): the credential forms
   inside onboarding raise these dialogs, so the answer must be able to sit on
   top of the question. */
.modal-overlay {
  position: fixed; inset: 0; z-index: 110;
  display: flex; align-items: center; justify-content: center; padding: 24px;
  background: color-mix(in srgb, var(--color-bg) 55%, transparent);
}
.modal-card {
  width: 400px; max-width: 90vw; background: var(--color-surface);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-md);
  padding: 22px 24px 18px; animation: fadeUp 0.25s ease both;
}
/* pre-line: the migrated confirm() strings carry \n\n paragraph breaks, and
   the message arrives as textContent (server error strings must never become
   markup), so the whitespace is all the formatting there is. */
.modal-body { margin: 0; font-size: 14px; line-height: 1.55; white-space: pre-line; overflow-wrap: anywhere; }
.modal-actions { display: flex; align-items: center; justify-content: flex-end; gap: 16px; margin-top: 18px; }
.modal-input { width: 100%; margin: 4px 0 14px; font-size: 14px; }
.modal-actions .modal-btn { padding: 8px 18px; font-size: 14px; }
@media (prefers-reduced-motion: reduce) { .modal-card { animation: none; } }

/* ---------- drawer (core.js openDrawer()) ---------- */
/* Detail beside a list rather than on top of it: slides in from the right
   over a dimmed page, so the list is untouched when it closes. Same z-band as
   the modal, which can still sit on top (a confirm raised from inside). */
.drawer-overlay {
  position: fixed; inset: 0; z-index: 105; display: flex; justify-content: flex-end;
  background: color-mix(in srgb, var(--color-bg) 45%, transparent);
}
.drawer {
  width: min(560px, 92vw); height: 100%; overflow-y: auto; display: flex; flex-direction: column;
  background: var(--color-surface); border-left: 1px solid var(--color-divider); box-shadow: var(--shadow-lg);
  animation: drawerIn 0.22s ease both;
}
@keyframes drawerIn { from { transform: translateX(24px); opacity: 0; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .drawer { animation: none; } }
.drawer-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; padding: 18px 20px 12px; border-bottom: 1px solid var(--color-divider); }
.drawer-heading { min-width: 0; }
.drawer-title { font-size: 16px; font-weight: 500; line-height: 1.35; overflow-wrap: anywhere; }
.drawer-subtitle { font-size: 12.5px; color: var(--color-neutral-400); margin-top: 3px; }
.drawer-close { flex: none; width: 32px; height: 32px; padding: 0; border-radius: 8px; font-size: 18px; }
.drawer-body { padding: 16px 20px 24px; font-size: 14px; }

/* ---------- onboarding + auth ---------- */
.onboarding-overlay, .auth-overlay {
  position: fixed; inset: 0; z-index: 100;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 24px;
  background: var(--color-bg);
}
.auth-overlay { overflow-y: auto; padding: 32px 0; justify-content: safe center; animation: fadeUp 0.5s ease both; }
/* Same overflow treatment as .auth-overlay directly above, for the same
   reason: a step taller than the viewport (byok's vendor cards) would
   otherwise centre-clip at both ends with nothing to scroll. "safe center"
   keeps short steps centred and lets tall ones scroll from the top. */
.onboarding-overlay { overflow-y: auto; padding: 32px 0; justify-content: safe center; }
.auth-hero { text-align: center; position: relative; z-index: 1; }
.auth-title { font-size: 30px; font-weight: 500; letter-spacing: -0.015em; }
.auth-tagline { font-size: 15px; margin-top: 4px; }
.auth-card {
  position: relative; z-index: 1; width: 400px; max-width: 90vw; background: var(--color-surface); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md); padding: 28px; display: flex; flex-direction: column; gap: 14px;
}
.auth-footnote { position: relative; z-index: 1; font-size: 12px; }
/* Legal links: auth overlay footer and the end of the Settings page. The
   pages themselves live in public/legal/ (source of truth: the root *.md). */
.legal-links { font-size: 12px; margin-bottom: 24px; }
.auth-footnote a, .legal-links a {
  color: color-mix(in srgb, var(--color-text) 55%, transparent); text-decoration: none;
}
.auth-footnote a:hover, .legal-links a:hover { color: var(--color-text); }

/* 580px, not 440: the wizard grid gives 132px + gap to Qubis (the figure), and the fields
   were living in what was left. max-width keeps phones unaffected. */
.onboarding-card {
  width: 580px; max-width: 90vw; background: var(--color-surface); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md); padding: 28px 28px 20px; animation: fadeUp 0.4s ease both;
}
.onboarding-logo { display: flex; align-items: center; gap: 12px; margin-bottom: 22px; font-size: 15px; font-weight: 500; }
.onboarding-step h2 { font-size: 20px; margin: 0 0 6px; }
.onboarding-step p { font-size: 13.5px; color: var(--color-neutral-400); margin: 0 0 20px; line-height: 1.5; }
.field { display: flex; flex-direction: column; gap: 6px; font-size: 13px; color: var(--color-neutral-400); }
.field-input, .onboarding-step input, .onboarding-step select, .onboarding-step textarea {
  width: 100%; background: transparent; border: 1px solid var(--color-divider); color: var(--color-text);
  padding: 10px 12px; border-radius: var(--radius-md); font-size: 15px; outline: none; margin-bottom: 0;
  font-family: var(--font-body); resize: vertical;
}
.field-input:focus, .onboarding-step input:focus, .onboarding-step select:focus, .onboarding-step textarea:focus { border-color: var(--color-accent); }
.onboarding-step input, .onboarding-step select { margin-bottom: 12px; }
.chip-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  background: transparent; border: 1px solid var(--color-divider); color: var(--color-text);
  border-radius: 999px; padding: 8px 16px; font-size: 14px;
}
.chip.selected { background: color-mix(in srgb, var(--color-accent) 16%, transparent); border-color: var(--color-accent); }
.onboarding-connector-row {
  display: flex; align-items: center; justify-content: space-between; padding: 8px 10px;
  border: 1px solid var(--color-divider); border-radius: var(--radius-md); font-size: 12.5px; margin-bottom: 6px;
}
.onboarding-actions { display: flex; align-items: center; justify-content: space-between; margin-top: 26px; }
/* The workspace address on the company step (queue item 2(a)): the fixed
   prefix and the editable part read as one address. */
.onboarding-address { display: block; margin-top: 14px; }
.onboarding-address-row { display: flex; align-items: center; gap: 4px; margin-top: 6px; }
.onboarding-address-row input { flex: 1; min-width: 0; }
.onboarding-address-note { display: block; margin-top: 6px; font-size: 0.85em; }
.onboarding-error { color: var(--danger, #c0392b); margin-top: 8px; font-size: 0.9em; }
.onboarding-dots { display: flex; gap: 6px; }
.onboarding-dot { width: 7px; height: 7px; border-radius: 50%; background: color-mix(in srgb, var(--color-text) 18%, transparent); }
.onboarding-dot.active { background: var(--color-accent); }
.btn-outline-accent {
  background: transparent; border: 1px solid var(--color-accent); color: var(--color-accent-300);
  border-radius: var(--radius-md); padding: 11px 22px; font-size: 15px; font-weight: 500;
}
.btn-outline-accent:hover:not(:disabled) { background: color-mix(in srgb, var(--color-accent) 12%, transparent); }
.btn-text {
  background: transparent; border: none; color: var(--color-neutral-400); font-size: 14px; padding: 8px 0;
  /* Underlined at rest: muted text with no decoration reads as a caption,
     and some of these
     ("Take me in", "Get a key ↗") are the only way forward. The offset and
     translucent decoration keep it quiet. cursor here too — the global
     button rule does not cover the <a class="btn-text"> variants. */
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
}
.btn-text:hover { color: var(--color-text); text-decoration-color: currentColor; }
.auth-error {
  background: color-mix(in srgb, var(--warn) 12%, transparent); color: var(--warn);
  border: 1px solid color-mix(in srgb, var(--warn) 30%, transparent); border-radius: var(--radius-md);
  padding: 8px 11px; font-size: 12px; line-height: 1.45;
}

/* Stock page (public/inventory.js) */
.stock-forms { display: flex; flex-direction: column; gap: 12px; margin-top: 16px; }
.stock-form { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.stock-form strong { flex-basis: 100%; }
.stock-form .input { flex: 1 1 10em; }
.stock-low td:first-child { font-weight: 600; }
.stock-lines, .stock-history { padding-left: 1.2em; margin: 8px 0 16px; }

/* ---------- tables and small chips (shared) ---------- */
/* One table look for the pages that draw one (Contacts, Stock, Revenue,
   Voices). Until 2026-09-12 each carried class="table" and no rule existed. */
.table-wrap { overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.table th { text-align: left; font-weight: 500; font-size: 12px; color: var(--color-neutral-400); padding: 8px 10px; border-bottom: 1px solid var(--color-divider); white-space: nowrap; }
.table td { padding: 9px 10px; border-bottom: 1px solid color-mix(in srgb, var(--color-divider) 60%, transparent); vertical-align: middle; }
.table tr:last-child td { border-bottom: none; }
.chip-small { font-size: 11px; padding: 1px 7px; }
.revenue-total { margin-right: 14px; }
/* A credential paste form under a connector card (core.js credentialForm). */
.connector-credential { margin-top: 6px; font-size: 12.5px; }
.connector-credential > summary { cursor: pointer; color: var(--color-accent-300); }

/* Standing approvals on the automation form (2026-09-19). */
.standing-approvals { margin: 14px 0; }
.standing-title { font-weight: 600; margin-bottom: 4px; }
.standing-row { display: block; margin-top: 6px; cursor: pointer; }

/* The package panel's feature chips (2026-09-19): a wrapping list, not one long line. */
.provider-row-top { align-items: flex-start; }
.feature-chips { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; }
.feature-chip { display: inline-block; padding: 2px 8px; border-radius: 999px; background: var(--surface-2, rgba(127,127,127,.12)); font-size: 12px; }
.feature-chip-muted { opacity: .75; }

/* The activity feed on the overview (42.3): a run is a row, its trace opens under it. */
.activity-row { cursor: pointer; }
.activity-trace { padding: 6px 12px 10px 24px; border-left: 2px solid var(--surface-2, rgba(127,127,127,.25)); margin: 0 0 8px 8px; font-size: 13px; }
