/* The application shell: theme tokens, and the components base.html itself
   renders — nav, account menu, banners, toasts, tables, forms, buttons.
   Page-specific styling stays in each template's own <style> block.

   This lived inline in base.html until it was 630 of that file's 839 lines,
   which meant every change to the page *structure* — the responsive nav below
   is the case in point — was made inside a file that was three-quarters
   stylesheet. It is loaded after app.css (Tailwind) and, like the inline block
   it replaces, is unlayered, so it still wins ties against Tailwind utilities.

   Not built by anything: Tailwind's `@source` scan reads templates/ for class
   names, and hand-written CSS was never part of that pipeline. */

:root, [data-theme="light"] {
  --accent: #E5611F;
  --accent-bright: #D9551A;
  --bg: #FAFAF7;
  --bg-2: #F2F2EC;
  --surface: #FFFFFF;
  --surface-2: #F7F7F2;
  --border: rgba(20,22,26,.11);
  --border-strong: rgba(20,22,26,.20);
  --text: #181A1E;
  --muted: #5B626C;
  --faint: #8A9099;
  /* Tag palette — dark enough to read as text on a pale tint. */
  --tag-red: #C0392F;
  --tag-amber: #8A5A00;
  --tag-green: #22694A;
  --tag-teal: #0B6570;
  --tag-blue: #1F4FB0;
  --tag-violet: #5B3BB5;
  --tag-pink: #A32B71;
  --tag-slate: #4C535D;
}
[data-theme="dark"] {
  --accent: #FF7A45;
  --accent-bright: #FF8E5E;
  --bg: #0d0e11;
  --bg-2: #101218;
  --surface: #15171d;
  --surface-2: #1b1e25;
  --border: rgba(255,255,255,.09);
  --border-strong: rgba(255,255,255,.17);
  --text: #ECEDF0;
  --muted: #969CA6;
  --faint: #646B76;
  /* Same eight hues, lifted for a dark surface. */
  --tag-red: #F27B76;
  --tag-amber: #E0A32E;
  --tag-green: #52B788;
  --tag-teal: #3FB6C0;
  --tag-blue: #6FA0F0;
  --tag-violet: #A78BFA;
  --tag-pink: #F07EBB;
  --tag-slate: #94A0AE;
}
* { transition: background-color .2s ease, border-color .2s ease, color .15s ease; }
a, button, input, select, textarea, img { transition: none; }
body { font-family: "Hanken Grotesk", system-ui, sans-serif; background: var(--bg); color: var(--text); -webkit-font-smoothing: antialiased; }
.wordmark { font-family: "Space Grotesk", sans-serif; font-weight: 600; letter-spacing: -.03em; display: inline-flex; align-items: baseline; }
.wordmark .mark { display: inline-block; width: .58em; height: .75em; margin: 0 .01em; vertical-align: -.2em; overflow: visible; }
.mono { font-family: "JetBrains Mono", ui-monospace, monospace; }
@keyframes ps-spin { to { transform: rotate(360deg); } }
.ps-spin { animation: ps-spin 0.8s linear infinite; }

/* Anything clickable gets the hand. A browser's default for <button> is the
   plain arrow, which on a page where every other control is styled reads as
   "this is decoration, not a control" — the sign-in button was the one people
   noticed. Set once here rather than remembered per template, because the
   templates that reach for a bare <button> are exactly the ones that forget.
   Disabled controls say so instead: a hand on a button that will not respond
   is a worse lie than no hand at all. */
button, summary, [role="button"],
input[type="submit"], input[type="button"], input[type="reset"] { cursor: pointer; }
button:disabled, [role="button"][aria-disabled="true"],
input[type="submit"]:disabled, input[type="button"]:disabled,
input[type="reset"]:disabled { cursor: not-allowed; }

/* A form mid-submit. The guard in forms.js sets the attribute; this is the
   only thing the person sees, and it has to say "heard you, working" without
   disabling the control — a disabled submit button is dropped from the POST,
   which would silently change what some forms mean. pointer-events stops the
   second click; the guard stops the second Enter. */
form[data-submitting] button[type="submit"],
form[data-submitting] input[type="submit"] {
  opacity: 0.65;
  cursor: progress;
  pointer-events: none;
}

/* Global form input styles — applies to every form-rendering page */
input[type="text"], input[type="email"], input[type="password"],
input[type="url"], input[type="number"], input[type="search"],
select, textarea {
  width: 100%;
  padding: 0.5rem 0.75rem;
  font-size: 0.875rem;
  font-family: inherit;
  border: 1px solid var(--border-strong);
  border-radius: 0.5rem;
  background: var(--surface);
  color: var(--text);
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
  box-sizing: border-box;
}
input[type="checkbox"] { width: auto; }
input:focus, select:focus, textarea:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(229,97,31,.12);
}
label { font-size: 0.875rem; font-weight: 500; color: var(--text); display: block; margin-bottom: 0.25rem; }
form p { margin-bottom: 1rem; }
.helptext { font-size: 0.75rem; color: var(--muted); margin-top: 0.25rem; display: block; }
.errorlist { font-size: 0.8rem; color: #D8443F; margin-top: 0.25rem; padding: 0; list-style: none; }

/* Shared button style */
.btn-primary {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.5rem 1.25rem;
  background: var(--accent); color: #fff;
  font-family: "Space Grotesk", sans-serif; font-weight: 600; font-size: 0.875rem;
  border: none; border-radius: 0.5rem; cursor: pointer;
  transition: background 0.15s;
  white-space: nowrap;
}
.btn-primary:hover { background: var(--accent-bright); }
.btn-secondary {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.5rem 1rem;
  background: var(--surface); color: var(--text);
  font-size: 0.875rem; font-weight: 500;
  border: 1px solid var(--border-strong); border-radius: 0.5rem; cursor: pointer;
  transition: background 0.15s;
  white-space: nowrap;
}
.btn-secondary:hover { background: var(--surface-2); }
.btn-danger {
  display: inline-flex; align-items: center;
  padding: 0.5rem 1rem;
  background: #D8443F; color: #fff;
  font-size: 0.875rem; font-weight: 500;
  border: none; border-radius: 0.5rem; cursor: pointer;
  white-space: nowrap;
}
/* ---------------------------------------------------------------------------
   Primary navigation, and its collapse.

   The row is a single line of links with no wrapping, so on a narrow viewport
   it simply overflowed the screen: nothing was hidden, everything was just
   unreachable to the right of the fold. base.html had no width-based media
   query at all, so this is the first one.

   Rule: below 48rem the inline links are replaced by a button that opens the
   same list as a panel. Above it, byte-for-byte the nav that was there before.
   48rem because the widest case — an owner of a workspace with a team — needs
   about 630px for six links plus the logo and the avatar, and 768px of
   viewport leaves 720px after the row's padding.

   The panel is a <details>, like the account menu beside it: no JavaScript,
   which matters under a CSP that forbids inline script, and it closes on the
   navigation because the page is replaced.
   --------------------------------------------------------------------------- */
.nav-links {
  display: flex;
  align-items: center;
  gap: 1.5rem;
}
.nav-link {
  font-size: .875rem;
  color: var(--muted);
  transition: color .15s ease;
  white-space: nowrap;
}
.nav-link:hover { color: var(--text); }

.nav-menu {
  position: relative;
  display: none;
}
.nav-menu summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  color: var(--muted);
  /* A tap target, not a 20px glyph. */
  padding: .4rem;
  margin: -.4rem;
  border-radius: .5rem;
}
.nav-menu summary::-webkit-details-marker { display: none; }
.nav-menu[open] summary,
.nav-menu summary:hover { color: var(--text); }
.nav-panel {
  position: absolute;
  left: 0;
  top: calc(100% + .75rem);
  width: min(14rem, calc(100vw - 2rem));
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: .75rem;
  box-shadow: 0 18px 48px -24px rgba(20,22,26,.35);
  overflow: hidden;
  /* Above the account panel's 80 is unnecessary; matching it is enough,
     since only one <details> is ever open at a time in practice. */
  z-index: 80;
}
.nav-panel .nav-link {
  display: block;
  padding: .7rem 1rem;
  color: var(--text);
  font-weight: 600;
}
.nav-panel .nav-link:hover { background: var(--surface-2); }

@media (max-width: 48rem) {
  .nav-links { display: none; }
  .nav-menu { display: block; }
}

.account-menu {
  position: relative;
  margin-left: auto;
}
.account-menu summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  cursor: pointer;
  color: var(--muted);
}
.account-menu summary::-webkit-details-marker { display: none; }
.account-avatar {
  width: 2rem;
  height: 2rem;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: "Space Grotesk", sans-serif;
  font-size: .82rem;
  font-weight: 700;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 11%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--border));
}
.account-menu[open] .account-avatar,
.account-menu summary:hover .account-avatar {
  background: color-mix(in srgb, var(--accent) 16%, var(--surface));
}
.account-panel {
  position: absolute;
  right: 0;
  top: calc(100% + .75rem);
  width: min(18rem, calc(100vw - 2rem));
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: .75rem;
  box-shadow: 0 18px 48px -24px rgba(20,22,26,.35);
  overflow: hidden;
  z-index: 80;
}
.account-panel-header {
  padding: .9rem 1rem;
  background: var(--surface-2);
}
.account-panel-header {
  border-bottom: 1px solid var(--border);
}
.account-panel-footer {
  border-top: 1px solid var(--border);
  background: var(--surface-2);
}
/* Label over description rather than side by side: the descriptions are
   long enough that a two-column row left the headings looking like the
   narrow half of a table. */
.account-panel-link,
.account-panel button.account-panel-link {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .15rem;
  padding: .7rem 1rem;
  color: var(--text);
  font-size: .875rem;
  text-align: left;
}
a.account-panel-link > span:first-child {
  font-weight: 600;
}
.account-panel-desc {
  font-size: .75rem;
  line-height: 1.35;
  color: var(--muted);
}
.account-panel-link:hover,
.account-panel button.account-panel-link:hover {
  background: var(--surface-2);
}
/* Tag colours — an optional hue per tag, carried by data-color so the
   palette lives here in CSS and never as a style attribute built from the
   database. A tag with no colour simply has no data-color and stays plain. */
[data-color="red"] { --tag-hue: var(--tag-red); }
[data-color="amber"] { --tag-hue: var(--tag-amber); }
[data-color="green"] { --tag-hue: var(--tag-green); }
[data-color="teal"] { --tag-hue: var(--tag-teal); }
[data-color="blue"] { --tag-hue: var(--tag-blue); }
[data-color="violet"] { --tag-hue: var(--tag-violet); }
[data-color="pink"] { --tag-hue: var(--tag-pink); }
[data-color="slate"] { --tag-hue: var(--tag-slate); }

.tag-chip {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .1rem .55rem; border-radius: 999px;
  font-size: .75rem; line-height: 1.6;
  background: var(--bg-2); color: var(--text);
  border: 1px solid var(--border);
}
.tag-chip:hover { border-color: var(--border-strong); }
.tag-chip[data-color] {
  background: color-mix(in srgb, var(--tag-hue) 12%, var(--surface));
  border-color: color-mix(in srgb, var(--tag-hue) 38%, transparent);
  color: var(--tag-hue);
}
.tag-chip[data-color]:hover {
  border-color: color-mix(in srgb, var(--tag-hue) 60%, transparent);
}
[data-theme="dark"] .tag-chip[data-color] {
  background: color-mix(in srgb, var(--tag-hue) 18%, var(--surface));
  border-color: color-mix(in srgb, var(--tag-hue) 34%, transparent);
}
/* Small filled dot for places that keep neutral text — filter lists, menus. */
.tag-dot {
  display: inline-block; flex: none;
  width: .5rem; height: .5rem; border-radius: 999px;
  background: var(--tag-hue, transparent);
  border: 1px solid var(--tag-hue, var(--border-strong));
}

/* Changes-by-tag rows — the dashboard rollup card. The bar's width is the
   only thing the template sets inline (a percentage we compute); the hue
   still comes from data-color, never from a stored colour string. */
.tag-change-row {
  display: grid;
  grid-template-columns: minmax(0, auto) minmax(1.5rem, 1fr) auto;
  align-items: center;
}
.tag-bar {
  height: .375rem; border-radius: 999px;
  background: var(--bg-2); overflow: hidden;
}
.tag-bar > span {
  display: block; height: 100%; border-radius: 999px;
  background: var(--tag-hue, var(--accent));
}

/* Colour swatches — the radio row on the Tags page */
.swatches { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem; }
.swatch { position: relative; display: inline-flex; margin: 0; }
.swatch input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.swatch input + span {
  display: block; width: 1.15rem; height: 1.15rem; border-radius: 999px;
  background: var(--tag-hue, var(--surface-2));
  border: 1px solid var(--tag-hue, var(--border-strong));
  cursor: pointer;
}
.swatch input:checked + span {
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 3.5px var(--tag-hue, var(--border-strong));
}
.swatch input:focus-visible + span {
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 3.5px var(--accent);
}

/* Tag picker — checkbox pills on the monitor create/edit forms */
.tag-picker { display: flex; flex-wrap: wrap; gap: .4rem; }
.tag-pick { position: relative; display: inline-flex; margin: 0; }
.tag-pick input[type="checkbox"] { position: absolute; opacity: 0; width: 1px; height: 1px; }
.tag-pick span {
  display: inline-block;
  padding: .3rem .75rem;
  border: 1px solid var(--border-strong); border-radius: 999px;
  background: var(--surface); color: var(--text);
  font-size: .8125rem; font-weight: 500;
  cursor: pointer; user-select: none;
}
.tag-pick span:hover { background: var(--surface-2); }
/* The colour lives on the input, so hand it to the pill beside it. */
.tag-pick input[data-color="red"] + span { --tag-hue: var(--tag-red); }
.tag-pick input[data-color="amber"] + span { --tag-hue: var(--tag-amber); }
.tag-pick input[data-color="green"] + span { --tag-hue: var(--tag-green); }
.tag-pick input[data-color="teal"] + span { --tag-hue: var(--tag-teal); }
.tag-pick input[data-color="blue"] + span { --tag-hue: var(--tag-blue); }
.tag-pick input[data-color="violet"] + span { --tag-hue: var(--tag-violet); }
.tag-pick input[data-color="pink"] + span { --tag-hue: var(--tag-pink); }
.tag-pick input[data-color="slate"] + span { --tag-hue: var(--tag-slate); }
.tag-pick input[data-color] + span::before {
  content: ""; display: inline-block;
  width: .45rem; height: .45rem; margin-right: .35rem;
  border-radius: 999px; background: var(--tag-hue); vertical-align: middle;
}
.tag-pick input[data-color]:checked + span::before { background: #fff; }
.tag-pick input:checked + span {
  background: var(--accent); border-color: var(--accent); color: #fff;
}
.tag-pick input:focus-visible + span { box-shadow: 0 0 0 3px rgba(229,97,31,.25); }

/* Tag filter — multi-select panel on the monitors list */
.tag-filter { position: relative; }
.tag-filter-summary {
  list-style: none;
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  padding: .55rem .7rem;
  border: 1px solid var(--border-strong); border-radius: .5rem;
  background: var(--surface); color: var(--text);
  font-size: .875rem; cursor: pointer;
}
.tag-filter-summary::-webkit-details-marker { display: none; }
.tag-filter[open] .tag-filter-chevron { transform: rotate(180deg); }
.tag-filter-panel {
  position: absolute; z-index: 60;
  top: calc(100% + .35rem); left: 0;
  min-width: max(100%, 15rem);
  padding: .6rem;
  background: var(--surface);
  border: 1px solid var(--border); border-radius: .6rem;
  box-shadow: 0 18px 48px -24px rgba(20,22,26,.35);
}
.tag-filter-modes {
  display: flex; gap: .9rem; margin-top: .5rem;
  font-size: .75rem; color: var(--muted);
}
.tag-filter-modes label { display: inline-flex; align-items: center; gap: .3rem; margin: 0; font-weight: 400; }
.tag-filter-list { max-height: 15rem; overflow-y: auto; margin-top: .4rem; }
.tag-filter-option {
  display: flex; align-items: center; gap: .5rem;
  margin: 0; padding: .3rem .35rem; border-radius: .4rem;
  font-weight: 400; cursor: pointer;
}
.tag-filter-option:hover { background: var(--surface-2); }

/* Saved views — the picker reuses .tag-filter for the dropdown shell and
   adds only what differs: rows are links, not checkboxes. */
.saved-views-bar {
  display: flex; align-items: center; gap: .6rem;
  flex-wrap: wrap; margin-bottom: .75rem;
}
.saved-view-picker { min-width: 190px; }
.saved-view-panel { min-width: 260px; }
.saved-view-option {
  display: flex; align-items: center; gap: .45rem;
  padding: .3rem .35rem; border-radius: .4rem;
  font-size: .8125rem; color: var(--text);
}
.saved-view-option:hover { background: var(--surface-2); }
.saved-view-option.is-active { background: var(--surface-2); font-weight: 600; }
.saved-view-star { flex: none; width: .8rem; color: var(--accent); }
.saved-view-hint {
  margin-left: auto; flex: none;
  font-size: .6875rem; color: var(--muted); font-weight: 400;
}
.saved-view-divider { border-top: 1px solid var(--border); margin: .5rem 0; }
.saved-view-save { margin: 0 .35rem; }
.saved-view-manage {
  display: block; margin-top: .5rem; padding: .3rem .35rem;
  font-size: .75rem; color: var(--accent);
}
.saved-view-manage:hover { text-decoration: underline; }

.filter-chip {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .2rem .55rem; border-radius: 999px;
  border: 1px solid var(--border); background: var(--bg-2);
  color: var(--text); font-size: .75rem;
}
.filter-chip:hover { border-color: var(--border-strong); }

/* Bulk selection — the monitors table's own header strip. It is always
   present (so checking a box never reflows the page) and sticks under the
   nav, which is why the card around it must not clip overflow. */
.table-card {
  background: var(--surface);
  border: 1px solid var(--border); border-radius: .75rem;
}
/* No overflow clipping here: the tag pickers inside the strip open as
   absolutely-positioned popovers and must be allowed to escape it. The
   table below does the corner-rounding for its own end of the card. */
.bulk-strip {
  position: sticky; top: calc(3.5rem + 1px); z-index: 30;
}
.table-wrap { overflow: hidden; border-radius: 0 0 .75rem .75rem; }
.bulk-bar {
  display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
  min-height: 3rem; padding: .5rem .9rem;
  background: var(--bg); border-bottom: 1px solid var(--border);
  border-radius: .75rem .75rem 0 0;
  font-size: .8125rem; color: var(--muted);
}
/* Tinted while a selection is live, so the strip's change of mode reads at
   a glance rather than only through its wording. */
.bulk-bar.is-selecting {
  background: color-mix(in srgb, var(--accent) 9%, var(--surface));
  color: var(--text);
}
.bulk-count { font-weight: 600; color: var(--text); white-space: nowrap; }
.bulk-actions { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.bulk-result { margin-left: auto; font-size: .75rem; }
.btn-sm { padding: .35rem .7rem; font-size: .8125rem; gap: .35rem; }
.bulk-link {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--accent); font-size: .8125rem; font-weight: 500;
  text-decoration: underline; text-underline-offset: 2px;
}
.bulk-scope {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  padding: .45rem .9rem;
  background: color-mix(in srgb, var(--accent) 5%, var(--surface));
  border-bottom: 1px solid var(--border);
  font-size: .75rem; color: var(--muted);
}
.bulk-panel {
  padding: .85rem .9rem;
  background: var(--surface); border-bottom: 1px solid var(--border);
}
.bulk-fields {
  display: grid; gap: .75rem;
  /* auto-fill, not auto-fit: leftover tracks stay empty rather than
     stretching two fields across the full width of a wide table. */
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
.bulk-field > span {
  display: block; margin-bottom: .25rem;
  font-family: var(--font-mono, monospace);
  font-size: .6875rem; letter-spacing: .02em; color: var(--muted);
}
.bulk-field select {
  width: 100%; font-size: .8125rem; border-radius: .5rem;
  padding: .45rem .55rem;
  border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text);
}
/* A checkbox field sits on the same grid track as the selects, but its
   control is inline with its label rather than stacked under a caption. */
.bulk-field-check { display: flex; flex-direction: column; justify-content: flex-end; }
.bulk-check {
  display: flex; align-items: center; gap: .45rem;
  font-size: .8125rem; color: var(--text); cursor: pointer;
  padding: .45rem 0;
}
.bulk-check input { width: auto; cursor: pointer; }
.bulk-panel-foot {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  margin-top: .75rem;
}
.bulk-panel-hint { font-size: .75rem; color: var(--muted); }

/* Quota (decisions doc §6). The counter is always on screen, so its
   resting state has to be quiet — it only earns colour as the workspace
   approaches, and then reaches, its limit. */
.quota-pill {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .2rem .55rem; border-radius: 999px;
  border: 1px solid var(--border); background: var(--surface);
  font-size: .75rem; color: var(--muted); white-space: nowrap;
}
.quota-pill strong { color: var(--text); font-weight: 600; }
.quota-pill.is-near { border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); }
.quota-pill.is-full {
  border-color: #D8443F; color: #D8443F;
  background: color-mix(in srgb, #D8443F 8%, var(--surface));
}
.quota-pill.is-full strong { color: #D8443F; }
.quota-pill-link { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.quota-notice, .quota-banner {
  border-radius: .75rem; padding: .85rem 1rem;
  font-size: .8125rem; line-height: 1.5;
}
.quota-notice {
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--border));
  background: color-mix(in srgb, var(--accent) 6%, var(--surface));
  color: var(--text);
}
.quota-notice a, .quota-banner a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
/* Louder than the at-limit notice: this one says monitoring has stopped on
   named pages, which is the most consequential thing this app can tell
   somebody. */
.quota-banner {
  border: 1px solid #D8443F;
  background: color-mix(in srgb, #D8443F 6%, var(--surface));
  color: var(--text);
}
.quota-banner-list {
  margin: .6rem 0 0; padding: 0; list-style: none;
  display: flex; flex-wrap: wrap; gap: .35rem .5rem;
}
.quota-banner-list li {
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  padding: .15rem .5rem; border-radius: .375rem;
  background: var(--surface); border: 1px solid var(--border);
  font-size: .75rem;
}
.quota-banner-more { color: var(--muted); }
.quota-banner-actions {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  margin-top: .75rem;
}
.quota-banner-hint { font-size: .75rem; color: var(--muted); }

/* Louder still, and above the page rather than inside it: this one says
   *nothing* in the workspace is being checked. It is what earns the
   dispatcher the right to stop a whole tenant (tasks/dispatch.py,
   due_monitors), so it is deliberately not dismissible and appears on
   every page rather than only on the monitors list. */
.tenant-stopped {
  border-bottom: 1px solid #D8443F;
  background: color-mix(in srgb, #D8443F 12%, var(--surface));
  color: var(--text);
}
.tenant-stopped-inner {
  display: flex; align-items: flex-start; gap: .6rem;
  font-size: .8125rem; line-height: 1.5;
}
.tenant-stopped svg { flex-shrink: 0; margin-top: .15rem; color: #D8443F; }
.tenant-stopped strong { color: #D8443F; }

/* ── Flash messages ──────────────────────────────────────────────────
   A save that redirects to a page identical to the one you submitted is
   indistinguishable from a save that did nothing, which is what every
   settings form in here looked like. This is the confirmation.

   The timed dismissal is a CSS animation, not a JS timer: script-src is
   'self' and a toast whose only way out is a script file is a toast that
   never leaves when that file fails to load. Only success and info fade
   on their own — a warning or an error stays until it is dismissed or the
   page changes, because the point of those is that somebody reads them.

   z-index sits above the nav (50) and below the impersonation banner
   (60), which must never be covered by anything. */
.toast-stack {
  position: fixed; top: 4.5rem; right: 1.25rem; z-index: 55;
  display: flex; flex-direction: column; gap: .5rem;
  width: min(24rem, calc(100vw - 2.5rem));
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  display: flex; align-items: flex-start; gap: .55rem;
  padding: .7rem .8rem;
  border-radius: .6rem;
  font-size: .8125rem; line-height: 1.45;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  box-shadow: 0 10px 28px -10px rgba(20,22,26,.35);
  animation: toast-in .18s ease-out both;
}
.toast > svg { flex-shrink: 0; margin-top: .12rem; }
.toast-success { border-color: rgba(28,157,93,.5); }
.toast-success > svg { color: #1C9D5D; }
.toast-warning { border-color: rgba(180,83,9,.5); }
.toast-warning > svg { color: #B45309; }
.toast-error { border-color: rgba(216,68,63,.5); }
.toast-error > svg { color: #D8443F; }
.toast-info > svg, .toast-debug > svg { color: var(--muted); }
.toast-text { flex: 1 1 auto; min-width: 0; }
.toast-dismiss {
  flex-shrink: 0; background: none; border: 0; cursor: pointer;
  padding: 0 .1rem; line-height: 1; color: var(--muted);
}
.toast-dismiss:hover { color: var(--text); }
/* 5s of reading time, then a short fade. `forwards` holds the end state so
   it does not reappear; `visibility` takes it out of the a11y tree too. */
.toast-autohide {
  animation: toast-in .18s ease-out both,
             toast-out .45s ease-in 5s forwards;
}
@keyframes toast-in {
  from { opacity: 0; transform: translateY(-.4rem); }
  to   { opacity: 1; transform: none; }
}
@keyframes toast-out { to { opacity: 0; visibility: hidden; } }
@media (prefers-reduced-motion: reduce) {
  /* No slide, but still self-dismissing — the timer is the useful half. */
  .toast { animation: none; }
  .toast-autohide { animation: toast-out .45s linear 5s forwards; }
}

/* The loudest thing in the product, on purpose. This says the person
   looking at the screen is not the person the screen belongs to. It sits
   above the nav rather than below it, is not dismissible, and carries its
   own exit — an operator who cannot find the way out is an operator who
   keeps working inside somebody else's account. */
.impersonating {
  background: #6B1D8F;
  color: #fff;
  position: sticky; top: 0; z-index: 60;
  border-bottom: 2px solid #4A1263;
}
.impersonating-inner {
  display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
  font-size: .8125rem; line-height: 1.4;
}
.impersonating svg { flex-shrink: 0; }
.impersonating strong { font-weight: 700; }
.impersonating .impersonating-meta { color: rgba(255,255,255,.75); }
.impersonating .impersonating-exit {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .3rem .9rem;
  background: #fff; color: #4A1263;
  font-family: "Space Grotesk", sans-serif; font-weight: 600; font-size: .8125rem;
  border: none; border-radius: .4rem; cursor: pointer;
  white-space: nowrap;
}
.impersonating .impersonating-exit:hover { background: #F2E6F7; }

/* Logo swap for dark mode */
[data-theme="dark"] .logo-light { display: none !important; }
[data-theme="dark"] .logo-dark { display: inline !important; }

/* Dark mode overrides for Tailwind hardcoded utility classes */
[data-theme="dark"] .bg-white { background-color: var(--surface) !important; }
[data-theme="dark"] .bg-slate-50 { background-color: var(--surface-2) !important; }
[data-theme="dark"] .bg-slate-100 { background-color: var(--bg-2) !important; }
[data-theme="dark"] .bg-slate-200 { background-color: var(--surface-2) !important; }
[data-theme="dark"] .bg-slate-800 { background-color: var(--accent) !important; }
[data-theme="dark"] .border { border-color: var(--border) !important; }
[data-theme="dark"] .border-b { border-bottom-color: var(--border) !important; }
[data-theme="dark"] .border-slate-200,
[data-theme="dark"] .border-slate-300 { border-color: var(--border) !important; }
[data-theme="dark"] .text-slate-900 { color: var(--text) !important; }
[data-theme="dark"] .text-slate-600,
[data-theme="dark"] .text-slate-500 { color: var(--muted) !important; }
[data-theme="dark"] .text-slate-400 { color: var(--faint) !important; }
[data-theme="dark"] .text-blue-700 { color: var(--accent) !important; }
[data-theme="dark"] input:not([type="checkbox"]),
[data-theme="dark"] select,
[data-theme="dark"] textarea { background-color: var(--surface) !important; color: var(--text) !important; border-color: var(--border-strong) !important; }
[data-theme="dark"] .hover\:bg-slate-50:hover { background-color: var(--surface-2) !important; }
[data-theme="dark"] table { background-color: var(--surface); color: var(--text); }
