/* ==========================================================================
   RoundBase — operations analytics for waste & recycling
   Design system: "Aurora" — dawn over the depot yard.

   An atmospheric colour field (petrol/teal into the brand blue, one ember
   note where the sun comes up) sits behind frosted-glass panels; the numbers
   themselves stay sober. Two genuinely designed themes switched by
   data-theme on <html>: the dark primary, and a "glass morning" light.

   - Brand: the logo gradient, blue #4098d0 → teal #58c0c8. It carries the
     mark, primary actions and active states — never large fills.
   - State means state: green = healthy, amber = attention, coral = failed.
     Shape and label carry it; colour supports.
   - Display type is Bricolage Grotesque; text and data are Public Sans with
     tabular figures. Both self-hosted from /static/fonts.
   ========================================================================== */

@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 400 800;
  font-stretch: 100%;
  font-display: swap;
  src: url("/fonts/bricolage-grotesque-latin-var.woff2") format("woff2");
}

@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/public-sans-latin-var.woff2") format("woff2");
}

/* --------------------------------------------------------------------------
   1. TOKENS
   -------------------------------------------------------------------------- */

:root,
[data-theme="dark"] {
  /* dawn over the depot, grown from the logo: petrol/teal into the brand
     blue, with one restrained ember note low on the right */
  --sky:
    radial-gradient(1180px 700px at 8% -12%, rgba(18, 90, 100, 0.95), transparent 64%),
    radial-gradient(1080px 640px at 76% -14%, rgba(46, 122, 188, 0.92), transparent 62%),
    radial-gradient(1000px 420px at 46% -4%, rgba(88, 192, 200, 0.34), transparent 66%),
    radial-gradient(760px 340px at 97% 12%, rgba(172, 92, 46, 0.30), transparent 68%);
  --horizon: linear-gradient(90deg, transparent, rgba(64, 152, 208, 0.55) 20%, rgba(88, 192, 200, 0.85) 50%, rgba(120, 176, 214, 0.5) 78%, transparent);
  --grain-op: 0.045;

  --canvas: #071417;
  --glass: rgba(226, 244, 248, 0.052);
  --glass-2: rgba(226, 244, 248, 0.085);
  --glass-line: rgba(226, 244, 248, 0.13);
  --glass-line-2: rgba(226, 244, 248, 0.07);
  --glass-solid: #0f1e22;
  --glass-well: #0c181c;
  --glass-top: rgba(255, 255, 255, 0.10);
  --header-veil: rgba(7, 20, 23, 0.72);

  --ink: #eaf2f4;
  --ink-2: #a2b6ba;
  --ink-3: #87999e;

  --accent: #5cb8e8;
  --accent-2: #58c0c8;
  --accent-soft: rgba(92, 184, 232, 0.16);
  --accent-line: rgba(92, 184, 232, 0.36);
  --accent-ring: rgba(92, 184, 232, 0.22);
  --on-accent: #08161f;

  --good: #46d97c;
  --good-soft: rgba(70, 217, 124, 0.14);
  --good-line: rgba(70, 217, 124, 0.32);
  --crit: #ff7b7b;
  --crit-soft: rgba(255, 123, 123, 0.15);
  --crit-line: rgba(255, 123, 123, 0.32);
  --attn: #f0b44e;
  --attn-soft: rgba(240, 180, 78, 0.15);
  --attn-line: rgba(240, 180, 78, 0.34);

  --ramp-1: #a8def0;
  --ramp-2: #74c4e2;
  --ramp-3: #4e9dc8;
  --ramp-4: #37749e;

  --glow-kpi: 0 0 34px rgba(88, 192, 200, 0.34);
  --glow-btn: 0 8px 22px -12px rgba(88, 192, 200, 0.6);
  --lift: 0 18px 44px -22px rgba(0, 0, 0, 0.85);
  --lift-hi: 0 26px 60px -24px rgba(0, 0, 0, 0.9);

  color-scheme: dark;
}

[data-theme="light"] {
  /* the same dawn, an hour later: frost and pale brand sky, sun still low right */
  --sky:
    radial-gradient(1180px 700px at 8% -12%, rgba(152, 209, 212, 0.85), transparent 64%),
    radial-gradient(1080px 640px at 76% -14%, rgba(158, 202, 236, 0.92), transparent 62%),
    radial-gradient(1000px 420px at 46% -4%, rgba(214, 240, 242, 0.95), transparent 66%),
    radial-gradient(760px 340px at 97% 12%, rgba(255, 212, 172, 0.55), transparent 68%);
  --horizon: linear-gradient(90deg, transparent, rgba(31, 110, 159, 0.45) 20%, rgba(47, 154, 162, 0.7) 50%, rgba(31, 110, 159, 0.4) 78%, transparent);
  --grain-op: 0.028;

  --canvas: #e9f1f4;
  --glass: rgba(255, 255, 255, 0.62);
  --glass-2: rgba(255, 255, 255, 0.80);
  --glass-line: rgba(255, 255, 255, 0.92);
  --glass-line-2: rgba(14, 42, 52, 0.11);
  --glass-solid: #f5f9fb;
  --glass-well: #eaf2f5;
  --glass-top: rgba(255, 255, 255, 0.9);
  --header-veil: rgba(233, 241, 244, 0.78);

  --ink: #0e1f24;
  --ink-2: #42585e;
  --ink-3: #566c72;

  --accent: #1a6c9c;
  --accent-2: #0f7a80;
  --accent-soft: rgba(26, 108, 156, 0.10);
  --accent-line: rgba(26, 108, 156, 0.32);
  --accent-ring: rgba(26, 108, 156, 0.18);
  --on-accent: #ffffff;

  --good: #137a45;
  --good-soft: rgba(19, 122, 69, 0.10);
  --good-line: rgba(19, 122, 69, 0.30);
  --crit: #c0392f;
  --crit-soft: rgba(192, 57, 47, 0.10);
  --crit-line: rgba(192, 57, 47, 0.30);
  --attn: #8a5d0a;
  --attn-soft: rgba(138, 93, 10, 0.11);
  --attn-line: rgba(138, 93, 10, 0.32);

  --ramp-1: #0f4263;
  --ramp-2: #1c6892;
  --ramp-3: #3d93bd;
  --ramp-4: #72b9d6;

  --glow-kpi: none;
  --glow-btn: 0 8px 20px -12px rgba(15, 122, 128, 0.45);
  --lift: 0 16px 40px -24px rgba(14, 42, 52, 0.40);
  --lift-hi: 0 24px 54px -26px rgba(14, 42, 52, 0.48);

  color-scheme: light;
}

:root {
  --display: "Bricolage Grotesque", "Trebuchet MS", Verdana, sans-serif;
  --body: "Public Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;

  --rad: 18px;
  --rad-m: 12px;
  --rad-sm: 10px;

  --shell-max: 1240px;

  --ease: 160ms ease;
  --ease-slow: 240ms cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* --------------------------------------------------------------------------
   2. BASE
   -------------------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--body);
  font-size: 14.5px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* The colour field is anchored to the top of the document, not the viewport:
   dawn belongs over the header, and the data below it stays on a calm surface. */
.sky {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1240px;
  z-index: 0;
  background: var(--sky);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 52%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0%, #000 52%, transparent 100%);
  pointer-events: none;
}

.sky::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: var(--grain-op);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

.app-root {
  position: relative;
  z-index: 1;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.hidden {
  display: none !important;
}

a {
  color: inherit;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 6px;
}

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

* {
  scrollbar-color: var(--accent-line) transparent;
  scrollbar-width: thin;
}

/* --------------------------------------------------------------------------
   3. GLASS PRIMITIVES
   --------------------------------------------------------------------------
   Two surface depths. Panels are the frosted-glass cards that float on the
   sky (backdrop blur, lift shadow, inset top light). Wells are inset
   surfaces that sit ON a panel — a flat tint, never a second blur. */

.login-card,
.card,
.metric-card,
.mini,
.panel,
.dash-thumb-card,
.dataset-table-wrap {
  position: relative;
  border-radius: var(--rad);
  background: var(--glass);
  border: 1px solid var(--glass-line-2);
  -webkit-backdrop-filter: blur(22px) saturate(1.55);
  backdrop-filter: blur(22px) saturate(1.55);
  box-shadow: var(--lift), inset 0 1px 0 var(--glass-top);
}

@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {

  .login-card,
  .card,
  .metric-card,
  .mini,
  .panel,
  .dash-thumb-card,
  .dataset-table-wrap {
    background: var(--glass-solid);
  }
}

.pipeline-card,
.chat-shell,
.dq-check-card,
.dq-unavailable {
  background: var(--glass-2);
  border: 1px solid var(--glass-line-2);
  border-radius: var(--rad-m);
}

/* --------------------------------------------------------------------------
   4. TYPE & TEXT STATES
   -------------------------------------------------------------------------- */

.loading-text,
.empty-text {
  font-size: 13px;
  color: var(--ink-3);
  padding: 14px 2px;
}

.error-text {
  font-size: 13px;
  color: var(--crit);
  padding: 14px 2px;
}

/* The export's status line sits under the toolbar buttons, in the same
   right-anchored column (.dataset-tools). Anchored right so it stays with the
   button it answers; text left-aligned inside a bounded box so a three-line
   notice reads as a paragraph and not as a ragged right-aligned block. */
#exportStatus {
  padding: 0;
  max-width: 440px;
  line-height: 1.5;
  text-align: left;
}

/* The same line reports a refusal (a bad filter, a failed start, nothing fits)
   and the offer of the first N rows that do fit. The offer is not an error, so
   it drops the critical colour for the muted text tone the rest of the toolbar
   uses. ID + class, so it beats .error-text. */
#exportStatus.export-status-info {
  color: var(--ink-3);
}

.loading-container {
  padding: 22px 2px;
}

.animate-pulse {
  font-size: 13px;
  color: var(--ink-3);
  animation: rb-pulse 1.6s ease-in-out infinite;
}

@keyframes rb-pulse {

  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0.45;
  }
}

/* --------------------------------------------------------------------------
   5. BUTTONS & SMALL CONTROLS
   -------------------------------------------------------------------------- */

/* Primary — the brand gradient pill. Dark petrol ink on it in the dark
   theme, white in the light one; both pairs clear AA.
   NOTE: .ai-run-btn is the RUNNABLE agent's CTA, rendered from /api/agents
   (it used to be #runDQChecksBtn, a static id). The quiet ghost styling below
   is for the coming-soon tiles, which carry .ai-run-btn-ghost. */
.login-btn,
.ai-run-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--body);
  font-size: 14px;
  font-weight: 600;
  color: var(--on-accent);
  background: linear-gradient(148deg, var(--accent-2), var(--accent));
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 12px 20px;
  cursor: pointer;
  white-space: nowrap;
  box-shadow: var(--glow-btn);
  transition: filter var(--ease), transform var(--ease), box-shadow var(--ease);
}

.login-btn {
  width: 100%;
  margin-top: 16px;
}

.ai-run-btn {
  font-size: 12.5px;
  padding: 8px 15px;
}

.login-btn:hover,
.ai-run-btn:hover {
  filter: brightness(1.07);
  transform: translateY(-1px);
}

.login-btn:active,
.ai-run-btn:active {
  transform: none;
}

.login-btn:disabled,
.ai-run-btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
  filter: none;
}

.btn-arrow {
  font-size: 13px;
  line-height: 1;
  transition: transform var(--ease);
}

.login-btn:hover .btn-arrow,
.btn-text-link:hover .btn-arrow {
  transform: translateX(3px);
}

/* Ghost — quiet glass buttons (header icons, Export, Copy, admin actions,
   chat send). NOTE: .ai-run-btn is deliberately NOT here — the runnable
   agent's CTA is the primary pill above; the coming-soon tiles render a
   badge, not a button. */
.logout-btn,
.export-btn,
.chat-send-btn,
.admin-action-btn,
.dq-export-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  font-family: var(--body);
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ink-2);
  background: var(--glass-2);
  border: 1px solid var(--glass-line-2);
  border-radius: 999px;
  padding: 7px 14px;
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--ease), background var(--ease), border-color var(--ease);
}

.logout-btn:hover,
.export-btn:hover,
.chat-send-btn:hover,
.admin-action-btn:hover,
.dq-export-btn:hover {
  color: var(--ink);
  border-color: var(--glass-line);
}

[data-theme="light"] .logout-btn:hover,
[data-theme="light"] .export-btn:hover,
[data-theme="light"] .chat-send-btn:hover,
[data-theme="light"] .admin-action-btn:hover,
[data-theme="light"] .dq-export-btn:hover {
  border-color: var(--accent-line);
}

.export-btn:disabled,
.admin-action-btn:disabled,
.chat-send-btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

/* The header's icon-only buttons are square glass tiles. */
.logout-btn.icon-only {
  width: 34px;
  height: 34px;
  padding: 0;
  border-radius: 11px;
}

.logout-btn.icon-only svg {
  width: 16px;
  height: 16px;
  display: block;
}

.admin-action-btn {
  font-size: 12px;
  padding: 5px 11px;
  margin-right: 5px;
  background: transparent;
}

.admin-action-btn:hover {
  background: var(--glass-2);
}

.admin-action-warn:hover {
  color: var(--crit);
  border-color: var(--crit-line);
  background: var(--crit-soft);
}

/* The DQ agent's "Not available" state — dashed, resting, no longer a button
   that promises anything. Written class+class so it outranks the primary
   .ai-run-btn gradient above. */
.ai-run-btn.ai-run-btn-disabled,
.ai-run-btn.ai-run-btn-disabled:hover {
  color: var(--ink-3);
  background: transparent;
  border: 1px dashed var(--glass-line);
  box-shadow: none;
  filter: none;
  transform: none;
  opacity: 1;
}

/* Text links */
.btn-text-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: none;
  padding: 2px;
  font-family: var(--body);
  font-size: 12.5px;
  font-weight: 500;
  color: var(--accent);
  cursor: pointer;
  transition: gap var(--ease);
}

.btn-text-link:hover {
  gap: 9px;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.link-small {
  background: none;
  border: none;
  padding: 2px;
  font-family: var(--body);
  font-size: 12.5px;
  color: var(--ink-2);
  text-decoration: underline;
  text-decoration-color: var(--glass-line);
  text-underline-offset: 3px;
  cursor: pointer;
  transition: color var(--ease);
}

.link-small:hover {
  color: var(--accent);
  text-decoration-color: var(--accent-line);
}

/* Chips — the pill-shaped labels (Fabric chip, workspace, dataset pills). */
.pill-cloud,
.lake-badge,
.dataset-pill,
.badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 28px;
  padding: 0 12px;
  border-radius: 999px;
  background: var(--glass);
  border: 1px solid var(--glass-line-2);
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-2);
  white-space: nowrap;
}

.live-dot,
.badge-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--good);
  box-shadow: 0 0 10px var(--good);
  flex: none;
}

/* --------------------------------------------------------------------------
   6. FORMS
   -------------------------------------------------------------------------- */

.field-group {
  margin-bottom: 16px;
}

.field-label {
  display: block;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ink-2);
  margin-bottom: 6px;
}

/* The one-line constraint under a data-entry input ("Between 0.5 and 3",
   "No future dates") — quieter than the label, read after the field. */
.field-hint {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 6px;
}

.text-input {
  width: 100%;
  font-family: var(--body);
  font-size: 14px;
  color: var(--ink);
  background: var(--glass-2);
  border: 1px solid var(--glass-line-2);
  border-radius: var(--rad-m);
  padding: 11px 14px;
  transition: border-color var(--ease), background var(--ease), box-shadow var(--ease);
}

.text-input::placeholder {
  color: var(--ink-3);
  opacity: 0.8;
}

.text-input:hover {
  border-color: var(--glass-line);
}

.text-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ring);
}

select.text-input {
  appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--ink-2) 50%),
    linear-gradient(135deg, var(--ink-2) 50%, transparent 50%);
  background-position:
    calc(100% - 19px) 50%,
    calc(100% - 14px) 50%;
  background-size: 5px 5px;
  background-repeat: no-repeat;
  padding-right: 36px;
  cursor: pointer;
}

.password-wrapper {
  position: relative;
}

.password-wrapper .text-input {
  padding-right: 40px;
}

.lock-icon {
  position: absolute;
  right: 13px;
  top: 50%;
  transform: translateY(-50%);
  width: 15px;
  height: 15px;
  color: var(--ink-3);
  pointer-events: none;
}

.lock-icon svg {
  width: 100%;
  height: 100%;
  display: block;
}

.field-sub {
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--ink-3);
  margin-top: 8px;
}

.form-success {
  color: var(--good);
  margin-bottom: 14px;
}

.login-error {
  font-size: 13px;
  line-height: 1.5;
  color: var(--crit);
  background: var(--crit-soft);
  border: 1px solid var(--crit-line);
  border-radius: var(--rad-m);
  padding: 10px 13px;
  margin-bottom: 16px;
}

.checkbox-row {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 13.5px;
  color: var(--ink-2);
  cursor: pointer;
}

.checkbox-row input {
  accent-color: var(--accent);
}

.admin-checkbox-row {
  margin: 4px 0 8px;
}

/* --------------------------------------------------------------------------
   7. BRAND
   -------------------------------------------------------------------------- */

.brand-mark {
  flex: none;
  display: grid;
  place-items: center;
  filter: drop-shadow(0 0 12px rgba(88, 192, 200, 0.45));
}

[data-theme="light"] .brand-mark {
  filter: none;
}

.brand-mark svg {
  display: block;
}

/* Each mark carries both theme strokes; only the current theme's shows. */
.mark-ring-light {
  display: none;
}

[data-theme="light"] .mark-ring-dark {
  display: none;
}

[data-theme="light"] .mark-ring-light {
  display: inline;
}

.brand-name {
  font-family: var(--display);
  font-weight: 700;
  letter-spacing: -0.028em;
  line-height: 1.1;
  color: var(--ink);
}

.brand-lockup {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.brand-byline,
.dash-brand-byline {
  font-size: 11.5px;
  color: var(--ink-3);
  line-height: 1.2;
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   8. LOGIN
   -------------------------------------------------------------------------- */

.login-wrapper {
  position: relative;
  width: 100%;
  max-width: 1120px;
  margin: auto;
  padding: 56px 28px 72px;
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: clamp(40px, 6vw, 88px);
  align-items: center;
}

.login-theme-btn {
  position: absolute;
  top: 24px;
  right: 28px;
  z-index: 2;
}

/* The set-password view (activation / reset links) reuses the login canvas but
   has no intro column — a single card, centred, at the login card's width. */
#setPasswordView.login-wrapper {
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
}

#setPasswordView .set-password-card {
  width: 100%;
  max-width: 440px;
}

.set-password-intro {
  margin-bottom: 20px;
}

.set-password-expired {
  margin-bottom: 18px;
}

.login-intro {
  min-width: 0;
  animation: rb-rise 0.72s cubic-bezier(0.2, 0.72, 0.2, 1) both;
}

.brand-pill {
  display: flex;
  align-items: center;
  gap: 13px;
  margin-bottom: 48px;
}

.brand-pill .brand-name {
  font-size: 22px;
}

.login-eyebrow,
.hero-eyebrow {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent-2);
  margin: 0 0 14px;
}

[data-theme="light"] .login-eyebrow,
[data-theme="light"] .hero-eyebrow {
  color: var(--accent);
}

.login-heading {
  font-family: var(--display);
  font-size: clamp(40px, 5.4vw, 62px);
  font-weight: 700;
  letter-spacing: -0.045em;
  line-height: 0.98;
  margin: 0 0 20px;
  color: var(--ink);
}

/* the second line carries the brand gradient (plain accent where unsupported) */
.login-heading span {
  color: var(--accent);
}

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .login-heading span {
    background: linear-gradient(100deg, var(--accent) 0%, var(--accent-2) 62%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}

.login-subtitle {
  max-width: 52ch;
  font-size: 15.5px;
  line-height: 1.65;
  color: var(--ink-2);
  margin: 0 0 36px;
}

/* Feature rows — quiet, under a horizon hairline */
.pill-grid {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 28px;
  padding-top: 4px;
}

.pill-grid::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 12%;
  height: 1px;
  background: var(--horizon);
}

.pill {
  padding: 16px 0 4px;
}

.pill-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 5px;
}

.pill-icon {
  display: inline-flex;
  width: 16px;
  height: 16px;
  color: var(--accent);
}

.pill-icon svg {
  width: 100%;
  height: 100%;
}

.pill-title {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
}

.pill-body {
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink-3);
}

/* Sign-in card — a glass panel with the horizon as its top edge. */
.login-card {
  padding: 30px 30px 26px;
  overflow: hidden;
  box-shadow: var(--lift-hi), inset 0 1px 0 var(--glass-top);
  animation: rb-rise 0.72s cubic-bezier(0.2, 0.72, 0.2, 1) 0.12s both;
}

.login-card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--horizon);
}

.login-card-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 24px;
}

.login-title {
  font-family: var(--display);
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.025em;
  color: var(--ink);
}

.login-card-header .badge {
  margin-top: 2px;
  height: 26px;
  font-size: 11.5px;
}

.login-footer-row {
  display: flex;
  justify-content: flex-end;
  margin: -4px 0 4px;
}

.login-note {
  display: flex;
  gap: 10px;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--ink-3);
  border-top: 1px solid var(--glass-line-2);
  margin-top: 22px;
  padding-top: 16px;
}

.note-icon {
  flex: none;
  width: 15px;
  height: 15px;
  margin-top: 3px;
  color: var(--accent);
}

.note-icon svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* --------------------------------------------------------------------------
   9. DASHBOARD SHELL
   -------------------------------------------------------------------------- */

.dash-root {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  width: 100%;
}

.dash-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--header-veil);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  backdrop-filter: blur(18px) saturate(1.4);
  border-bottom: 1px solid var(--glass-line-2);
}

.dash-header-inner {
  /* The bar spans the viewport — brand hard left, actions hard right — while
     the content below keeps the shell width. Constrained to the shell, the
     action icons floated oddly mid-screen on wide monitors. */
  max-width: none;
  padding: 0 28px;
  height: 64px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.dash-brand-row {
  display: flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
}

.brand-home-btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: none;
  border: 0;
  padding: 2px;
  cursor: pointer;
  border-radius: var(--rad-sm);
  transition: opacity var(--ease);
}

.brand-home-btn:hover {
  opacity: 0.82;
}

.brand-home-btn .brand-name {
  font-size: 17px;
}

.dash-brand-byline {
  padding-left: 11px;
  border-left: 1px solid var(--glass-line-2);
}

.dash-header-right {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: flex-end;
}

/* The Fabric pill is a status readout, not an action: a wider gap keeps it
   from reading as the first button of the icon group. */
.dash-header-right .pill-cloud {
  margin-right: 14px;
}

.dash-main {
  flex: 1;
}

.dash-main-inner {
  max-width: var(--shell-max);
  margin: 0 auto;
  padding: 30px 28px 72px;
}

.dash-foot {
  max-width: var(--shell-max);
  margin: 0 auto;
  width: 100%;
  padding: 22px 28px 28px;
  border-top: 1px solid var(--glass-line-2);
  font-size: 12px;
  color: var(--ink-3);
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

/* --------------------------------------------------------------------------
   10. HERO — greeting + luminous KPIs
   -------------------------------------------------------------------------- */

.hero {
  margin-bottom: 46px;
}

.horizon {
  height: 1px;
  background: var(--horizon);
  margin-bottom: 34px;
  position: relative;
  animation: rb-rise 0.72s cubic-bezier(0.2, 0.72, 0.2, 1) both;
}

.horizon::after {
  content: "";
  position: absolute;
  left: 12%;
  right: 12%;
  top: -12px;
  height: 24px;
  background: var(--horizon);
  filter: blur(12px);
  opacity: 0.55;
  pointer-events: none;
}

.hero .hero-eyebrow {
  animation: rb-rise 0.72s cubic-bezier(0.2, 0.72, 0.2, 1) 0.06s both;
}

.greeting-title {
  font-family: var(--display);
  font-size: clamp(36px, 5.4vw, 58px);
  font-weight: 700;
  letter-spacing: -0.045em;
  line-height: 1;
  margin: 0 0 14px;
  color: var(--ink);
  animation: rb-rise 0.72s cubic-bezier(0.2, 0.72, 0.2, 1) 0.1s both;
}

.greeting-sub {
  max-width: 60ch;
  font-size: 15.5px;
  line-height: 1.62;
  color: var(--ink-2);
  margin: 0 0 34px;
  animation: rb-rise 0.72s cubic-bezier(0.2, 0.72, 0.2, 1) 0.16s both;
}

.metrics-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.metric-card {
  padding: 18px 20px 16px;
  min-width: 0;
  animation: rb-rise 0.72s cubic-bezier(0.2, 0.72, 0.2, 1) both;
}

.metric-card:nth-child(1) {
  animation-delay: 0.24s;
}

.metric-card:nth-child(2) {
  animation-delay: 0.3s;
}

.metric-card:nth-child(3) {
  animation-delay: 0.36s;
}

.metric-card:nth-child(4) {
  animation-delay: 0.42s;
}

.metric-label {
  display: block;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-2);
  letter-spacing: 0.01em;
  margin-bottom: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.metric-main {
  font-family: var(--display);
  font-size: clamp(26px, 3.2vw, 36px);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.04em;
  line-height: 1.05;
  color: var(--ink);
  text-shadow: var(--glow-kpi);
  margin: 4px 0 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.metric-sub {
  font-size: 12px;
  color: var(--ink-3);
}

/* Section notices — amber, dismissible */
.section-notice {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--attn);
  background: var(--attn-soft);
  border: 1px solid var(--attn-line);
  border-radius: var(--rad-m);
  padding: 9px 12px;
  margin: 14px 0;
}

.hero .section-notice {
  max-width: 640px;
}

.section-notice-text {
  min-width: 0;
}

.notice-dismiss {
  flex: none;
  background: none;
  border: none;
  padding: 0 2px;
  font-size: 13px;
  line-height: 1;
  color: var(--attn);
  opacity: 0.7;
  cursor: pointer;
}

.notice-dismiss:hover {
  opacity: 1;
}

/* --------------------------------------------------------------------------
   11. CARDS & SECTION FURNITURE
   -------------------------------------------------------------------------- */

.card {
  padding: 20px 22px;
  min-width: 0;
}

.card-head-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.card-heading {
  font-family: var(--display);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--ink);
}

.card>.card-heading:first-child {
  display: block;
  margin-bottom: 6px;
}

.card-sub {
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink-3);
}

.section-head-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

/* Section furniture, Aurora-style: a display title on the page, the content
   in glass panels below — sections are not boxed. */
.sec {
  margin-bottom: 46px;
}

.sec-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}

.sec-title,
.ai-section-heading {
  font-family: var(--display);
  font-size: clamp(22px, 3vw, 28px);
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1.1;
  color: var(--ink);
  margin: 0;
}

.ai-section-heading {
  margin: 0 0 18px;
}

.section-head-row .ai-section-heading,
.admin-view-header .ai-section-heading {
  margin: 0;
}

.sec-note {
  margin: 0;
  font-size: 13px;
  color: var(--ink-3);
}

.stamp {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

.panel {
  overflow: hidden;
}

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 16px 22px;
  border-bottom: 1px solid var(--glass-line-2);
  flex-wrap: wrap;
}

.panel-title {
  margin: 0;
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--ink);
}

.panel-foot {
  padding: 14px 22px;
  border-top: 1px solid var(--glass-line-2);
  font-size: 12.5px;
  color: var(--ink-2);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

/* "Coming soon" chip (chat panel head; same voice as the agent rows' badge) */
.soon {
  flex: none;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 3px 9px;
  border: 1px solid var(--glass-line-2);
  border-radius: 999px;
  background: var(--glass-2);
  white-space: nowrap;
}

/* The health + datasets sections stack full-width, like the prototype. */
.grid-ops {
  display: block;
}

.grid-ops-solo {
  display: block;
}

.ai-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: 16px;
  align-items: start;
  /* Matches .sec's margin-bottom: the AI agents block sits between two .sec
     sections (Dashboards above, Data entry below) but isn't one itself
     (its heading lives outside it, in #aiSectionHeading), so without this
     the Data entry section directly below had no gap above it. */
  margin-bottom: 46px;
}

/* While the chat panel is parked (hidden in index.html), the agents card
   takes the full row instead of leaving an empty right column. Un-parking
   the panel restores the two-column grid with no CSS change. */
.ai-grid:has(.chat-panel.hidden) {
  grid-template-columns: minmax(0, 1fr);
}

/* --------------------------------------------------------------------------
   12. WORKSPACE HEALTH
   -------------------------------------------------------------------------- */

.health {
  display: grid;
  grid-template-columns: 268px minmax(0, 1fr);
  gap: 16px;
  align-items: start;
}

.mini-stack {
  display: grid;
  gap: 16px;
}

.mini {
  padding: 18px 20px;
}

.mini-label {
  margin: 0 0 7px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-2);
}

.mini-value {
  font-family: var(--display);
  font-size: 30px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.04em;
  line-height: 1;
  color: var(--ink);
}

.mini-value-crit {
  color: var(--crit);
}

.pipeline-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.pipeline-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  min-width: 540px;
}

.pipeline-table th {
  text-align: left;
  padding: 10px 14px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
  border-bottom: 1px solid var(--glass-line-2);
  white-space: nowrap;
}

.pipeline-table th:first-child,
.pipeline-table td:first-child {
  padding-left: 22px;
}

.pipeline-table th:last-child,
.pipeline-table td:last-child {
  padding-right: 22px;
}

.pipeline-table td {
  padding: 11px 14px;
  border-bottom: 1px solid var(--glass-line-2);
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  vertical-align: middle;
}

.pipeline-table td:first-child {
  color: var(--ink);
  font-weight: 500;
}

.pipeline-table tbody tr {
  transition: background var(--ease);
}

.pipeline-table tbody tr:hover td {
  background: var(--glass);
}

/* Status pills (rendered by JS) — colour supports; the dot and label carry it. */
.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 11.5px;
  font-weight: 500;
  border-radius: 999px;
  padding: 3px 10px 3px 8px;
  border: 1px solid;
  white-space: nowrap;
}

.status-dot {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: currentColor;
  flex: none;
}

.status-ok {
  color: var(--good);
  background: var(--good-soft);
  border-color: var(--good-line);
}

.status-fail {
  color: var(--crit);
  background: var(--crit-soft);
  border-color: var(--crit-line);
}

.status-warn {
  color: var(--attn);
  background: var(--attn-soft);
  border-color: var(--attn-line);
}

.status-warn .status-dot {
  animation: rb-halo 2s ease-in-out infinite;
}

@keyframes rb-halo {

  0%,
  100% {
    opacity: 0.35;
  }

  50% {
    opacity: 1;
  }
}

/* --------------------------------------------------------------------------
   13. DATASETS
   -------------------------------------------------------------------------- */

.lake-badge {
  max-width: 100%;
  overflow: hidden;
}

.lake-badge .monospace-font {
  font-weight: 600;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
}

.warehouse-list-container {
  display: flex;
  flex-direction: column;
  max-height: 460px;
  overflow-y: auto;
}

/* The panel's grey loading/empty text needs its own indent — the rows carry
   their padding themselves. */
.warehouse-list-container>.loading-text,
.warehouse-list-container>.empty-text {
  padding: 14px 22px;
}

/* Composition strip: how the workspace's rows are shared between tables. */
.ds-comp {
  margin: 0 0 4px;
  padding: 18px 22px 16px;
  border-bottom: 1px solid var(--glass-line-2);
}

.ds-comp-bar {
  display: flex;
  gap: 2px;
  height: 24px;
  border-radius: 7px;
  overflow: hidden;
}

.ds-comp-seg {
  height: 100%;
  min-width: 3px;
}

.ds-comp-seg[data-ramp="1"],
.ds-comp-key[data-ramp="1"] {
  background: var(--ramp-1);
}

.ds-comp-seg[data-ramp="2"],
.ds-comp-key[data-ramp="2"] {
  background: var(--ramp-2);
}

.ds-comp-seg[data-ramp="3"],
.ds-comp-key[data-ramp="3"] {
  background: var(--ramp-3);
}

.ds-comp-seg[data-ramp="4"],
.ds-comp-key[data-ramp="4"] {
  background: var(--ramp-4);
}

.ds-comp-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 7px 18px;
  margin-top: 12px;
  font-size: 12px;
  color: var(--ink-2);
}

.ds-comp-lgi {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ds-comp-key {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  flex: none;
}

.ds-comp-val {
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* Table rows: name · rows · share · go */
.quick-link {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto 18px;
  align-items: center;
  gap: 14px;
  text-decoration: none;
  padding: 11px 22px;
  border-bottom: 1px solid var(--glass-line-2);
  transition: background var(--ease);
}

.quick-link:last-of-type {
  border-bottom: none;
}

.quick-link:hover {
  background: var(--glass-2);
}

.quick-link-main {
  min-width: 0;
}

.quick-link-title {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.quick-link-sub {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 1px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.quick-link-count {
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  font-size: 13px;
}

.quick-link-share {
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
  font-size: 12px;
  min-width: 44px;
}

.quick-link-go {
  color: var(--ink-3);
  display: grid;
  place-items: center;
  transition: color var(--ease), transform var(--ease);
}

.quick-link:hover .quick-link-go {
  color: var(--accent);
  transform: translateX(3px);
}

/* --------------------------------------------------------------------------
   14. DASHBOARD TILES (rendered by JS)
   -------------------------------------------------------------------------- */

.dash-thumb-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 14px;
}

.dash-thumb-link {
  text-decoration: none;
  display: block;
  min-width: 0;
  border-radius: var(--rad);
}

.dash-thumb-card {
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 20px;
  overflow: hidden;
  transition: transform var(--ease-slow), box-shadow var(--ease-slow), border-color var(--ease-slow);
}

/* a brand bloom that fades in from the top-right on hover */
.dash-thumb-card::before {
  content: "";
  position: absolute;
  inset: -40% -40% auto auto;
  width: 190px;
  height: 190px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--accent-soft), transparent 70%);
  opacity: 0;
  transition: opacity var(--ease-slow);
  pointer-events: none;
}

.dash-thumb-link:hover .dash-thumb-card {
  transform: translateY(-3px);
  box-shadow: var(--lift-hi), inset 0 1px 0 var(--glass-top);
  border-color: var(--glass-line);
}

[data-theme="light"] .dash-thumb-link:hover .dash-thumb-card {
  border-color: var(--accent-line);
}

.dash-thumb-link:hover .dash-thumb-card::before {
  opacity: 1;
}

.dash-thumb-body,
.dash-thumb-footer {
  position: relative;
  min-width: 0;
}

.dash-thumb-title {
  font-family: var(--display);
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.028em;
  line-height: 1.25;
  color: var(--ink);
  margin-bottom: 5px;
  padding-right: 34px;
}

.dash-thumb-sub {
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink-2);
  margin-bottom: 20px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 2.1em;
}

.dash-thumb-icon-wrap {
  position: absolute;
  top: -2px;
  right: 0;
  color: var(--ink-3);
  opacity: 0.55;
  transition: color var(--ease), opacity var(--ease);
}

.dash-thumb-link:hover .dash-thumb-icon-wrap {
  color: var(--accent);
  opacity: 1;
}

.dash-icon {
  width: 24px;
  height: 24px;
  display: block;
}

.dash-thumb-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.dash-type-badge {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--accent);
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid var(--accent-line);
  background: var(--accent-soft);
  white-space: nowrap;
}

.dash-thumb-cta {
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
  transition: color var(--ease);
  white-space: nowrap;
}

.dash-thumb-link:hover .dash-thumb-cta {
  color: var(--accent);
}

/* --------------------------------------------------------------------------
   15. AI AGENTS & CHAT
   -------------------------------------------------------------------------- */

/* #agentsList: every tile (runnable and coming-soon alike) renders here from
   /api/agents — there is no static markup in the list. */
.ai-agent-list {
  margin: 16px -22px -20px;
  border-top: 1px solid var(--glass-line-2);
}

.ai-agent-list>.loading-text,
.ai-agent-list>.empty-text {
  padding: 14px 22px;
}

.ai-agent-item {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 22px;
  border-bottom: 1px solid var(--glass-line-2);
}

.ai-agent-item:last-child {
  border-bottom: none;
}

.ai-agent-main {
  min-width: 0;
}

.ai-agent-title {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin-bottom: 2px;
}

.ai-agent-sub {
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink-2);
  max-width: 400px;
}

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

/* "Coming soon" — a quiet stamp, and the row it sits on steps back. */
.incoming-badge-corner {
  position: absolute;
  top: 12px;
  right: 22px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 3px 9px;
  border: 1px solid var(--glass-line-2);
  border-radius: 999px;
  background: var(--glass-2);
  pointer-events: none;
  white-space: nowrap;
}

.ai-agent-item:has(.incoming-badge-corner) {
  opacity: 0.72;
}

.card>.incoming-badge-corner {
  top: 18px;
  right: 20px;
}

/* Chat — one panel, prototype-style: head, conversation, input bar. The
   card's own padding is turned off so the panel furniture owns the edges. */
.chat-panel {
  padding: 0;
  overflow: hidden;
}

.chat {
  display: grid;
  gap: 14px;
  padding: 18px 22px;
  max-height: 420px;
  overflow-y: auto;
}

.msg {
  max-width: 86%;
  padding: 13px 16px;
  border-radius: 16px;
  font-size: 13px;
  line-height: 1.6;
  background: var(--glass-2);
  border: 1px solid var(--glass-line-2);
  color: var(--ink-2);
}

.msg strong {
  color: var(--ink);
  font-weight: 600;
}

.msg.me {
  margin-left: auto;
  color: var(--ink);
  background: var(--accent-soft);
  border-color: var(--accent-line);
}

.msg-who {
  display: block;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 6px;
}

.chat-example {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--glass-line-2);
  font-size: 12.5px;
  color: var(--ink-3);
}

.chat-bar {
  display: flex;
  gap: 10px;
  padding: 14px 22px;
  border-top: 1px solid var(--glass-line-2);
}

.chat-in {
  flex: 1;
  min-width: 0;
  height: 36px;
  font-family: var(--body);
  font-size: 13px;
  color: var(--ink);
  background: var(--glass-2);
  border: 1px solid var(--glass-line-2);
  border-radius: 999px;
  padding: 0 14px;
}

.chat-in::placeholder {
  color: var(--ink-3);
  opacity: 0.8;
}

.chat-in:disabled {
  cursor: not-allowed;
}

.chat-in:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ring);
}

/* Live-chat states. The model answers in paragraphs, so its text keeps its
   line breaks; notices are UI furniture (they never join the transcript) —
   a calm dashed "not switched on yet" vs a real failure in the crit voice. */
.msg-text {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.msg.chat-pending {
  color: var(--ink-3);
  font-style: italic;
}

.msg.chat-notice-info {
  color: var(--ink-3);
  border-style: dashed;
}

.msg.chat-notice-error {
  color: var(--crit);
  background: var(--crit-soft);
  border-color: var(--crit-line);
}

/* --------------------------------------------------------------------------
   16. DATA QUALITY RESULTS
   -------------------------------------------------------------------------- */

.dq-results-section {
  margin: 40px 0 8px;
}

.dq-unavailable {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--ink-2);
  padding: 16px 18px;
}

.dq-unavailable-icon {
  flex: none;
}

.dq-summary-header {
  display: flex;
  align-items: center;
  gap: 10px;
  border-radius: var(--rad-m);
  border: 1px solid;
  padding: 12px 16px;
  margin-bottom: 14px;
}

.dq-status-indicator {
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: currentColor;
  flex: none;
}

.dq-status-text {
  font-size: 14px;
  font-weight: 600;
}

.dq-status-ok {
  color: var(--good);
  background: var(--good-soft);
  border-color: var(--good-line);
}

.dq-status-warning {
  color: var(--attn);
  background: var(--attn-soft);
  border-color: var(--attn-line);
}

.dq-status-critical {
  color: var(--crit);
  background: var(--crit-soft);
  border-color: var(--crit-line);
}

.dq-summary-stats {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  border-top: 1px solid var(--glass-line-2);
  border-bottom: 1px solid var(--glass-line-2);
  margin-bottom: 6px;
}

.dq-stat {
  padding: 12px 16px 11px;
  border-left: 1px solid var(--glass-line-2);
  min-width: 0;
}

.dq-stat:first-child {
  border-left: none;
  padding-left: 2px;
}

.dq-stat-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 5px;
  white-space: nowrap;
}

.dq-stat-value {
  font-family: var(--display);
  font-size: 22px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.03em;
  color: var(--ink);
}

.dq-stat-critical .dq-stat-value {
  color: var(--crit);
}

.dq-stat-warning .dq-stat-value {
  color: var(--attn);
}

.dq-stat-info .dq-stat-value {
  color: var(--ink-2);
}

.dq-stat-error .dq-stat-value {
  color: var(--crit);
}

#dq-results-container {
  margin-top: 18px;
}

.dq-category-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  font-size: 13.5px;
  font-weight: 600;
  padding: 10px 2px 8px;
  margin-top: 10px;
  border-bottom: 1px solid var(--glass-line);
}

.dq-category-critical,
.dq-category-error {
  color: var(--crit);
}

.dq-category-warning {
  color: var(--attn);
}

.dq-category-info {
  color: var(--ink-2);
}

.dq-category-passed {
  color: var(--good);
}

.dq-expand-icon {
  font-size: 11px;
  color: var(--ink-3);
}

.dq-no-issues {
  font-size: 13.5px;
  color: var(--good);
  background: var(--good-soft);
  border: 1px solid var(--good-line);
  border-radius: var(--rad-m);
  padding: 12px 16px;
  margin: 10px 0;
}

.dq-check-card {
  margin: 10px 0;
  overflow: hidden;
}

.dq-check-passed {
  opacity: 0.72;
}

.dq-check-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 11px 14px;
}

.dq-check-title {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  min-width: 0;
}

.dq-check-name {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
}

.dq-check-info {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
}

.dq-severity-badge,
.dq-category-badge {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  border-radius: 999px;
  padding: 2px 8px;
  border: 1px solid;
}

.dq-severity-critical {
  color: var(--crit);
  background: var(--crit-soft);
  border-color: var(--crit-line);
}

.dq-severity-warning {
  color: var(--attn);
  background: var(--attn-soft);
  border-color: var(--attn-line);
}

.dq-severity-info {
  color: var(--ink-2);
  background: var(--glass-2);
  border-color: var(--glass-line-2);
}

.dq-category-badge {
  color: var(--ink-3);
  background: transparent;
  border-color: var(--glass-line);
}

.dq-issues-count {
  font-size: 12.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--attn);
}

.dq-passed-badge {
  color: var(--good);
}

.dq-error-badge {
  color: var(--crit);
}

.dq-check-details {
  border-top: 1px solid var(--glass-line-2);
  padding: 13px 14px;
}

.dq-check-description {
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink-2);
}

.dq-error {
  font-size: 13px;
  color: var(--crit);
  margin-top: 8px;
}

.dq-failed-rows-section {
  margin-top: 14px;
}

.dq-failed-rows-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 8px;
}

.dq-export-btn {
  font-size: 12px;
  padding: 4px 11px;
  text-transform: none;
  letter-spacing: 0;
}

.dq-failed-rows-table-wrapper {
  overflow-x: auto;
  border: 1px solid var(--glass-line-2);
  border-radius: var(--rad-sm);
}

.dq-failed-rows-table {
  width: 100%;
  border-collapse: collapse;
}

.dq-failed-rows-table th {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: left;
  color: var(--ink-3);
  background: var(--glass-2);
  padding: 7px 12px;
  border-bottom: 1px solid var(--glass-line-2);
  white-space: nowrap;
}

.dq-failed-rows-table td {
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
  padding: 7px 12px;
  border-bottom: 1px solid var(--glass-line-2);
  white-space: nowrap;
}

.dq-failed-rows-table tr:last-child td {
  border-bottom: none;
}

.dq-failed-rows-table tbody tr:hover td {
  background: var(--glass);
}

.dq-no-data {
  font-size: 13px;
  color: var(--ink-3);
  padding: 12px;
}

/* Clearing / ignoring an issue. The badge count stays the OPEN one; what the
   team has already ruled on sits beside it in a quieter weight — never
   replacing it, never folded into it. */

.dq-cleared-count {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
  margin-left: 6px;
}

.dq-stat-dismissed .dq-stat-value {
  color: var(--ink-3);
}

.dq-row-actions-head {
  text-align: right;
}

.dq-failed-rows-table td.dq-row-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  white-space: nowrap;
}

/* The same ghost language as .dq-export-btn, one size down: these sit inside a
   table row and must read as secondary to the data in it. */
.dq-dismiss-btn {
  font-family: var(--body);
  font-size: 11.5px;
  font-weight: 500;
  color: var(--ink-3);
  background: var(--glass-2);
  border: 1px solid var(--glass-line-2);
  border-radius: 999px;
  padding: 3px 10px;
  cursor: pointer;
  transition: color var(--ease), border-color var(--ease);
}

.dq-dismiss-btn:hover {
  color: var(--ink);
  border-color: var(--glass-line);
}

.dq-dismiss-btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.dq-undo-btn {
  color: var(--ink-2);
}

/* A just-cleared row stays where it was, dimmed: the undo has to be findable,
   and the row is still the evidence for the decision. */
.dq-failed-rows-table tr.dq-row-dismissed td {
  opacity: 0.55;
  font-style: italic;
}

.dq-dismissal-tag {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--good);
  background: var(--good-soft);
  border: 1px solid var(--good-line);
  border-radius: 999px;
  padding: 2px 8px;
}

.dq-no-key {
  font-size: 12px;
  color: var(--ink-3);
}

/* Dismissals from an earlier run: their rows are excluded from the sample, so
   the decision itself is all there is left to show. */
.dq-dismissals {
  margin-top: 12px;
  border: 1px solid var(--glass-line-2);
  border-radius: var(--rad-sm);
  padding: 10px 12px;
}

.dq-dismissals-header {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 8px;
}

.dq-dismissal-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 5px 0;
}

.dq-dismissal-key {
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}

.dq-dismissal-meta {
  font-size: 12px;
  color: var(--ink-3);
  flex: 1 1 auto;
  min-width: 0;
}

.dq-dismissal-note {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 8px;
}

.dq-dismiss-error {
  font-size: 12.5px;
  color: var(--crit);
  margin-top: 10px;
}

/* --------------------------------------------------------------------------
   17. ADMIN AREA & ACCOUNT (PASSWORD + TWO-FACTOR)
   -------------------------------------------------------------------------- */

.admin-view-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 22px;
}

.admin-view-header .hero-eyebrow {
  margin-bottom: 8px;
}

.admin-grid {
  display: grid;
  /* the users table carries six columns of text — give it the room */
  grid-template-columns: minmax(0, 2.25fr) minmax(0, 1fr);
  gap: 16px;
  align-items: start;
}

/* The admin area is a single stacked column: the users table, then the three
   access editors, each owning its full width.

   Addressed by CLASS, never :nth-child. The rules here used to pin "the second
   card" to a narrow right column — which was Dashboard access once the dataset
   and agent editors were added, leaving that one squeezed vertically on the
   right while its two peers flowed full width. Class selectors mean a fourth
   editor needs no new rule. */
#adminView .admin-grid {
  grid-template-columns: minmax(0, 1fr);
  /* Each area needs room to read as its own thing. The 16px card gap left
     "Dashboard access" glued to the users table above it. */
  gap: 46px;
}

/* .sec ships its own bottom margin for the main dashboard, where sections are
   not grid items. Here it would stack on top of the gap, so the space between
   two sections came out nearly four times the space above the first one. */
#adminView .admin-grid>.sec {
  margin-bottom: 0;
}

/* --- Platform area (Amarji operators) --- */

/* Same single stacked column as the admin area, and for the same reason: every
   table here is wide, and each block needs to read as its own thing. */
.platform-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 46px;
  align-items: start;
}

.platform-grid>.sec {
  margin-bottom: 0;
}

/* A client row opens its people — say so before the click. */
.platform-tenant-row {
  cursor: pointer;
}

/* --- Impersonation banner --- */

/* Amber, from the shared --attn tokens (both themes define them), so it reads
   as "something is different about this session" without the alarm of --crit:
   nothing has gone wrong, the operator asked for this. It sits ABOVE the
   header in the flow — never fixed, never overlaying — so it can push the page
   down instead of covering the first thing on it. */
.impersonation-banner {
  background: var(--attn-soft);
  border-bottom: 1px solid var(--attn-line);
  color: var(--attn);
}

.impersonation-banner-inner {
  max-width: 1320px;
  margin: 0 auto;
  padding: 10px 24px;
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.impersonation-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--attn);
  flex: none;
}

.impersonation-text {
  font-size: 13px;
  letter-spacing: 0.01em;
  min-width: 0;
}

.impersonation-text strong {
  font-weight: 600;
}

.impersonation-sep {
  opacity: 0.55;
  margin: 0 6px;
}

.impersonation-readonly {
  text-transform: uppercase;
  font-size: 11px;
  letter-spacing: 0.08em;
  opacity: 0.85;
}

/* Pushed to the far end so the way out is always in the same place. */
.impersonation-exit {
  margin-left: auto;
}

/* An SSO tile is dead while viewing as someone (the server refuses the launch
   — the token would assert an identity that is not really there). Dimmed and
   un-hoverable so it looks unavailable rather than broken; the title says why. */
.dash-thumb-inert {
  opacity: 0.45;
  cursor: not-allowed;
}

.dash-thumb-inert .dash-thumb-card:hover {
  transform: none;
}

/* --- New user, folded into the users card --- */

.new-user-plus {
  font-size: 15px;
  line-height: 1;
  margin-right: 6px;
}

.admin-new-user {
  margin: 0 0 20px;
  padding: 18px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--panel-2, rgba(255, 255, 255, 0.02));
}

.new-user-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0 16px;
}

/* The checkbox and the submit sit on one line under the fields — the form is
   three inputs, and stacking them made it taller than the table it sits above. */
.new-user-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.new-user-actions .admin-checkbox-row {
  margin: 0;
}

.new-user-submit {
  width: auto;
  margin: 0;
  flex: 0 0 auto;
}

/* The Account view: two sibling cards — password and two-factor — reading as
   equals. auto-fit means they sit side by side while two 420px columns fit and
   stack the moment they don't, so no breakpoint owns the decision. The cap
   keeps the pair from stretching across a very wide screen, and align-items
   stops the shorter card growing to match the taller one. */
#accountView .admin-grid {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
  max-width: 1100px;
  margin-inline: auto;
  align-items: start;
}

.admin-form-sub {
  margin: 4px 0 18px;
}

/* Temp-password notice — the one green-tinted panel */
.admin-notice {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  background: var(--good-soft);
  border: 1px solid var(--good-line);
  border-radius: var(--rad-m);
  padding: 14px 16px;
  margin-bottom: 16px;
}

/* The same panel in the attention key, for the two states that are not simply
   good news: a temporary password that could NOT be emailed (someone still has
   to carry it by hand), and the invited user's forced password change. */
.admin-notice-attn {
  background: var(--attn-soft);
  border-color: var(--attn-line);
}

.admin-notice-attn .admin-temp-password {
  color: var(--attn);
  border-color: var(--attn-line);
}

.admin-notice-text {
  min-width: 0;
  font-size: 13.5px;
  color: var(--ink-2);
}

.admin-notice-title {
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 4px;
}

.admin-temp-password {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--good);
  background: var(--glass-solid);
  border: 1px solid var(--good-line);
  border-radius: 6px;
  padding: 2px 8px;
  user-select: all;
}

.admin-notice-sub {
  font-size: 12.5px;
  color: var(--ink-3);
  margin-top: 6px;
}

.admin-notice-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
}

/* Users table */
.admin-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin: 0 -22px;
}

.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  min-width: 760px;
}

.admin-table th {
  text-align: left;
  padding: 10px 14px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
  border-bottom: 1px solid var(--glass-line-2);
  white-space: nowrap;
}

.admin-table th:first-child,
.admin-table td:first-child {
  padding-left: 22px;
}

.admin-table th:last-child,
.admin-table td:last-child {
  padding-right: 22px;
}

.admin-table td {
  padding: 11px 14px;
  border-bottom: 1px solid var(--glass-line-2);
  color: var(--ink-2);
  vertical-align: middle;
  white-space: nowrap;
}

.admin-table tbody tr {
  transition: background var(--ease);
}

.admin-table tbody tr:hover td {
  background: var(--glass);
}

.admin-row-disabled td {
  opacity: 0.55;
}

.admin-user-name {
  font-weight: 600;
  color: var(--ink);
}

.admin-you-badge {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--accent);
  border: 1px solid var(--accent-line);
  border-radius: 999px;
  padding: 1px 7px;
  margin-left: 7px;
  vertical-align: 1px;
}

.admin-user-email {
  font-size: 12.5px;
  max-width: 180px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.admin-role-badge,
.admin-status-badge {
  display: inline-block;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-radius: 999px;
  padding: 2px 9px;
  border: 1px solid var(--glass-line);
  color: var(--ink-2);
  white-space: nowrap;
}

.admin-role-admin {
  color: var(--accent);
  border-color: var(--accent-line);
  background: var(--accent-soft);
}

.admin-status-active {
  color: var(--good);
  border-color: var(--good-line);
  background: var(--good-soft);
}

.admin-status-disabled {
  color: var(--ink-3);
  border-style: dashed;
}

/* Sits BESIDE Active, not instead of it: an invited account is active and
   simply hasn't been picked up yet. Attention, not alarm — it resolves itself
   the moment the person signs in. */
.admin-status-invited {
  color: var(--attn);
  border-color: var(--attn-line);
  background: var(--attn-soft);
  margin-left: 6px;
}

.admin-last-signin {
  font-variant-numeric: tabular-nums;
  font-size: 12.5px;
}

.admin-actions-cell {
  white-space: nowrap;
}

/* Access matrix: one row per resource, one column per member.

   Replaced a per-resource card that repeated the whole member list inside every
   item. The table reads both ways — across a row for "who can open this",
   down a column for "what can this person open". */
.matrix-wrap {
  overflow-x: auto;
  /* The person columns are narrow, but a long enough member list still has to
     scroll rather than squeeze the resource names to nothing. */
}

.access-matrix {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.access-matrix thead th {
  padding: 0 10px 12px;
  border-bottom: 1px solid var(--glass-line-2);
  vertical-align: bottom;
}

.matrix-person {
  text-align: center;
  min-width: 92px;
}

.matrix-person-name {
  display: block;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
}

.matrix-person-email {
  display: block;
  font-size: 11px;
  font-weight: 400;
  color: var(--ink-3);
  margin-top: 2px;
}

.matrix-person-everyone {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
}

.access-matrix tbody tr {
  border-bottom: 1px solid var(--glass-line-2);
}

/* The resource column absorbs the slack, so a name and its boxes can sit a long
   way apart — the hover band is what keeps the eye on one row while it travels. */
.access-matrix tbody tr:hover {
  background: var(--glass-2);
}

.access-matrix tbody tr:last-child {
  border-bottom: 0;
}

/* Stays a table cell: display:flex here would take it out of the table box
   model and the column would stop lining up with its header. */
.matrix-resource {
  text-align: left;
  font-weight: 500;
  color: var(--ink);
  padding: 11px 14px 11px 0;
  width: 100%;
}

.matrix-resource-name {
  overflow-wrap: anywhere;
  margin-right: 8px;
}

.matrix-cell {
  text-align: center;
  padding: 11px 10px;
}

.matrix-cell input {
  accent-color: var(--accent);
  cursor: pointer;
}

/* A row open to everyone: the individual boxes are inert, so they read as
   inert instead of looking like settings that are being ignored. */
.matrix-row-everyone .matrix-cell input[data-grant-user-id] {
  opacity: 0.25;
  cursor: default;
}

.matrix-cell-everyone {
  border-right: 1px solid var(--glass-line-2);
}

.matrix-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 16px;
}

/* The note is absent in the normal case, so the button holds the right edge
   on its own rather than sliding left. */
.matrix-foot .export-btn {
  margin-left: auto;
}

.admin-save-grants[disabled] {
  opacity: 0.45;
  cursor: default;
}

/* --- Access groups & column rules (the Column access card) --- */

.admin-groups-card .sec-head {
  align-items: center;
  gap: 12px;
}

.admin-groups-card .sec-head .export-btn {
  margin-left: auto;
}

.group-row {
  border-top: 1px solid var(--glass-line-2);
  padding: 10px 0;
}

.group-row:first-child {
  border-top: none;
}

.group-row-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.group-name {
  font-weight: 600;
}

.group-desc {
  color: var(--ink-3);
  font-size: 13px;
}

.group-meta {
  color: var(--ink-3);
  font-size: 12.5px;
  margin-left: auto;
}

.group-editor {
  margin-top: 12px;
  padding: 14px;
  border: 1px solid var(--glass-line-2);
  border-radius: 10px;
  background: var(--glass-2);
  display: grid;
  gap: 12px;
}

.group-members {
  display: grid;
  gap: 6px;
}

.rule-col,
.group-member {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  cursor: pointer;
}

.rule-col {
  /* Warehouse column identifiers can be long unbroken words
     (FlintProcessed14AProcessedFlintGlassCullet): without a break
     opportunity they overflow the grid cell into the neighbouring
     checkbox instead of wrapping. */
  min-width: 0;
  overflow-wrap: anywhere;
}

.rules-note {
  color: var(--ink-3);
  font-size: 12.5px;
}

.rules-list {
  display: grid;
  gap: 8px;
}

.rule-row {
  border: 1px solid var(--glass-line-2);
  border-radius: 8px;
  padding: 8px 10px;
}

.rule-row-head {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

.rule-table-name {
  font-weight: 600;
  font-size: 13.5px;
  margin-right: auto;
}

.rule-mode-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  cursor: pointer;
}

.rule-columns-slot {
  margin-top: 8px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 4px 16px;
  max-height: 260px;
  overflow-y: auto;
  padding-top: 8px;
  border-top: 1px dashed var(--glass-line-2);
}

.rule-col-stray-tag {
  color: var(--warn, #c88a2b);
  font-size: 11px;
}

.rule-add-select {
  max-width: 320px;
}

.group-editor-foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  flex-wrap: wrap;
}

.group-editor-error {
  margin-right: auto;
}

/* --- Two-factor authentication (Security view + the admin 2FA column) --- */

/* On/Off state chip. Shares its shape with the role and status badges above so
   the admin table reads as one system, and is reused verbatim as the Security
   card's own state badge. */
.twofa-badge {
  display: inline-flex;
  align-items: center;
  flex: none;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink-3);
  background: var(--glass-2);
  border: 1px solid var(--glass-line-2);
  border-radius: 999px;
  padding: 3px 10px;
  white-space: nowrap;
}

.twofa-badge-on {
  color: var(--good);
  background: var(--good-soft);
  border-color: var(--good-line);
}

.twofa-lead {
  margin: 4px 0 16px;
  max-width: 62ch;
}

/* A code is a short string read off a screen and typed straight back —
   monospaced and generously tracked so a 6 and a 5 can't be confused, and
   never full-bleed: a 6-digit field the width of the card invites a password. */
.code-input {
  font-family: var(--mono);
  font-size: 17px;
  letter-spacing: 0.22em;
  max-width: 15ch;
}

/* Except on the sign-in card, where the field belongs to a stack of full-width
   inputs and a short one would read as a different kind of control. */
#loginTwoFactorGroup .code-input {
  max-width: none;
}

.twofa-code-field {
  margin-bottom: 18px;
}

/* The enrolment step: the QR beside its instructions, stacking under it on a
   narrow screen (see the media query at the end of this block). */
.twofa-enrol {
  display: flex;
  align-items: flex-start;
  gap: 24px;
  flex-wrap: wrap;
}

/* A QR code is black-on-white geometry — it keeps its own white field in BOTH
   themes, quiet zone included, or a dark-theme scan simply fails. */
.twofa-qr {
  flex: none;
  width: 188px;
  height: 188px;
  display: grid;
  place-items: center;
  background: #fff;
  border-radius: var(--rad-m);
  border: 1px solid var(--glass-line-2);
  padding: 10px;
}

.twofa-qr svg {
  width: 100%;
  height: 100%;
  display: block;
}

.twofa-qr path {
  fill: #0b1a1f;
}

.twofa-enrol-body {
  flex: 1 1 260px;
  min-width: 0;
}

.twofa-secret {
  display: inline-block;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--ink);
  background: var(--glass-2);
  border: 1px solid var(--glass-line-2);
  border-radius: 8px;
  padding: 7px 11px;
  margin: 6px 0 18px;
  /* One click (or a long-press) takes the whole key — nobody should have to
     drag-select a 32-character secret. */
  user-select: all;
  word-break: break-all;
}

.twofa-actions {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

/* .login-btn is full-width by default (it is the sign-in button); in an action
   row it sits to its own content. */
.twofa-actions .login-btn {
  width: auto;
  margin-top: 0;
}

.twofa-recovery-notice {
  margin-top: 4px;
}

/* Ten codes in a grid: dense enough to read as one block worth copying, loose
   enough that each is unmistakably its own line. */
.twofa-recovery-list {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 8px;
  margin: 0 0 18px;
  padding: 0;
}

.twofa-recovery-code {
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: 0.06em;
  color: var(--ink);
  background: var(--glass-2);
  border: 1px solid var(--glass-line-2);
  border-radius: 8px;
  padding: 9px 12px;
  text-align: center;
  user-select: all;
}

.admin-2fa-cell {
  white-space: nowrap;
}

@media (max-width: 560px) {
  .twofa-enrol {
    gap: 18px;
  }

  .twofa-qr {
    width: 100%;
    height: auto;
    aspect-ratio: 1;
  }
}

/* --------------------------------------------------------------------------
   18. DATASET EXPLORER
   -------------------------------------------------------------------------- */

.dataset-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}

/* The title block yields before the toolbar wraps: a flex-basis well under its
   natural width means the header only breaks onto two lines on a genuinely
   narrow viewport, not whenever an export label grows by a few characters. */
.dataset-heading {
  flex: 1 1 320px;
  min-width: 0;
}

/* Toolbar + export status, stacked and anchored to the right edge. margin-left
   auto keeps the column on the right even on the rare wrap, instead of the
   space-between fallback dropping a lone item to the left. */
.dataset-tools {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
  margin-left: auto;
  max-width: 100%;
}

.dataset-title-main {
  font-family: var(--display);
  font-size: clamp(20px, 2.4vw, 26px);
  font-weight: 600;
  letter-spacing: -0.03em;
  color: var(--ink);
  margin: 2px 0 6px;
  word-break: break-all;
}

.dataset-path {
  color: var(--ink-3);
  font-weight: 400;
}

.dataset-subtitle {
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--ink-2);
  max-width: 560px;
}

.dataset-pills {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.ds-limit {
  display: flex;
  align-items: center;
  gap: 6px;
}

.ds-limit-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.ds-limit-select {
  font-family: var(--body);
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ink);
  background: var(--glass-2);
  border: 1px solid var(--glass-line-2);
  border-radius: 999px;
  padding: 5px 10px;
  cursor: pointer;
  transition: border-color var(--ease);
}

.ds-limit-select:hover {
  border-color: var(--glass-line);
}

.ds-limit-select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ring);
}

/* The table panel: one glass panel, the table scrolling inside it. */
.dataset-table-wrap {
  overflow: hidden;
}

.dataset-table-inner {
  overflow: auto;
  max-height: 62vh;
}

/* A ?dataset= tab: the table IS the page. dataset-wide (stamped on
   .dash-root by showDatasetView) lifts the layout's max-width so the columns
   get the whole viewport. */
.dash-root.dataset-wide .dash-main-inner {
  max-width: none;
  padding: 26px 32px 56px;
}

.dash-root.dataset-wide .dash-foot {
  max-width: none;
}

.dash-root.dataset-wide .dataset-table-inner {
  max-height: calc(100vh - 300px);
  min-height: 320px;
}

/* `separate` (not `collapse`) is load-bearing under the sticky thead: a
   collapsed border is hoisted to the table and painted below the cell
   backgrounds, so rows scrolling underneath would smear through translucent
   hairlines between the header and the filter row. Separated borders paint
   against each cell's own opaque background. */
.dataset-table-inner table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
}

/* The whole thead sticks as a block, so the filter row rides directly under
   the column headers. Header cells are the SOLID glass tone: sticky cells
   need an opaque back for rows to disappear under. */
.dataset-table-inner thead {
  position: sticky;
  top: 0;
  z-index: 2;
}

.dataset-table-inner th {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  text-align: left;
  color: var(--ink-3);
  background: var(--glass-solid);
  padding: 10px 14px;
  border-bottom: 1px solid var(--glass-line-2);
  white-space: nowrap;
}

/* Sortable column headers. The sort glyph is a ::after pseudo-element on
   purpose: pseudo-element text is not part of innerText, so the CSV export
   (which reads the header row's text) never picks up an arrow. */
.dataset-table-inner th.ds-sortable {
  cursor: pointer;
  user-select: none;
  transition: color var(--ease), background var(--ease);
}

.dataset-table-inner th.ds-sortable:hover {
  color: var(--accent);
}

.dataset-table-inner th.ds-sortable:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  color: var(--accent);
}

.dataset-table-inner th.ds-sortable::after {
  content: "↕";
  margin-left: 6px;
  opacity: 0.4;
}

.dataset-table-inner th.ds-sort-asc,
.dataset-table-inner th.ds-sort-desc {
  color: var(--ink);
}

.dataset-table-inner th.ds-sort-asc::after {
  content: "↑";
  opacity: 1;
  color: var(--accent);
}

.dataset-table-inner th.ds-sort-desc::after {
  content: "↓";
  opacity: 1;
  color: var(--accent);
}

/* Per-column filter row — the bottom of the sticky thead, recessed one step
   into the well tone so it reads as controls, not data. */
.ds-filter-row th {
  padding: 7px 8px;
  background: var(--glass-well);
  border-bottom: 1px solid var(--glass-line-2);
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  vertical-align: middle;
}

.ds-filter-cell {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 130px;
}

/* The compact edition of .text-input, sized for a table cell. Lands on
   <input> and <select> (the bool tri-state), so everything holds for both. */
.ds-filter-input,
.ds-filter-op {
  font-family: var(--body);
  font-size: 12px;
  color: var(--ink);
  background: var(--glass-solid);
  border: 1px solid var(--glass-line-2);
  border-radius: 8px;
  padding: 4px 8px;
  width: 100%;
  min-width: 0;
  transition: border-color var(--ease), background var(--ease), box-shadow var(--ease);
}

[data-theme="light"] .ds-filter-input,
[data-theme="light"] .ds-filter-op {
  background: #ffffff;
}

.ds-filter-input:hover,
.ds-filter-op:hover {
  border-color: var(--glass-line);
}

.ds-filter-op {
  flex: 0 0 auto;
  width: auto;
  cursor: pointer;
  color: var(--ink-2);
}

select.ds-filter-input {
  cursor: pointer;
}

.ds-filter-input:focus,
.ds-filter-op:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ring);
}

.ds-filter-input::placeholder {
  color: var(--ink-3);
  opacity: 0.8;
}

/* A column that is actually filtering is marked in the brand accent. */
.ds-filter-cell.is-active .ds-filter-input,
.ds-filter-cell.is-active .ds-filter-op {
  border-color: var(--accent-line);
  background: var(--accent-soft);
}

/* `between` shows its second bound only when that operator is selected. */
.ds-filter-cell .ds-filter-value2 {
  display: none;
}

.ds-filter-cell.has-range .ds-filter-value2 {
  display: block;
}

/* Columns of a type we can't safely filter (xml, varbinary, geography...). */
.ds-filter-none {
  font-size: 12px;
  color: var(--ink-3);
  opacity: 0.6;
}

.dataset-table-inner td {
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
  padding: 8px 14px;
  border-bottom: 1px solid var(--glass-line-2);
  white-space: nowrap;
}

.dataset-table-inner tbody tr {
  transition: background var(--ease);
}

.dataset-table-inner tbody tr:hover td {
  background: var(--glass-2);
}

.dataset-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  font-size: 12.5px;
  color: var(--ink-2);
  padding: 11px 16px;
  border-top: 1px solid var(--glass-line-2);
}

.dataset-footer span:first-child {
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   19. PAGE-LOAD REVEAL
   -------------------------------------------------------------------------- */

@keyframes rb-rise {
  from {
    opacity: 0;
    transform: translateY(16px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

.grid-ops,
.sec-dashboards {
  animation: rb-rise 0.72s cubic-bezier(0.2, 0.72, 0.2, 1) 0.3s both;
}

.sec-dashboards {
  animation-delay: 0.38s;
}

/* --------------------------------------------------------------------------
   20. SCROLLBARS
   -------------------------------------------------------------------------- */

.warehouse-list-container::-webkit-scrollbar,
.chat-body::-webkit-scrollbar,
.pipeline-table-wrap::-webkit-scrollbar,
.admin-table-wrap::-webkit-scrollbar,
.dataset-table-inner::-webkit-scrollbar,
.dq-failed-rows-table-wrapper::-webkit-scrollbar {
  width: 9px;
  height: 9px;
}

.warehouse-list-container::-webkit-scrollbar-track,
.chat-body::-webkit-scrollbar-track,
.pipeline-table-wrap::-webkit-scrollbar-track,
.admin-table-wrap::-webkit-scrollbar-track,
.dataset-table-inner::-webkit-scrollbar-track,
.dq-failed-rows-table-wrapper::-webkit-scrollbar-track {
  background: transparent;
}

.warehouse-list-container::-webkit-scrollbar-thumb,
.chat-body::-webkit-scrollbar-thumb,
.pipeline-table-wrap::-webkit-scrollbar-thumb,
.admin-table-wrap::-webkit-scrollbar-thumb,
.dataset-table-inner::-webkit-scrollbar-thumb,
.dq-failed-rows-table-wrapper::-webkit-scrollbar-thumb {
  background: var(--accent-line);
  border-radius: 999px;
  border: 2px solid transparent;
  background-clip: content-box;
}

.warehouse-list-container::-webkit-scrollbar-thumb:hover,
.chat-body::-webkit-scrollbar-thumb:hover,
.pipeline-table-wrap::-webkit-scrollbar-thumb:hover,
.admin-table-wrap::-webkit-scrollbar-thumb:hover,
.dataset-table-inner::-webkit-scrollbar-thumb:hover,
.dq-failed-rows-table-wrapper::-webkit-scrollbar-thumb:hover {
  background: var(--accent);
  background-clip: content-box;
}

/* --------------------------------------------------------------------------
   21. REDUCED MOTION
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {

  .login-intro,
  .login-card,
  .horizon,
  .hero .hero-eyebrow,
  .greeting-title,
  .greeting-sub,
  .metric-card,
  .grid-ops,
  .sec-dashboards {
    animation: none;
    opacity: 1;
    transform: none;
  }

  .status-warn .status-dot {
    animation: none;
    opacity: 0.8;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* --------------------------------------------------------------------------
   22. RESPONSIVE
   -------------------------------------------------------------------------- */

@media (max-width: 1100px) {
  .health {
    grid-template-columns: minmax(0, 1fr);
  }

  .mini-stack {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .ai-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .admin-grid {
    grid-template-columns: minmax(0, 1fr);
  }


  .metrics-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 900px) {
  .login-wrapper {
    grid-template-columns: minmax(0, 1fr);
    padding: 40px 20px 48px;
    gap: 40px;
    align-items: start;
  }

  .login-theme-btn {
    top: 18px;
    right: 20px;
  }

  .brand-pill {
    margin-bottom: 32px;
  }

  .login-subtitle {
    margin-bottom: 28px;
  }

  .dash-header-inner {
    padding: 10px 18px;
    height: auto;
    flex-wrap: wrap;
  }

  .dash-main-inner {
    padding: 24px 18px 56px;
  }

  .dash-foot {
    padding-left: 18px;
    padding-right: 18px;
  }

  .pill-cloud {
    display: none;
  }

  .dq-summary-stats {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .dq-stat:nth-child(3n + 1) {
    border-left: none;
    padding-left: 2px;
  }

  .dq-stat:nth-child(n + 4) {
    border-top: 1px solid var(--glass-line-2);
  }
}

@media (max-width: 640px) {
  .login-card {
    padding: 24px 20px 20px;
  }

  .pill-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
  }

  .pill {
    padding: 14px 0 10px;
    border-bottom: 1px solid var(--glass-line-2);
  }

  .pill:last-child {
    border-bottom: none;
  }

  .card {
    padding: 18px 16px;
  }

  .admin-table-wrap {
    margin: 0 -16px;
  }

  .pipeline-table th:first-child,
  .pipeline-table td:first-child,
  .admin-table th:first-child,
  .admin-table td:first-child {
    padding-left: 16px;
  }

  .pipeline-table th:last-child,
  .pipeline-table td:last-child,
  .admin-table th:last-child,
  .admin-table td:last-child {
    padding-right: 16px;
  }

  .ds-comp {
    padding-left: 16px;
    padding-right: 16px;
  }

  .panel-head,
  .panel-foot {
    padding-left: 16px;
    padding-right: 16px;
  }

  .quick-link {
    padding-left: 16px;
    padding-right: 16px;
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .quick-link-share,
  .quick-link-go {
    display: none;
  }

  .ai-agent-list {
    margin: 16px -16px -18px;
  }

  .ai-agent-item {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    padding: 14px 16px;
  }

  .dash-header-right {
    gap: 6px;
  }

  .chat-bubble {
    max-width: 100%;
  }
}

@media (max-width: 470px) {
  .metrics-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .mini-stack {
    grid-template-columns: minmax(0, 1fr);
  }

  .dash-brand-byline,
  .brand-byline {
    display: none;
  }

  .dataset-pills {
    gap: 6px;
  }

  /* Phones: the toolbar goes under the title as a full-width, left-aligned
     block, and the status line follows it. */
  .dataset-tools {
    width: 100%;
    align-items: flex-start;
    margin-left: 0;
  }

  #exportStatus {
    max-width: none;
  }
}
