/* Kernel design system.
 *
 * Calm and dense: quiet neutral ground, one teal accent, state colours only where state is
 * shown. Instrument Sans for the interface, IBM Plex Mono for the things people copy —
 * keys, hashes, ids, filenames. Tokens first, then layout, then components.
 *
 * Everything here is served as a file because the Content-Security-Policy forbids inline
 * styles; the fonts are vendored under static/fonts for the same reason (default-src 'self'
 * rules out a font CDN). HTMX's indicator styles are defined here too, because
 * `includeIndicatorStyles` is off.
 */

/* --- fonts ------------------------------------------------------------------------------ */

@font-face {
  font-family: "Instrument Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/instrument-sans-normal-400_700.woff2") format("woff2");
}

@font-face {
  font-family: "Instrument Sans";
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/instrument-sans-italic-400_700.woff2") format("woff2");
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-normal-400.woff2") format("woff2");
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-normal-500.woff2") format("woff2");
}

/* --- tokens ----------------------------------------------------------------------------- */

:root {
  color-scheme: light dark;

  --font-sans: "Instrument Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas,
    "Liberation Mono", monospace;

  /* The design is denser than a default 16px rhythm: 13.5px carries most of the interface,
   * 12.5px the metadata around it. Sizes stay in rem so a reader's own zoom still works. */
  --text-2xs: 0.6875rem;
  --text-xs: 0.75rem;
  --text-sm: 0.78125rem;
  --text-md: 0.84375rem;
  --text-lg: 0.9375rem;
  --text-xl: 1.25rem;
  --text-2xl: 1.625rem;
  --leading: 1.5;

  /* The eyebrow: the uppercase label that titles almost every card in this design. */
  --eyebrow-size: 0.78125rem;
  --eyebrow-spacing: 1px;

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-8: 3rem;

  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 14px;
  --radius-xl: 16px;
  --radius-pill: 999px;

  --sidebar-width: 14.75rem;
  --topbar-height: 3.75rem;
  --content-max: 77.5rem;
  --narrow-max: 25rem;
  --form-max: 44rem;

  --shadow-sm: 0 1px 2px rgba(23, 25, 28, 0.05);
  --shadow: 0 8px 24px rgba(23, 25, 28, 0.08);
  --shadow-md: 0 16px 40px rgba(23, 25, 28, 0.14);
  --shadow-lg: 0 30px 80px rgba(23, 25, 28, 0.3);
  --shadow-accent: 0 4px 14px rgba(15, 139, 132, 0.25);

  --duration: 150ms;

  /* Light palette. Text tokens meet WCAG AA (4.5:1) on every ground they are used on:
   * --text 17.6:1, --text-muted 5.0:1 on --surface-muted (its worst case), --text-faint
   * 4.8:1 on --surface and 4.5:1 on --bg. --accent carries --on-accent at 5.5:1;
   * --accent-bright is the design's #0F8B84 and is never used behind text, only for dots,
   * rings, progress fills and the mark. --danger carries --on-danger at 6.5:1. */
  --bg: #f6f7f8;
  --surface: #ffffff;
  --surface-muted: #f1f3f5;
  --surface-sunken: #eef1f4;
  --border: #e6e8eb;
  /* The hairline between rows inside a card. Lighter than --border on a light ground and
   * lighter than --surface on a dark one -- as a tint of the surface it vanished in dark. */
  --rule: #f1f3f5;
  --border-input: #dde1e5;
  --border-strong: #cbd0d6;
  --text: #17191c;
  --text-secondary: #3b434b;
  --text-muted: #616976;
  --text-faint: #6b7280;
  --text-disabled: #9aa5b1;
  --accent: #0f766e;
  --accent-strong: #0b5f59;
  --accent-bright: #0f8b84;
  --accent-hover: #0b7a73;
  --accent-soft: #e3f4f2;
  --accent-soft-strong: #d9f2ef;
  --on-accent: #ffffff;
  --danger: #b91c1c;
  --danger-strong: #7f1d1d;
  --danger-soft: #fee2e2;
  --on-danger: #ffffff;
  --success: #15803d;
  --success-strong: #116a31;
  --success-soft: #dcfce7;
  --warning: #b45309;
  --warning-strong: #9a4407;
  --warning-soft: #fef3c7;
  --warning-border: #fde3b0;
  --warning-text: #7c5a1e;
  --info-soft: #dbeafe;
  --focus: #0f8b84;

  /* The dark band: a deliberate surface treatment on light pages (the landing page's
   * handoff section, the raw session log), not a theme. */
  --ink: #17191c;
  --ink-raised: #2a2f35;
  --ink-border: #2f343a;
  --ink-text: #d5dae0;
  --ink-text-muted: #b8bec6;
  --ink-text-faint: #8a9199;
  --ink-accent: #8fd1cb;

  --state-backlog: #52606d;
  --state-backlog-soft: #eef1f4;
  --state-backlog-dot: #9aa5b1;
  --state-ready: #1d4ed8;
  --state-ready-soft: #dbeafe;
  --state-ready-dot: #3b82f6;
  --state-running: #0f766e;
  --state-running-soft: #d9f2ef;
  --state-running-dot: #0f8b84;
  --state-waiting: #b45309;
  --state-waiting-soft: #fef3c7;
  --state-waiting-dot: #f59e0b;
  --state-blocked: #b91c1c;
  --state-blocked-soft: #fee2e2;
  --state-blocked-dot: #ef4444;
  --state-review: #6d28d9;
  --state-review-soft: #ede9fe;
  --state-review-dot: #8b5cf6;
  --state-completed: #15803d;
  --state-completed-soft: #dcfce7;
  --state-completed-dot: #22c55e;
  --state-cancelled: #52606d;
  --state-cancelled-soft: #eef1f4;
  --state-cancelled-dot: #9aa5b1;

  --priority-low: #52606d;
  --priority-normal: #1d4ed8;
  --priority-high: #b45309;
  --priority-urgent: #b91c1c;
}

@media (prefers-color-scheme: dark) {
  :root {
    /* Dark palette. Contrast on --surface: --text 15.1:1, --text-muted 8.6:1,
     * --text-faint 6.7:1, --accent 10.2:1; --on-accent on --accent 9.8:1; every state
     * chip clears 7.6:1 on its own soft ground. */
    --bg: #0f1113;
    --surface: #17191c;
    --surface-muted: #1e2125;
    --surface-sunken: #23272c;
    --border: #2f343a;
    --rule: #262b31;
    --border-input: #3a4048;
    --border-strong: #464d56;
    --text: #eceef0;
    --text-secondary: #ced4da;
    --text-muted: #aeb6bf;
    --text-faint: #98a1aa;
    --text-disabled: #79828c;
    --accent: #8fd1cb;
    --accent-strong: #aee0db;
    --accent-bright: #14a79e;
    --accent-hover: #aee0db;
    --accent-soft: #123430;
    --accent-soft-strong: #16403b;
    --on-accent: #08201e;
    --danger: #ff9a90;
    --danger-strong: #ffc0b9;
    --danger-soft: #3a1a17;
    --on-danger: #2b0f0c;
    --success: #7ed694;
    --success-strong: #a5e5b4;
    --success-soft: #12301e;
    --warning: #f0b968;
    --warning-strong: #f7d59b;
    --warning-soft: #3a2c10;
    --warning-border: #4d3c17;
    --warning-text: #e7c78f;
    --info-soft: #16233f;
    --focus: #8fd1cb;

    --ink: #0b0d0f;
    --ink-raised: #1e2125;
    --ink-border: #2f343a;
    --ink-text: #d5dae0;
    --ink-text-muted: #b8bec6;
    --ink-text-faint: #8a9199;
    --ink-accent: #8fd1cb;

    --state-backlog: #aeb6bf;
    --state-backlog-soft: #1e2125;
    --state-backlog-dot: #79828c;
    --state-ready: #9db8ff;
    --state-ready-soft: #16233f;
    --state-ready-dot: #6d93ff;
    --state-running: #8fd1cb;
    --state-running-soft: #123430;
    --state-running-dot: #4fbdb3;
    --state-waiting: #f0b968;
    --state-waiting-soft: #3a2c10;
    --state-waiting-dot: #e0a244;
    --state-blocked: #ff9a90;
    --state-blocked-soft: #3a1a17;
    --state-blocked-dot: #f4756a;
    --state-review: #c3b4ff;
    --state-review-soft: #241d40;
    --state-review-dot: #a48bff;
    --state-completed: #7ed694;
    --state-completed-soft: #12301e;
    --state-completed-dot: #4cc46c;
    --state-cancelled: #aeb6bf;
    --state-cancelled-soft: #1e2125;
    --state-cancelled-dot: #79828c;

    --priority-low: #aeb6bf;
    --priority-normal: #9db8ff;
    --priority-high: #f0b968;
    --priority-urgent: #ff9a90;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
    --shadow-md: 0 16px 40px rgba(0, 0, 0, 0.6);
    --shadow-lg: 0 30px 80px rgba(0, 0, 0, 0.7);
    --shadow-accent: 0 4px 14px rgba(0, 0, 0, 0.5);
  }
}

/* --- base ------------------------------------------------------------------------------- */

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

html {
  font-family: var(--font-sans);
  font-size: 100%;
  line-height: var(--leading);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  font-size: var(--text-md);
  -webkit-font-smoothing: antialiased;
}

/* Headings are tight and slightly negative-tracked; the larger they get, the tighter they
 * set. `balance` keeps a two-line title from leaving one orphaned word. */
/* No global `overflow-wrap: anywhere`. It looks harmless and is not: `auto` table layout
 * sizes a column to its longest word, so a document-wide "any character may end a line"
 * makes every column's floor one character. The registry collapsed to one letter per line
 * the first time this was tried. Elements that must break long values ask for it by name
 * (`.prose`, `.runtime-path`, `.digest-full`, `.markdown`), and
 * tests/e2e/test_registry_overflow.py asserts the laid-out widths, not the declarations. */
h1,
h2,
h3 {
  margin: 0 0 var(--space-3);
  line-height: 1.2;
  font-weight: 700;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

h1 {
  font-size: var(--text-2xl);
  letter-spacing: -0.023em;
}

h2 {
  font-size: var(--text-lg);
  letter-spacing: -0.013em;
}

h3 {
  font-size: var(--text-md);
  letter-spacing: -0.01em;
}

p {
  margin: 0 0 var(--space-3);
  text-wrap: pretty;
}

a {
  color: var(--accent);
  text-decoration: none;
}

a:hover {
  color: var(--accent-strong);
  text-decoration: underline;
}

ul,
ol {
  margin: 0 0 var(--space-3);
  padding-left: 1.25rem;
}

ul[role="list"] {
  list-style: none;
  padding: 0;
}

code,
kbd,
.mono {
  font-family: var(--font-mono);
}

code {
  font-size: 0.92em;
}

/* The key-cap look the shortcut legends use, borrowed from the design's inline hints. */
kbd {
  display: inline-block;
  min-width: 1.5em;
  padding: 2px var(--space-2);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text-secondary);
  font-family: inherit;
  font-size: var(--text-xs);
  font-weight: 600;
  text-align: center;
}

/* Work keys, hashes, ids and filenames: the things people copy out of the page. */
.key,
.hash,
.mono {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

time {
  white-space: nowrap;
}

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

[hidden] {
  display: none !important;
}

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: -100%;
  left: var(--space-2);
  z-index: 100;
  padding: var(--space-2) var(--space-3);
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.skip-link:focus {
  top: var(--space-2);
}

.muted {
  color: var(--text-muted);
}

.meta {
  color: var(--text-faint);
  font-size: var(--text-sm);
  margin: 0;
}

/* The eyebrow titles nearly every card in this design: small, uppercase, wide-tracked. */
.eyebrow {
  margin: 0 0 var(--space-1);
  font-size: var(--eyebrow-size);
  font-weight: 700;
  letter-spacing: var(--eyebrow-spacing);
  text-transform: uppercase;
  color: var(--text-muted);
}

.prose {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Values a person copies rather than reads -- ids, hashes, URLs -- may break anywhere,
 * because the alternative is a row that pushes the page sideways. */
.work-title,
.inbox-title,
.timeline-summary,
.card-title {
  overflow-wrap: anywhere;
}

/* A state dot: the 8px mark that carries state where a full chip would be too loud. */
.dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  flex: none;
  border-radius: 50%;
  background: currentColor;
}

/* --- public shell ----------------------------------------------------------------------- */

.public-shell {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  /* The sign-in surfaces sit on a soft teal wash rather than the flat application grey:
   * the one place in the product where the brand is allowed to be the loudest thing. */
  background:
    radial-gradient(70% 50% at 50% 0%, var(--accent-soft-strong) 0%, var(--bg) 60%)
    no-repeat;
}

.public-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
}

.public-main {
  flex: 1;
  width: 100%;
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--space-6) var(--space-4);
  /* Sign-in and registration are one card on an otherwise empty page; centring it keeps the
   * teal wash behind it rather than above it. Pages with real content (onboarding, an
   * invitation) fill the column and are unaffected. */
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.public-main > * {
  width: 100%;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.02em;
  font-size: var(--text-lg);
}

.brand:hover {
  color: var(--text);
  text-decoration: none;
}

.brand-mark {
  width: 28px;
  height: 28px;
  flex: none;
  border-radius: 9px;
}

.brand-mark-sm {
  width: 22px;
  height: 22px;
  border-radius: 7px;
}

/* --- application shell ------------------------------------------------------------------ */

/* The shell is a two-column flex: a full-height sidebar carrying the brand, the
 * organization switcher, the navigation and the signed-in person; and a column holding a
 * sticky top bar over the page itself. */
.app-shell {
  min-height: 100vh;
  display: flex;
}

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

/* Stacking, bottom to top: page content (0) < drawer backdrop (30) < drawer (35) <
 * topbar with the Menu button (40); dialogs live in the browser's top layer. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  height: var(--topbar-height);
  padding: 0 var(--space-5);
  /* Translucent over the page ground so content scrolling underneath stays hinted at.
   * The solid colour goes first on purpose: an engine without color-mix() drops that
   * declaration and keeps this one, where dropping both would leave the bar transparent
   * over scrolling content. -webkit- for Safari before 18, which blurs only prefixed. */
  background: var(--bg);
  background: color-mix(in srgb, var(--bg) 85%, transparent);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
}

.topbar > * {
  min-width: 0;
}

.topbar .nav-toggle,
.topbar .create-work {
  flex-shrink: 0;
}

.topbar-spacer {
  flex: 1;
}

.topbar .search {
  position: relative;
  flex: 1;
  max-width: 32.5rem;
}

.topbar .search-input {
  width: 100%;
  background: var(--surface);
}

/* The type-ahead dropdown hangs off the search wrapper, under the top bar's own layer so it
 * is never covered by it. kernel.js toggles the ``hidden`` attribute; ``[hidden]`` already
 * wins in the base reset, so nothing here needs to fight it. */
.search-results {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  left: 0;
  z-index: 45;
  max-height: min(70vh, 32rem);
  overflow-y: auto;
  padding: var(--space-1);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-md);
}

.search-note {
  margin: 0;
  padding: var(--space-3);
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* The no-match state reuses the shared empty macro; inside the dropdown it is trimmed down
 * so it reads as a line, not a full page. */
.search-results .empty-state {
  padding: var(--space-4) var(--space-3);
  border: 0;
  background: none;
}

.search-results .empty-state .empty-title {
  font-size: var(--text-md);
}

.search-group + .search-group {
  margin-top: var(--space-1);
  border-top: 1px solid var(--border);
  padding-top: var(--space-1);
}

.search-group-label {
  margin: 0;
  padding: var(--space-2) var(--space-3) var(--space-1);
  color: var(--text-faint);
  font-size: var(--text-2xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.search-group ul {
  margin: 0;
}

.search-result {
  display: block;
  padding: var(--space-2) var(--space-3);
  border-radius: 8px;
  color: var(--text);
}

.search-result:hover,
.search-result:focus {
  background: var(--accent-soft);
  color: var(--accent-strong);
  text-decoration: none;
  outline: none;
}

.search-result-head {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}

.search-result-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--text-sm);
  font-weight: 500;
}

.search-result-key {
  flex-shrink: 0;
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

.search-result-snippet {
  display: block;
  overflow: hidden;
  color: var(--text-muted);
  font-size: var(--text-xs);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.search-result:focus .search-result-key,
.search-result:hover .search-result-key,
.search-result:focus .search-result-snippet,
.search-result:hover .search-result-snippet {
  color: inherit;
}

/* The sidebar. */

.sidebar {
  position: sticky;
  top: 0;
  height: 100vh;
  width: var(--sidebar-width);
  flex: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  border-right: 1px solid var(--border);
  background: var(--surface);
  padding: var(--space-4) 14px;
  overflow-y: auto;
}

.sidebar .brand {
  padding: var(--space-1) var(--space-2);
  font-size: 1.03125rem;
}

.sidebar-nav {
  min-width: 0;
}

.sidebar-nav ul {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0;
}

/* Navigation items carry a dot rather than an icon: this product has no icon set, and a
 * dot that takes the item's own colour says "here" without inventing a pictogram for
 * "Analytics". The dot is decorative, so it is drawn rather than written. */
.sidebar-nav a {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-2);
  border-radius: var(--radius);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: 500;
  transition: background var(--duration);
}

.sidebar-nav a::before {
  content: "";
  width: 8px;
  height: 8px;
  flex: none;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.45;
}

.sidebar-nav a:hover {
  background: var(--surface-muted);
  color: var(--text);
  text-decoration: none;
}

.sidebar-nav a[aria-current="page"] {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}

.sidebar-nav a[aria-current="page"]::before {
  opacity: 1;
}

/* The signed-in person and the account actions sit at the foot of the rail. */
.sidebar-footer {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-top: var(--space-3);
  border-top: 1px solid var(--border);
}

.sidebar-user {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

.sidebar-user-name {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--text-sm);
  font-weight: 600;
}

.sidebar-user-meta {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-muted);
  font-size: var(--text-2xs);
}

.app-main {
  position: relative;
  z-index: 0; /* one stacking context for the page, always below the backdrop */
  flex: 1;
  min-width: 0;
  width: 100%;
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 28px 32px 60px;
}

/* The drawer toggle exists for narrow screens only; the compound selector outranks the
 * later ``.btn { display: inline-flex }`` rule, which otherwise showed it everywhere. */
.topbar .nav-toggle {
  display: none;
}

.backdrop {
  position: fixed;
  inset: 0;
  z-index: 30;
  background: rgba(23, 25, 28, 0.45);
}

@media (max-width: 900px) {
  .topbar .nav-toggle {
    display: inline-flex;
  }

  .topbar {
    padding: 0 var(--space-3);
    gap: var(--space-2);
  }

  /* The drawer fades rather than slides: its geometry is final the instant it opens, so a
   * tap "beside the drawer" lands on the backdrop in every browser (a sliding drawer
   * could still be moving under the finger). Closing fades out, then jumps off-screen. */
  /* The drawer starts under the top bar, which stays above it: the Menu button that opened
   * it has to remain visible and pressable to close it again. */
  .sidebar {
    position: fixed;
    top: var(--topbar-height);
    bottom: 0;
    left: 0;
    z-index: 35;
    height: auto;
    max-width: 85vw;
    opacity: 0;
    transform: translateX(-100%);
    transition:
      opacity var(--duration) ease-out,
      transform 0s linear var(--duration);
    box-shadow: none;
  }

  body.nav-open .sidebar {
    opacity: 1;
    transform: none;
    transition:
      opacity var(--duration) ease-out,
      transform 0s;
    box-shadow: var(--shadow-lg);
  }

  .app-main {
    padding: 20px 16px 48px;
  }
}

@media (max-width: 720px) {
  .topbar .search {
    display: none;
  }

  .org-switcher summary,
  .user-menu summary {
    max-width: 8rem;
  }
}

/* --- menus (details/summary) ------------------------------------------------------------ */

.menu {
  position: relative;
  min-width: 0;
}

.menu summary {
  display: block;
  list-style: none;
  cursor: pointer;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.menu summary::-webkit-details-marker {
  display: none;
}

.menu summary::after {
  content: " \25BE";
  color: var(--text-disabled);
}

/* The organization switcher reads as a control rather than a link: it changes which
 * tenant's data the whole rail is describing. */
.org-switcher-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-2) var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: 1.4;
}

.org-switcher-summary:hover {
  background: var(--surface-muted);
}

.user-menu-summary {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2);
  border-radius: var(--radius);
  min-width: 0;
}

.user-menu-summary:hover {
  background: var(--surface-muted);
}

.user-menu summary.user-menu-summary::after {
  content: none;
}

.user-menu-summary > .sidebar-user {
  flex: 1;
  min-width: 0;
  display: block;
}

.menu-list {
  position: absolute;
  top: calc(100% + var(--space-1));
  right: 0;
  z-index: 40;
  min-width: 12rem;
  margin: 0;
  padding: var(--space-2);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-md);
}

.org-switcher .menu-list {
  left: 0;
  right: auto;
}

/* In the rail the account menu opens upwards: it sits at the bottom of a full-height
 * column, so downwards would run off the screen. */
.user-menu .menu-list {
  top: auto;
  bottom: calc(100% + var(--space-1));
  left: 0;
  right: 0;
}

.menu-list a,
.menu-list .btn {
  display: block;
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text);
  font-size: var(--text-sm);
  text-align: left;
  white-space: nowrap;
}

.menu-list a:hover,
.menu-list .btn:hover {
  background: var(--surface-muted);
  text-decoration: none;
}

.menu-list a[aria-current="true"] {
  font-weight: 600;
  color: var(--accent);
}

.menu-separator {
  margin-top: var(--space-2);
  padding-top: var(--space-2);
  border-top: 1px solid var(--border);
}

/* --- page header ------------------------------------------------------------------------ */

.page-header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3) var(--space-4);
  margin-bottom: 18px;
}

.page-header h1 {
  margin-bottom: 0;
}

.page-header > div:first-child {
  flex: 1 1 16rem;
  min-width: 0;
}

/* A few pages put the title and its sentence straight into the header rather than wrapping
 * them. The subtitle then takes its own line under the title row, so any actions still sit
 * beside the title rather than below the sentence. */
.page-header > h1 {
  flex: 1 1 16rem;
  min-width: 0;
}

.page-header > .page-subtitle {
  flex: 1 1 100%;
  order: 10;
  margin-top: 0;
}

/* The sentence under a page title: what this screen is for, in one line. */
.page-subtitle {
  margin: 4px 0 0;
  color: var(--text-muted);
  font-size: var(--text-md);
}

.page-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-left: auto;
}

/* The keys a page supports, shown on the page that supports them. Decorative to a screen
 * reader: the shortcuts dialog is the accessible list, and every key is a shortcut for
 * something Tab and Enter already do. */
.keyboard-legend {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 0 auto;
  color: var(--text-muted);
  font-size: var(--text-xs);
}

@media (max-width: 900px) {
  .keyboard-legend {
    display: none;
  }
}

/* Underline tabs. The active one is marked in ink, not in the accent: on a page that
 * already carries state colours, a teal underline reads as another status. */
.tab-strip {
  display: flex;
  gap: var(--space-1);
  overflow-x: auto;
  scrollbar-width: none;
  border-bottom: 1px solid var(--border);
  margin: 22px 0 20px;
  width: 100%;
}

.tab-strip::-webkit-scrollbar {
  display: none;
}

.page-header .tab-strip {
  width: auto;
  margin: 0;
  border-bottom: 0;
}

.tab-strip a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-bottom: -1px;
  padding: var(--space-2) var(--space-3);
  border-bottom: 2px solid transparent;
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: 600;
  white-space: nowrap;
}

.tab-strip a:hover {
  color: var(--text);
  text-decoration: none;
}

.tab-strip a[aria-current="page"] {
  color: var(--text);
  border-bottom-color: var(--text);
}

/* --- buttons ---------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 2.125rem;
  padding: 0 14px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
  white-space: nowrap;
  transition:
    background-color var(--duration),
    border-color var(--duration),
    color var(--duration);
}

.btn:hover {
  text-decoration: none;
}

.btn:disabled,
.btn[aria-disabled="true"] {
  background: var(--surface-muted);
  border-color: var(--border);
  color: var(--text-disabled);
  cursor: not-allowed;
}

/* The one teal button on a page: the thing this screen is for. */
.btn-primary {
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: var(--shadow-accent);
}

.btn-primary:hover {
  background: var(--accent-hover);
}

.btn-secondary {
  background: var(--surface);
  color: var(--text);
  border-color: var(--border-input);
}

.btn-secondary:hover {
  background: var(--bg);
}

/* Ink: an affirmative action that is not *the* action -- confirming an inbox item, say,
 * where a teal button beside a teal state chip would read as decoration. */
.btn-ink {
  background: var(--text);
  color: var(--surface);
}

.btn-ink:hover {
  background: var(--text-secondary);
}

.btn-danger {
  background: var(--danger);
  color: var(--on-danger);
}

.btn-danger:hover {
  background: var(--danger-strong);
}

.btn-quiet {
  background: transparent;
  color: var(--text);
}

.btn-quiet:hover {
  background: var(--surface-muted);
}

/* A destructive action offered among ordinary ones: outlined, not filled, so the page does
 * not shout before the person has chosen anything. */
.btn-danger-quiet {
  background: var(--surface);
  border-color: var(--border-input);
  color: var(--danger);
}

.btn-danger-quiet:hover {
  background: var(--danger-soft);
}

.btn-small {
  min-height: 1.875rem;
  padding: 0 var(--space-3);
  font-size: var(--text-xs);
}

.btn-plus {
  font-size: var(--text-xl);
  font-weight: 400;
  line-height: 0;
}

/* --- forms ------------------------------------------------------------------------------ */

/* A form is a column of controls, and a control wider than the sentence that labels it is
 * harder to read, not easier. Forms cap at a measure; a form inside a dialog or a filter
 * bar sets its own width and opts out. */
.form {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-width: var(--form-max);
}

.dialog .form,
.filter-bar .form,
.form-inline {
  max-width: none;
}

.form-inline {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: flex-end;
}

.inline-form {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.field-inline {
  flex-direction: row;
  align-items: center;
  gap: var(--space-2);
}

.field-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-4);
}

label {
  font-size: var(--text-xs);
  font-weight: 600;
}

.input {
  width: 100%;
  min-height: 2.375rem;
  padding: 10px 12px;
  border: 1px solid var(--border-input);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: var(--text-md);
  transition:
    border-color var(--duration),
    box-shadow var(--duration);
}

.input:hover:not(:disabled) {
  border-color: var(--border-strong);
}

/* Checkboxes and radios stay native -- they are the controls the platform already makes
 * accessible and keyboard-operable -- but they take the brand's tick instead of the
 * browser's default blue, which is the one colour on these pages that belongs to nothing. */
input[type="checkbox"],
input[type="radio"] {
  accent-color: var(--accent-bright);
}

.input:disabled,
.input[readonly] {
  background: var(--bg);
  color: var(--text-muted);
}

.field-inline .input {
  width: auto;
}

.textarea {
  min-height: 5rem;
  resize: vertical;
}

.select {
  appearance: none;
  padding-right: 2rem;
  background-image: linear-gradient(45deg, transparent 50%, var(--text-muted) 50%),
    linear-gradient(135deg, var(--text-muted) 50%, transparent 50%);
  background-position: calc(100% - 1rem) 55%, calc(100% - 0.7rem) 55%;
  background-size: 0.3rem 0.3rem;
  background-repeat: no-repeat;
}

.field-invalid .input {
  border-color: var(--danger);
}

.field-hint {
  margin: 0;
  font-size: var(--text-xs);
  font-weight: 400;
  color: var(--text-muted);
}

.field-error {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--danger);
  font-weight: 600;
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}

.filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

/* --- filter bar (board/list saved filters) --------------------------------------------- */

.filter-bar {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}

.filter-bar .filters {
  margin-bottom: 0;
  gap: var(--space-2) var(--space-3);
}

.filter-bar .field-inline label {
  color: var(--text-muted);
}

.filter-bar .input {
  min-height: 2.125rem;
  padding: var(--space-2) 10px;
  font-size: var(--text-sm);
}

/* A select keeps room for its own arrow: the compact padding above is more specific than
 * `.select`, so shortening it here put the caret on top of the value. */
.filter-bar .select {
  padding-right: 2rem;
}

/* Saved views are pills: a filter is a place you go back to, not a form you refill. */
.saved-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
}

.saved-filter {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-pill);
  padding: 2px var(--space-2);
  background: var(--surface);
  font-size: var(--text-xs);
  font-weight: 600;
}

.saved-filter a {
  color: var(--text-secondary);
}

.saved-filter a:hover {
  color: var(--text);
  text-decoration: none;
}

.saved-filter-shared {
  font-size: var(--text-2xs);
  font-weight: 500;
  color: var(--text-muted);
}

/* --- cards ------------------------------------------------------------------------------ */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  padding: 22px;
  min-width: 0;
}

.card-narrow {
  max-width: var(--narrow-max);
  margin: 0 auto;
  border-radius: 20px;
  padding: 28px;
  box-shadow: 0 20px 50px rgba(23, 25, 28, 0.08);
}

/* The auth pages' alternate action ("New to Kernel? Create an account") is a link inside a
 * muted sentence; underline it so it is tellable from that text without relying on the
 * accent colour, which does not reach 3:1 against the muted run (WCAG 1.4.1). */
.card-narrow .muted a { text-decoration: underline; }

.card-form {
  max-width: var(--form-max);
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(16.25rem, 1fr));
  gap: 14px;
}

.card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

.card-title {
  font-weight: 700;
  font-size: var(--text-lg);
  letter-spacing: -0.012em;
  color: var(--text);
}

/* A card that is a link to the thing it describes lifts slightly under the pointer, so it
 * reads as one target rather than a panel with a link somewhere inside it. */
.card-link {
  display: block;
  color: inherit;
  transition:
    box-shadow var(--duration),
    transform var(--duration),
    border-color var(--duration);
}

.card-link:hover {
  border-color: var(--border-strong);
  box-shadow: var(--shadow);
  transform: translateY(-1px);
  text-decoration: none;
}

.project-key {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--accent);
}

.block {
  margin-bottom: var(--space-5);
}

.block h2 {
  font-size: var(--eyebrow-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--eyebrow-spacing);
  color: var(--text-muted);
}

/* The heading row of a card section: an eyebrow, its count, and any action it offers. */
.section-head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: 10px;
}

.section-head h2 {
  margin: 0;
}

/* --- badges ----------------------------------------------------------------------------- */

/* State chips are pills: small, bold, and coloured by what they say. Each pair is checked
 * for AA on its own soft ground, so a chip is legible without reading the label twice. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 1.375rem;
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  font-size: var(--text-2xs);
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  background: var(--surface-muted);
  color: var(--text-muted);
}

.badge-state-backlog { background: var(--state-backlog-soft); color: var(--state-backlog); }
.badge-state-ready { background: var(--state-ready-soft); color: var(--state-ready); }
.badge-state-running { background: var(--state-running-soft); color: var(--state-running); }
.badge-state-waiting_human { background: var(--state-waiting-soft); color: var(--state-waiting); }
.badge-state-blocked,
.badge-blocked { background: var(--state-blocked-soft); color: var(--state-blocked); }
.badge-state-review { background: var(--state-review-soft); color: var(--state-review); }
.badge-state-completed { background: var(--state-completed-soft); color: var(--state-completed); }
.badge-state-cancelled { background: var(--state-cancelled-soft); color: var(--state-cancelled); }

.badge-blocked {
  border: 1px solid var(--state-blocked);
}

/* Priority is an outline chip with a dot: it qualifies the work, it is not its state, and
 * two filled chips side by side would compete. */
.badge-priority-low,
.badge-priority-normal,
.badge-priority-high,
.badge-priority-urgent {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-secondary);
}

.badge-priority-low::before,
.badge-priority-normal::before,
.badge-priority-high::before,
.badge-priority-urgent::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
}

.badge-priority-low::before { background: var(--priority-low); }
.badge-priority-normal::before { background: var(--priority-normal); }
.badge-priority-high::before { background: var(--priority-high); }
.badge-priority-urgent::before { background: var(--priority-urgent); }

.badge-priority-urgent {
  border-color: var(--danger);
  color: var(--danger);
}

/* A count beside a heading or a tab: the number of things in the thing you are looking at. */
.count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.375rem;
  padding: 1px 7px;
  border-radius: var(--radius-pill);
  background: var(--surface-sunken);
  color: var(--text-secondary);
  font-size: var(--text-2xs);
  font-weight: 700;
  line-height: 1.4;
}

.label {
  display: inline-block;
  padding: 2px var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: var(--text-2xs);
  font-weight: 600;
  color: var(--text-secondary);
  background: var(--surface);
}

.labels {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  margin: 0;
}

/* A small uppercase tag for a kind of thing -- an artifact's type, an event's name. */
.tag {
  display: inline-block;
  padding: 2px 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text-secondary);
  font-size: 0.65625rem;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  white-space: nowrap;
}

.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.625rem;
  height: 1.625rem;
  border-radius: 50%;
  background: var(--text);
  color: var(--surface);
  font-size: var(--text-2xs);
  font-weight: 700;
  flex-shrink: 0;
}

.work-key {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--accent);
}

h1 .work-key {
  font-size: var(--text-lg);
  margin-right: var(--space-1);
}

/* --- tables ----------------------------------------------------------------------------- */

/* Tables stay tables -- a grid of rows is not a table to a screen reader, and half of what
 * this product shows is genuinely tabular. They are dressed as the card-rows around them:
 * a bordered container, an uppercase header, hairline separators, no vertical rules. */
.table-wrap {
  position: relative; /* contains visually-hidden headers (absolute) inside the scroll area */
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  margin-bottom: var(--space-4);
}

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}

/* Cells wrap. `nowrap` is opt-in, per cell, and the atoms that must never break carry it
 * themselves: `time`, `.badge`, `.btn`, `.capability`, `.work-key`. This is the inversion of
 * what this rule used to say, and the reason is that a default nobody can see beats the
 * declarations that fight it: `white-space: nowrap` inherited from here made `overflow-wrap`
 * and `word-break` on `.runtime-path` and `.runtime-problems` inert, so a 4096-character path
 * a daemon may legitimately report rendered on one line and the tokens page painted a
 * sixteen-scope badge list over five neighbouring columns. Both declarations were present the
 * whole time; the test that checked they were present could not see that they did nothing.
 * A cell that needs one line says so (`.cell-last-used`). */
.table th,
.table td {
  padding: 12px 16px;
  text-align: left;
  vertical-align: middle;
  border-bottom: 1px solid var(--rule);
}

.table th {
  padding-top: 10px;
  padding-bottom: 10px;
  font-size: var(--text-2xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--text-muted);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.table tbody tr:last-child td {
  border-bottom: 0;
}

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

.table .cell-title {
  min-width: 14rem;
  font-weight: 600;
}

.table .cell-actions {
  text-align: right;
}

.pager {
  display: flex;
  justify-content: flex-end;
}

/* --- board ------------------------------------------------------------------------------ */

/* Below 1280px the six columns keep a readable minimum and scroll sideways inside the
 * board; from 1280px up they share the width so the whole board is visible at once. */
.board-columns {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(13rem, 1fr);
  gap: 12px;
  overflow-x: auto;
  padding-bottom: var(--space-3);
  align-items: start;
}

@media (min-width: 1280px) {
  .board-columns {
    grid-auto-flow: row;
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
}

/* A column is a tray, not a card: recessed, so the work sitting in it reads as the
 * foreground. */
.column {
  background: var(--surface-sunken);
  border-radius: var(--radius-lg);
  padding: 10px;
  min-height: 12rem;
}

.column-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: var(--space-1) 6px 10px;
}

.column-title {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  font-size: var(--eyebrow-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--eyebrow-spacing);
  color: var(--text-muted);
}

/* The dot repeats the column's state in colour, so a scan down the board reads as states
 * rather than as six identical trays. */
.column-title::before {
  content: "";
  width: 8px;
  height: 8px;
  flex: none;
  border-radius: 50%;
  background: var(--state-backlog-dot);
}

.column[data-state="ready"] .column-title::before { background: var(--state-ready-dot); }
.column[data-state="running"] .column-title::before { background: var(--state-running-dot); }
.column[data-state="waiting_human"] .column-title::before { background: var(--state-waiting-dot); }
.column[data-state="review"] .column-title::before { background: var(--state-review-dot); }
.column[data-state="completed"] .column-title::before { background: var(--state-completed-dot); }

.column-head .count {
  margin-left: auto;
  background: var(--surface);
}

.column-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.column-empty {
  margin: 0;
  padding: 14px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
  color: var(--text-muted);
  font-size: var(--text-xs);
  text-align: center;
}

.work-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  transition:
    box-shadow var(--duration),
    transform var(--duration);
}

.work-card:hover {
  box-shadow: 0 6px 18px rgba(23, 25, 28, 0.1);
  transform: translateY(-1px);
}

.work-card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.work-card-head .work-key {
  white-space: nowrap; /* AUTH-12 never breaks across lines; the badges wrap instead */
}

.work-card-head .badge {
  margin-left: auto;
}

.work-card-head .badge-blocked {
  margin-left: 0;
}

.work-title {
  color: var(--text);
  font-weight: 600;
  font-size: var(--text-sm);
  line-height: 1.35;
  overflow-wrap: anywhere;
}

.work-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

/* --- work detail ------------------------------------------------------------------------ */

.work-header {
  align-items: flex-start;
}

.work-heading h1 {
  overflow-wrap: anywhere;
}

/* The chip row under a work item's title: what state it is in, how urgent it is, which
 * runtime holds it, whose it is. Read left to right, most durable first. */
.work-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-top: 10px;
  font-size: var(--text-xs);
  color: var(--text-muted);
}

.work-owner {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px 3px 3px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text-secondary);
  font-size: var(--text-2xs);
  font-weight: 600;
}

.action-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-left: auto;
}

.action-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.overview {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(14rem, 1fr);
  gap: var(--space-5);
}

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

@media (max-width: 900px) {
  .action-bar {
    margin-left: 0;
  }
}

.meta-list {
  margin: 0;
  display: grid;
  gap: var(--space-2);
  font-size: var(--text-sm);
}

.meta-list > div {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
}

.meta-list dt {
  color: var(--text-muted);
}

.meta-list dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
}

/* Each block of the overview is a card of its own: the goal, what constrains it, and what
 * "done" means are three separate questions, and running them together as headed prose is
 * how the third one stops being read. */
.overview .block {
  margin-bottom: var(--space-4);
  padding: 18px 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
}

.overview .block > h2 {
  margin-bottom: 10px;
}

.overview .block > :last-child {
  margin-bottom: 0;
}

/* Constraints are the things the agent may not do; acceptance criteria are what "done"
 * means. Both are lists people scan, so they are marked rather than bulleted. */
.constraints ul,
.acceptance-criteria ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-2);
  font-size: var(--text-md);
}

.constraints li,
.acceptance-criteria li {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}

.constraints li::before {
  content: "\25A0";
  flex: none;
  color: var(--warning);
  font-size: 0.5rem;
}

/* A criterion is a box waiting to be ticked; drawn empty, because Kernel records whether
 * the work is done, not which line of it was. */
.acceptance-criteria li::before {
  content: "";
  flex: none;
  width: 15px;
  height: 15px;
  border: 1.5px solid var(--border-strong);
  border-radius: var(--radius-sm);
  transform: translateY(2px);
}

.acceptance-criteria .is-met {
  color: var(--text-muted);
  text-decoration: line-through;
}

/* The work's goal is the one paragraph a person actually reads before deciding anything,
 * so it is set a size up from the surrounding metadata. */
.work-goal {
  margin: 0;
  font-size: var(--text-lg);
  line-height: 1.55;
}

/* --- work graph ------------------------------------------------------------------------- */

/* The graph is server-rendered SVG: static markup, no inline style (the CSP forbids it), so
 * every shape and line is coloured by class here. The drawing scrolls inside its own box and
 * never widens the page; under it a legend and a semantic list carry the same graph as text. */
.graph {
  display: grid;
  /* A single column that may shrink to zero, so a wide SVG or a long unbreakable label in
   * the text fallback scrolls/wraps inside the column instead of widening the page (390px). */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
}

.graph-truncation {
  margin: 0;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-left: 3px solid var(--warning);
  border-radius: var(--radius);
  background: var(--warning-soft);
  color: var(--text);
  font-size: var(--text-sm);
}

.graph-figure {
  margin: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-3);
}

.graph-viewport {
  overflow: auto;
  max-width: 100%;
  max-height: 70vh;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background:
    radial-gradient(circle, var(--surface-muted) 1px, transparent 1px) 0 0 / 22px 22px,
    var(--surface);
}

.graph-canvas {
  display: block;
}

/* Nodes: a coloured box per kind, its corner radius varied so the kinds are tellable without
 * relying on colour alone. The wrapping <a> carries no underline; the box is the hit target. */
.graph-node {
  cursor: pointer;
}

.graph-node .graph-node-shape {
  fill: var(--surface);
  stroke: var(--border-strong);
  stroke-width: 1.5;
}

.graph-node-kind {
  fill: var(--text-muted);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.graph-node-label {
  fill: var(--text);
  font-size: 13px;
  font-weight: 600;
}

.graph-node:hover .graph-node-shape,
.graph-node:focus .graph-node-shape {
  stroke-width: 2.5;
}

.graph-node:focus {
  outline: none;
}

.graph-node:focus-visible .graph-node-shape {
  stroke: var(--focus);
  stroke-width: 2.5;
}

/* Each node kind takes one state colour and one corner radius. */
.graph-node-work .graph-node-shape { stroke: var(--accent); rx: 4px; }
.graph-node-session .graph-node-shape { stroke: var(--state-running); rx: 24px; }
.graph-node-artifact .graph-node-shape { stroke: var(--state-completed); rx: 4px; }
.graph-node-decision .graph-node-shape { stroke: var(--state-review); rx: 14px; }
.graph-node-handoff .graph-node-shape { stroke: var(--state-waiting); rx: 4px; stroke-dasharray: 5 3; }

/* Edges: one colour and dash pattern per relationship, so the five are tellable apart. */
.graph-edge {
  stroke: var(--border-strong);
  stroke-width: 1.5;
  fill: none;
}

.graph-edge-dependency { stroke: var(--accent); stroke-width: 2; }
.graph-edge-parent { stroke: var(--text-muted); }
.graph-edge-session-chain { stroke: var(--state-running); stroke-dasharray: 6 4; }
.graph-edge-evidence { stroke: var(--state-completed); stroke-dasharray: 2 4; }
.graph-edge-handoff-lineage { stroke: var(--state-waiting); stroke-dasharray: 8 3 2 3; }

.graph-arrow path {
  fill: var(--border-strong);
}

/* Legend: node kinds and edge kinds, each swatch mirroring the drawing's style. */
.graph-legend-caption {
  display: grid;
  gap: var(--space-2);
}

.graph-legend {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  font-size: var(--text-sm);
  color: var(--text-muted);
}

.graph-legend-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.graph-legend-swatch {
  width: 1rem;
  height: 0.75rem;
  border-radius: var(--radius-sm);
  border: 1.5px solid var(--border-strong);
  background: var(--surface);
}

.graph-node-work .graph-legend-swatch { border-color: var(--accent); border-radius: 2px; }
.graph-node-session .graph-legend-swatch { border-color: var(--state-running); border-radius: 999px; }
.graph-node-artifact .graph-legend-swatch { border-color: var(--state-completed); border-radius: 2px; }
.graph-node-decision .graph-legend-swatch { border-color: var(--state-review); border-radius: 7px; }
.graph-node-handoff .graph-legend-swatch { border-color: var(--state-waiting); border-style: dashed; }

.graph-legend-line {
  width: 1.5rem;
  height: 0;
  border-top-width: 2px;
  border-top-style: solid;
  border-color: var(--border-strong);
}

.graph-edge-dependency .graph-legend-line { border-color: var(--accent); }
.graph-edge-parent .graph-legend-line { border-color: var(--text-muted); }
.graph-edge-session-chain .graph-legend-line { border-top-style: dashed; border-color: var(--state-running); }
.graph-edge-evidence .graph-legend-line { border-top-style: dotted; border-color: var(--state-completed); }
.graph-edge-handoff-lineage .graph-legend-line { border-top-style: dashed; border-color: var(--state-waiting); }

/* The text alternative: the same graph as a nested list, for a screen reader or a client
 * without SVG. Always in the DOM, never hidden. */
.graph-textalt {
  border-top: 1px solid var(--border);
  padding-top: var(--space-3);
}

.graph-textalt-heading {
  font-size: var(--text-sm);
  color: var(--text-muted);
  margin: 0 0 var(--space-2);
}

.graph-node-list {
  margin: 0;
  padding-left: var(--space-5);
  display: grid;
  gap: var(--space-2);
  font-size: var(--text-sm);
  /* A decision statement or work title can be one long token with no spaces; let it wrap so
   * it cannot stretch the grid column past the viewport on a narrow screen. */
  overflow-wrap: anywhere;
}

.graph-node-list-kind {
  display: inline-block;
  min-width: 4.5rem;
  color: var(--text-muted);
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.graph-relation-list {
  margin: var(--space-1) 0 0;
  padding-left: var(--space-4);
  color: var(--text-muted);
  overflow-wrap: anywhere;
}

/* The fallback's links sit inside running text, so they carry an underline to be tellable
 * from it without relying on colour (WCAG 1.4.1). */
.graph-node-list-link,
.graph-relation-list a {
  text-decoration: underline;
}

/* --- activity timeline ------------------------------------------------------------------ */

.timeline {
  display: grid;
  gap: var(--space-5);
  margin-bottom: var(--space-5);
}

.timeline-day {
  display: grid;
  gap: var(--space-2);
}

.timeline-date {
  font-size: var(--eyebrow-size);
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: var(--eyebrow-spacing);
  margin: 0;
}

.timeline-events {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  overflow: hidden;
}

.timeline-event {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: baseline;
  gap: var(--space-3);
  padding: 12px 16px;
  border-top: 1px solid var(--rule);
}

.timeline-events > .timeline-event:first-child {
  border-top: 0;
}

.timeline-time {
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
}

.timeline-body {
  min-width: 0;
}

.timeline-summary {
  margin: 0;
  font-size: var(--text-sm);
  overflow-wrap: anywhere;
}

.timeline-links {
  margin: var(--space-1) 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  font-size: var(--text-xs);
}

.timeline-type {
  color: var(--text-disabled);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  white-space: nowrap;
}

.load-more {
  justify-self: start;
}

@media (max-width: 40rem) {
  .timeline-event {
    grid-template-columns: auto 1fr;
  }

  .timeline-type {
    grid-column: 2;
  }
}

/* --- states ----------------------------------------------------------------------------- */

/* The empty state is a dashed panel, not a bordered card: it says "nothing is here yet"
 * rather than "here is a thing that happens to be blank". */
.empty-state {
  padding: 32px var(--space-4);
  text-align: center;
  border: 1px dashed var(--border-input);
  border-radius: var(--radius-xl);
  background: var(--surface);
  color: var(--text-muted);
  margin-bottom: var(--space-4);
}

.empty-state .empty-title {
  margin-bottom: var(--space-2);
  font-size: 1.0625rem;
  color: var(--text);
}

.empty-state p {
  max-width: 34rem;
  margin: 0 auto var(--space-4);
  color: var(--text-muted);
  font-size: var(--text-md);
}

.empty-state p:last-child {
  margin-bottom: 0;
}

/* The first-use state of a whole page gets a mark and more room: it is the only thing on
 * the screen, so it may as well say what to do next properly. */
.empty-state-hero {
  max-width: 34rem;
  margin: 20px auto var(--space-4);
  padding: 48px var(--space-5);
  border-radius: 20px;
}

.empty-mark {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  margin: 0 auto var(--space-3);
  border-radius: var(--radius-lg);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: var(--text-xl);
  font-weight: 700;
}

.state-error {
  border-color: var(--danger);
  border-style: solid;
}

.state-denied {
  border-style: solid;
}

/* Alerts are filled panels tinted by their kind, with a rule down the leading edge so the
 * kind survives being read in greyscale. */
.alert {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  padding: 14px 18px;
  margin-bottom: var(--space-4);
  border: 1px solid var(--border);
  border-left-width: 4px;
  border-radius: var(--radius-lg);
  background: var(--surface);
  font-size: var(--text-md);
}

.alert-success {
  border-color: var(--success-soft);
  border-left-color: var(--success);
  background: var(--success-soft);
  color: var(--success-strong);
}

.alert-error {
  border-color: var(--danger-soft);
  border-left-color: var(--danger);
  background: var(--danger-soft);
  color: var(--danger-strong);
}

.alert-warning {
  border-color: var(--warning-border);
  border-left-color: var(--warning);
  background: var(--warning-soft);
  color: var(--warning-text);
}

.alert-info {
  border-color: var(--accent-soft-strong);
  border-left-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent-strong);
}

.alert a {
  color: inherit;
  text-decoration: underline;
}

.flash-link {
  font-family: var(--font-mono);
  overflow-wrap: anywhere;
}

.error-page .request-id {
  font-size: var(--text-xs);
  font-family: var(--font-mono);
  color: var(--text-muted);
}

/* --- dialogs ---------------------------------------------------------------------------- */

.dialog {
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 0;
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-lg);
  max-width: min(30rem, calc(100vw - 2rem));
}

.dialog::backdrop {
  background: rgba(23, 25, 28, 0.45);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

.dialog-body {
  padding: 26px;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.dialog-body h2 {
  margin-bottom: 0;
  font-size: var(--text-xl);
  letter-spacing: -0.02em;
}

.dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

.dialog-actions .btn {
  min-height: 2.375rem;
  padding: 0 var(--space-4);
}

.shortcut-list {
  margin: 0;
  display: grid;
  gap: 6px;
}

.shortcut-list > div {
  display: flex;
  gap: var(--space-3);
  align-items: baseline;
}

.shortcut-list dt {
  min-width: 5rem;
}

.shortcut-list dd {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* --- HTMX indicator (the built-in styles are disabled by the CSP) ---------------------- */

.htmx-indicator {
  opacity: 0;
  transition: opacity var(--duration) ease-in;
  font-size: var(--text-sm);
  color: var(--text-muted);
}

.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator {
  opacity: 1;
}

/* --- API tokens ------------------------------------------------------------------------- */

.mono {
  font-family: var(--font-mono);
}

.table.tokens .cell-scopes {
  max-width: 18rem;
}

.badge.scope {
  font-family: var(--font-mono);
  font-weight: 500;
  margin: 0 var(--space-1) var(--space-1) 0;
}

.secret .secret-value {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

.secret .secret-value .input {
  font-family: var(--font-mono);
}

.fieldset {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.fieldset legend {
  padding: 0 var(--space-1);
  font-size: var(--text-sm);
  font-weight: 600;
}

.fieldset .field-inline .input,
.fieldset input[type="checkbox"],
.fieldset input[type="radio"] {
  width: auto;
  min-height: 0;
  flex: none;
}

.fieldset label {
  font-weight: 400;
}

.field-hint.warning {
  color: var(--danger);
  font-weight: 500;
}

.projects {
  max-height: 14rem;
  overflow-y: auto;
}

.scopes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--space-3);
  max-height: 22rem;
  overflow-y: auto;
}

.scope-group-title {
  margin: 0 0 var(--space-1);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.dialog-wide {
  max-width: min(44rem, calc(100vw - 2rem));
}

/* --- runtimes, machines and sessions ---------------------------------------------------- */

.page-intro {
  max-width: 60rem;
  margin: 0 0 var(--space-4);
  font-size: var(--text-sm);
}

.inline-form {
  display: inline;
}

.built-in {
  display: block;
  font-size: var(--text-xs);
  margin-top: var(--space-1);
  max-width: 16rem;
}

.runtime-key {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

/* A doctor report may carry a 4096-character path and twenty problems of 500 characters,
 * all of them legitimate values a person meets with no attacker involved. They wrap inside
 * their cell and scroll there rather than pushing the table sideways. */
/* Bounded in both directions, like the problems list below it and for the same reason: a
 * 4096-character path is a value a daemon may legitimately report, and once it is allowed to
 * wrap it becomes eighty lines that push every other runtime below the fold. Width alone is
 * half a fix — it only decides which way the row is unusable. */
.runtime-path {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  overflow-wrap: anywhere;
  word-break: break-word;
  max-width: 22rem;
  max-height: 4.5rem;
  overflow-y: auto;
}

/* The capability matrix. ``narrowed`` is deliberately not a warning colour: a row that
 * claims less than its adapter implements is a setting this organization chose, and
 * painting it amber would read as a fault the reader has to fix. */
.capability-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  margin: 0;
  padding: 0;
  list-style: none;
  max-width: 22rem;
}

.capability {
  font-size: var(--text-2xs);
  font-weight: 600;
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  white-space: nowrap;
}

.capability-on {
  background: var(--success-soft);
  color: var(--success);
}

.capability-narrowed {
  background: var(--info-soft);
  color: var(--text-muted);
  border-style: dashed;
  border-color: var(--border-strong);
}

.capability-off {
  color: var(--text-faint);
  border-color: var(--border);
}

.machine-reports {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.runtime-problems {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  overflow-wrap: anywhere;
  word-break: break-word;
  max-height: 12rem;
  overflow-y: auto;
}

.machine-report {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-sm);
}

.machine-name {
  font-weight: 500;
}

.runtime-problem {
  flex-basis: 100%;
  color: var(--danger);
  font-size: var(--text-xs);
}

/* What one machine's doctor() found its adapter can do. Its own line inside the report, so
 * a ten-flag list does not push the machine's name and its version apart, and muted like the
 * rest of Kernel's own words in this cell — every label here comes from a field name of
 * `RuntimeCapabilities`, never from anything a runtime said. */
.reported-capabilities {
  flex-basis: 100%;
  font-size: var(--text-xs);
  color: var(--text-muted);
}

/* "reported:" is Kernel speaking; what follows is the daemon's, and the quotation marks
 * say so. Never style a runtime-supplied string like our own status text. */
.reported-by {
  color: var(--text-muted);
  font-style: italic;
}

/* A column that holds a sentence needs a measure, and these two are the same defect met at
 * two depths — so they are declared together, because a reader who fixes one should see the
 * other.
 *
 * `auto` table layout squeezes a cell to its longest word when the row is wide. That is what
 * made the built-in explanation on `.cell-enabled` read nine characters at a time on a phone;
 * `.table .cell-title` has carried a measure for the same reason since M2.
 *
 * `.cell-machines` is that one step further, and worse. `overflow-wrap: anywhere` on
 * `.runtime-path` and `.runtime-problems` above makes its longest word **one character**, so
 * the column carrying the most prose on this page has no floor at all — the wrapping rule that
 * keeps a 4096-character path inside its cell is the same rule that lets the cell collapse.
 * Measured at 390px with three machines on one row: 96px of a 970px table, a runtime's own
 * problem sentence wrapping about two words to a line, while Runtime took 224px and Enabled
 * 176px. Neutralising `anywhere` gives the column 376px, which is what names the mechanism;
 * `min-width` gives it 224px and the problem line 200px, and the table still scrolls inside
 * `.table-wrap` with no page-level overflow.
 *
 * A `max-width` alone was never the fix: it decides the other end. `tests/e2e/
 * test_registry_overflow.py` asserts the width the browser **laid out**, not that these
 * declarations are present — the version that read the stylesheet certified this page as
 * correct for a whole milestone while it was broken (UI-M4-2). */
.cell-machines {
  min-width: 14rem;
  max-width: 26rem;
}

.cell-enabled {
  min-width: 11rem;
}

/* --- test configuration (on-demand doctor) -------------------------------------------- */
/* The per-row "Test configuration" control and the run it polls. The result reuses the same
   quotation and capability styling the machine reports column uses, so a runtime's own words
   never read as Kernel's. */
.runtime-test {
  margin-top: var(--space-2);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.runtime-test-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.test-machine-select {
  max-width: 12rem;
}

.runtime-test-result:empty {
  display: none;
}

.test-run {
  font-size: var(--text-sm);
}

.test-run-pending {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-muted);
}

.spinner {
  width: 0.85em;
  height: 0.85em;
  border: 2px solid var(--border);
  border-top-color: var(--accent-strong);
  border-radius: 50%;
  display: inline-block;
  animation: spin 0.7s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation: none;
  }
}

.test-run-result,
.test-run-failed {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-1) var(--space-2);
}

.test-run-heading {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-1) var(--space-2);
  margin: 0;
}

.test-run-result[data-result="problems"] {
  color: var(--text);
}

.cell-last-used {
  white-space: nowrap;
}

.badge.origin {
  font-size: var(--text-xs);
  background: var(--surface-muted);
  color: var(--text-muted);
}

.badge.origin-organization {
  background: var(--accent-soft);
  color: var(--accent-strong);
}

.health-healthy { background: var(--success-soft); color: var(--success); }
.health-problems { background: var(--danger-soft); color: var(--danger); }
.health-offline { background: var(--state-blocked-soft); color: var(--state-blocked); }
.health-unreported { background: var(--surface-muted); color: var(--text-muted); }

.badge-session-pending { background: var(--state-backlog-soft); color: var(--state-backlog); }
.badge-session-starting { background: var(--state-ready-soft); color: var(--state-ready); }
.badge-session-running { background: var(--state-running-soft); color: var(--state-running); }
.badge-session-completed { background: var(--state-completed-soft); color: var(--state-completed); }
.badge-session-failed { background: var(--danger-soft); color: var(--danger); }
.badge-session-exhausted { background: var(--warning-soft); color: var(--warning); }
.badge-session-cancelled { background: var(--state-cancelled-soft); color: var(--state-cancelled); }
/* Stale sits beside the status badge, never in its place: the session is still running as
   far as Kernel knows, and the badge says only that nobody has heard from it lately. */
.badge-session-stale { background: var(--state-blocked-soft); color: var(--state-blocked); }

.badge.runtime-key {
  font-family: var(--font-mono);
  font-weight: 500;
  margin: 0 var(--space-1) var(--space-1) 0;
}

.panel-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

/* --- session detail --------------------------------------------------------------------- */

.session-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: var(--space-5);
  align-items: start;
}

@media (max-width: 60rem) {
  .session-layout {
    grid-template-columns: minmax(0, 1fr);
  }
}

.session-events {
  margin-top: var(--space-4);
}

.session-timeline .event-detail {
  margin-top: var(--space-1);
}

.session-timeline .event-detail > summary {
  font-size: var(--text-xs);
  color: var(--text-muted);
  cursor: pointer;
}

/* The runtime's own output, dressed as a log rather than as prose: a dark panel is the
 * design's mark for "this is verbatim, and Kernel did not write it". */
.event-payload {
  margin: var(--space-2) 0 0;
  padding: 14px 16px;
  background: var(--ink);
  color: var(--ink-text);
  border-radius: 12px;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: 1.7;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 22rem;
  overflow: auto;
}

.timeline-more {
  list-style: none;
  padding: var(--space-3) 0 0;
}

/* --- motion ----------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}

/* --- milestone 6: work records, the artifact viewer and the Needs You inbox -------------
 *
 * Written after looking at the pages in a browser rather than before: the inbox row put the
 * work key hard against the title with nothing between them, and the counts had no shape at
 * all, both of which read as fine in the markup and wrong on the screen.
 */

/* The one count in the navigation. Amber rather than the accent: it is the number of things
 * waiting on a person, which is a different kind of fact from "you are here". */
.nav-badge {
  display: inline-grid;
  place-items: center;
  min-width: 1.375rem;
  height: 1.25rem;
  margin-left: auto;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  background: var(--warning);
  color: #ffffff;
  font-size: var(--text-2xs);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.inbox-section {
  margin-bottom: var(--space-5);
}

.inbox-section h2 {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--eyebrow-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--eyebrow-spacing);
  color: var(--text-muted);
  margin-bottom: 10px;
}

/* An inbox item is a card, not a table row: each one is a decision, and a decision needs
 * room for what it is, why it is being asked, and the two things you can do about it. */
.inbox-rows {
  display: grid;
  gap: var(--space-3);
}

.inbox-row {
  display: grid;
  gap: 14px;
  padding: 18px 20px;
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  background: var(--surface);
  transition:
    border-color var(--duration),
    box-shadow var(--duration);
}

/* The focused row is ringed rather than merely bordered: j/k moves through these without a
 * pointer, so "which one am I on" has to survive a glance. */
.inbox-row:focus-within {
  border-color: var(--accent-bright);
  box-shadow: 0 0 0 3px var(--accent-soft-strong);
}

.inbox-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.inbox-kind {
  font-size: var(--text-2xs);
  font-weight: 700;
  padding: 3px 9px;
  border-radius: var(--radius-pill);
}

.inbox-kind-approval { background: var(--warning-soft); color: var(--warning); }
.inbox-kind-blocker { background: var(--danger-soft); color: var(--danger); }
.inbox-kind-session { background: var(--state-review-soft); color: var(--state-review); }
.inbox-kind-handoff { background: var(--state-running-soft); color: var(--state-running); }

.inbox-link {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  font-weight: 700;
  font-size: var(--text-lg);
  color: var(--text);
  text-decoration: none;
}

.inbox-link:hover {
  color: var(--text);
}

.inbox-link:hover .inbox-title {
  text-decoration: underline;
}

.inbox-title {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* The key is a separate object from the title, not a suffix of it. Run together they read
 * as one sentence ending in an identifier, which is how "Deploy 2.4.0 to production AUTH-1"
 * happened. */
.inbox-work {
  flex: none;
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-weight: 400;
}

.inbox-detail {
  margin: 0;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  overflow-wrap: anywhere;
}

.inbox-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.inbox-empty {
  margin: 0 0 var(--space-4);
  font-size: var(--text-sm);
}

.inbox-row[data-severity="critical"] { border-left: 3px solid var(--danger); }
.inbox-row[data-severity="high"] { border-left: 3px solid var(--warning); }

/* --- the work-record tabs ---------------------------------------------------------------- */

.decisions, .blockers, .approvals { display: grid; gap: var(--space-3); list-style: none; padding: 0; }

.decision, .blocker, .approval {
  padding: 16px 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
}

/* A decision is a quotation from the record: ruled on the leading edge, the way the design
 * marks anything that was decided rather than observed. */
.decision {
  border-left: 3px solid var(--accent-bright);
}

.decision-statement, .blocker-title, .approval-question {
  margin: 0 0 var(--space-2);
  font-weight: 700;
  font-size: var(--text-lg);
}

.decision-superseded .decision-statement { text-decoration: line-through; color: var(--text-muted); }
.decision-superseded { border-left-color: var(--border-strong); }
.decision-supersession, .decision-meta, .blocker-meta, .approval-meta, .approval-reason {
  margin: var(--space-2) 0 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

.evidence { margin: var(--space-2) 0 0; padding-left: var(--space-5); font-size: var(--text-sm); }

.blocker-resolution {
  margin: var(--space-2) 0 0;
  padding-left: var(--space-3);
  border-left: 2px solid var(--success);
  color: var(--text-muted);
  font-size: var(--text-sm);
}

.blocker-resolved .blocker-title { color: var(--text-muted); }
.approval-not-yours { margin: var(--space-2) 0 0; font-size: var(--text-sm); }
.panel-heading {
  margin: var(--space-5) 0 var(--space-2);
  font-size: var(--eyebrow-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--eyebrow-spacing);
  color: var(--text-muted);
}

.panel-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

.badge-severity-critical { background: var(--danger-soft); color: var(--danger); }
.badge-severity-high { background: var(--warning-soft); color: var(--warning); }
.badge-severity-medium { background: var(--state-backlog-soft); color: var(--state-backlog); }
.badge-severity-low { background: var(--state-backlog-soft); color: var(--state-backlog); }
.badge-approval-pending { background: var(--state-waiting-soft); color: var(--state-waiting); }
.badge-approval-approved { background: var(--success-soft); color: var(--success); }
.badge-approval-rejected { background: var(--danger-soft); color: var(--danger); }
.badge-latest { background: var(--accent-soft); color: var(--accent); margin-left: var(--space-2); }

/* --- handoffs ----------------------------------------------------------------------------- */

.badge-handoff-requested { background: var(--state-backlog-soft); color: var(--state-backlog); }
.badge-handoff-compiled { background: var(--state-review-soft); color: var(--state-review); }
.badge-handoff-accepted { background: var(--state-running-soft); color: var(--state-running); }
.badge-handoff-rejected { background: var(--danger-soft); color: var(--danger); }
.badge-handoff-completed { background: var(--state-completed-soft); color: var(--state-completed); }
.badge-handoff-cancelled { background: var(--state-cancelled-soft); color: var(--state-cancelled); }

.handoff-reject-reason { margin-left: var(--space-2); font-size: var(--text-sm); }
.cell-lineage { white-space: normal; }
.lineage-arrow { margin: 0 var(--space-1); color: var(--text-muted); }

/* The rendered package: a document, not a form field. Not `.prose`, whose pre-wrap exists
 * for plain-text goals and would turn the newlines between rendered blocks into blank lines. */
.handoff-package {
  overflow-wrap: anywhere;
  font-size: var(--text-sm);
}
/* The document's own headings arrive demoted one level (its `# title` is an h2 here). */
.handoff-package h2 { font-size: var(--text-lg); margin: 0 0 var(--space-3); }
.handoff-package h3 { font-size: var(--text-md); margin: var(--space-4) 0 var(--space-2); }
.handoff-package ul, .handoff-package ol { padding-left: var(--space-5); }
.handoff-package code { overflow-wrap: anywhere; }

.handoff-json { margin-top: var(--space-4); font-size: var(--text-sm); }
.handoff-json summary { cursor: pointer; color: var(--text-muted); }
.handoff-json-body {
  margin: var(--space-2) 0 0;
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  overflow-x: auto;
  font-size: var(--text-xs);
}
/* The rejection is part of the record, not a flash: it is styled as a callout of its own so
 * it is never mistaken for -- or matched as -- the message a redirect left behind. */
.handoff-rejection {
  margin-top: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border);
  border-left: 4px solid var(--danger);
  border-radius: var(--radius);
  background: var(--danger-soft);
  font-size: var(--text-sm);
}
.handoff-rejection .handoff-reject-note { margin-left: var(--space-1); }

/* --- artifacts ---------------------------------------------------------------------------- */

.digest { font-family: var(--font-mono); font-size: var(--text-xs); }
.digest-full { overflow-wrap: anywhere; }

/* The artifact's facts: a two-column list over bare dt/dd pairs. It carried a
 * `detail-grid` class that has never existed in this stylesheet, so the page fell back to
 * the browser's indented <dl> while every other detail list in the product was a grid. */
.artifact-facts {
  display: grid;
  grid-template-columns: 8rem minmax(0, 1fr);
  gap: var(--space-2) var(--space-3);
  margin-bottom: var(--space-5);
  font-size: var(--text-sm);
}

.artifact-facts dt {
  font-weight: 600;
  color: var(--text-muted);
}

.artifact-facts dd {
  margin: 0;
  min-width: 0;
}

@media (max-width: 40rem) {
  .artifact-facts {
    grid-template-columns: minmax(0, 1fr);
    gap: 2px var(--space-3);
  }

  .artifact-facts dd {
    margin-bottom: var(--space-2);
  }
}

.artifact-preview {
  margin-top: var(--space-5);
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

.artifact-preview-text { overflow-x: auto; font-size: var(--text-sm); }
.artifact-preview-image { display: block; max-width: 100%; height: auto; }
.artifact-truncated { margin-top: var(--space-2); font-size: var(--text-sm); }

/* --- settings & integrations ------------------------------------------------------------- */

.settings-index { display: flex; flex-direction: column; gap: var(--space-5); }

.card-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
  gap: var(--space-4);
}

.card-list .card { display: flex; flex-direction: column; gap: var(--space-1); }

.card-list .card:hover {
  border-color: var(--border-strong);
  box-shadow: var(--shadow);
}

.card-link { font-weight: 700; font-size: var(--text-lg); }

.later-list { display: flex; flex-direction: column; gap: var(--space-2); margin-top: var(--space-3); }

.later-item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

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

.later-badge { background: var(--surface-muted); color: var(--text-muted); }

.detail-list { display: grid; gap: var(--space-2); margin: 0; }

.detail-list > div { display: grid; grid-template-columns: 8rem 1fr; gap: var(--space-2); }

.detail-list dt { font-weight: 600; color: var(--text-muted); font-size: var(--text-sm); }

.detail-list dd { margin: 0; }

.field-label { font-size: var(--text-sm); font-weight: 600; }

.field-static { margin: 0; }
/* --- the Home dashboard (M10) ------------------------------------------------------------ */

/* Each section is a card; they tile into as many columns as the viewport allows and fall to
 * one on a narrow screen, so Home is dense on a desktop and still calm on a phone. */
.dashboard {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: repeat(auto-fit, minmax(21.25rem, 1fr));
  align-items: start;
}

.dashboard-section {
  margin: 0;
  padding: 22px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
}

.dashboard-lead {
  margin: 0 0 var(--space-3);
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* Underlined because it sits inside running text: the accent link colour does not reach 3:1
 * against the muted lead it lives in, so colour alone would not tell it apart (WCAG 1.4.1,
 * axe link-in-text-block). The same reason underlines the auth pages' in-prose link below. */
.dashboard-more {
  margin-left: var(--space-2);
  font-size: var(--text-sm);
  white-space: nowrap;
  text-decoration: underline;
}

/* minmax(0, 1fr): the default 1fr track floors at min-content, so a row with a long unbreakable
 * title would widen the track past the viewport. minmax(0,…) lets the track — and the row's
 * ellipsis — shrink instead. */
.dashboard-rows {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
}

.dashboard-rows + .dashboard-rows {
  margin-top: var(--space-3);
}

.dashboard-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
  padding: 10px 12px;
  border-radius: var(--radius);
  background: var(--bg);
  transition: background var(--duration);
}

.dashboard-row:hover {
  background: var(--surface-sunken);
}

.dashboard-row:focus-within {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}

.dashboard-row[data-kind="blocked"] {
  border-left: 3px solid var(--state-blocked);
}

.dashboard-row[data-health="problems"] {
  border-left: 3px solid var(--danger);
}

.dashboard-link {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex: 1 1 auto;
  min-width: 0;
  font-weight: 600;
  font-size: var(--text-sm);
  text-decoration: none;
  color: var(--text);
}

.dashboard-link:hover {
  color: var(--text);
}

.dashboard-link:hover .dashboard-title {
  text-decoration: underline;
}

/* min-width:0 is what lets a nowrap flex child actually truncate instead of forcing the row
 * (and the page) wider than the viewport — the flexbox min-content gotcha. */
.dashboard-title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dashboard-row > .muted {
  flex: none;
  white-space: nowrap;
  font-size: var(--text-xs);
}

/* The work key is its own object, never a suffix run into the title (see .inbox-work). */
.dashboard-meta {
  flex: none;
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
}

.badge-online { background: var(--state-running-soft); color: var(--state-running); }
.badge-offline { background: var(--surface-sunken); color: var(--text-muted); }

.badge-health-healthy { background: var(--success-soft); color: var(--success); }
.badge-health-problems { background: var(--danger-soft); color: var(--danger); }
.badge-health-offline { background: var(--surface-sunken); color: var(--text-muted); }
.badge-health-unreported { background: var(--surface-sunken); color: var(--text-muted); }

.badge-handoff-requested { background: var(--state-ready-soft); color: var(--state-ready); }
.badge-handoff-compiled { background: var(--state-review-soft); color: var(--state-review); }
.badge-handoff-accepted { background: var(--state-running-soft); color: var(--state-running); }
.badge-handoff-completed { background: var(--state-completed-soft); color: var(--state-completed); }
.badge-handoff-rejected { background: var(--danger-soft); color: var(--danger); }
.badge-handoff-cancelled { background: var(--state-cancelled-soft); color: var(--state-cancelled); }

/* Analytics ----------------------------------------------------------------------------------
 *
 * Three sections, each a static horizontal-bar <svg> paired with the table that carries the
 * same numbers. The SVG scales to its column (`width: 100%` up to its natural 560px) so it
 * never widens the page; the wide runtime table scrolls inside its own `.table-wrap`, the same
 * containment the registry uses. Every colour is a theme variable, so the charts follow light
 * and dark without a second set of rules. Bars carry meaning by label and table row, never by
 * colour alone: the outcome colours are Kernel's reserved status colours, each beside its name.
 */
.analytics-range {
  margin: 0 0 var(--space-5);
  font-size: var(--text-sm);
  max-width: 60ch;
}

.analytics-section {
  margin-bottom: var(--space-8);
}

.analytics-section > h2 {
  font-size: var(--text-lg);
  margin: 0 0 var(--space-2);
}

.section-intro {
  margin: 0 0 var(--space-4);
  font-size: var(--text-sm);
  max-width: 70ch;
}

/* The KPI row: a label and a number, the number set in the mono face because it is a
 * measurement, not prose. */
.stat-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9.375rem, 1fr));
  gap: var(--space-3);
  margin: 0 0 var(--space-5);
}

.stat-tile {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  padding: 16px 18px;
}

.stat-tile dt {
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--text-muted);
  margin-bottom: 6px;
}

.stat-tile dd {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--text-2xl);
  font-weight: 500;
  color: var(--text);
  line-height: 1.1;
}

.stat-note {
  display: block;
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: 400;
  color: var(--text-muted);
  margin-top: var(--space-1);
}

/* Chart + its table, stacked so both keep the full column width and neither forces the page
 * sideways at a phone width. */
.analytics-pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
}

.chart-figure {
  margin: 0;
}

.chart-caption {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--space-2);
}

.chart-viewport {
  max-width: 100%;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  padding: var(--space-3) var(--space-4);
}

.analytics-chart {
  display: block;
  width: 100%;
  height: auto;
  max-width: 560px;
}

.chart-track {
  fill: var(--surface-muted);
  stroke: none;
}

.chart-value {
  fill: var(--accent);
}

.chart-bar-success .chart-value { fill: var(--success); }
.chart-bar-partial .chart-value { fill: var(--warning); }
.chart-bar-failure .chart-value { fill: var(--danger); }
.chart-bar-cancelled .chart-value { fill: var(--text-faint); }

.chart-bar-label {
  fill: var(--text);
  font-size: 12.5px;
  font-weight: 500;
}

.chart-bar-value {
  fill: var(--text-muted);
  font-size: 12.5px;
  font-weight: 600;
}

.chart-bar-withheld .chart-bar-value {
  font-style: italic;
}

/* The outcome swatch beside a table row's name — decorative, so it is aria-hidden and the
 * name carries the meaning. */
.outcome-swatch {
  display: inline-block;
  width: 0.7em;
  height: 0.7em;
  border-radius: 3px;
  margin-right: var(--space-2);
  vertical-align: baseline;
  background: var(--text-faint);
}

.outcome-success { background: var(--success); }
.outcome-partial { background: var(--warning); }
.outcome-failure { background: var(--danger); }
.outcome-cancelled { background: var(--text-faint); }

/* Numeric columns read right-aligned with tabular figures so the digits line up. */
.analytics-table td.num,
.analytics-table th.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.analytics-table .cell-withheld {
  color: var(--text-muted);
}

.analytics-table .cell-cost {
  white-space: normal;
}

.cost-note {
  display: block;
  font-size: var(--text-xs);
  font-weight: 400;
  white-space: normal;
}

/* The runtime registry's outcome column: real metrics where M10 left the column unfilled.
 * A prominent success rate over two muted lines of the counts it rests on. */
.cell-outcomes .outcome-rate {
  display: block;
  font-family: var(--font-mono);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.cell-outcomes .outcome-withheld {
  font-family: var(--font-sans);
  color: var(--text-muted);
}

.cell-outcomes .outcome-sub,
.cell-outcomes .outcome-counts {
  display: block;
  font-size: var(--text-xs);
  color: var(--text-muted);
}

/* The scheduler's advisory pick in the start-session dialog (M13). */
.recommendation {
  border: 1px solid var(--accent-soft-strong);
  background: var(--accent-soft);
  border-radius: var(--radius-lg);
  padding: var(--space-3) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.recommendation-title {
  margin: 0;
  color: var(--accent-strong);
  font-size: var(--text-md);
}

.recommendation-why {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.recommendation-note {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--text-muted);
}

/* --- public marketing site (M18) --------------------------------------------------------
 * Calm and factual: system typography, one restrained accent, generous vertical rhythm and
 * monospace eyebrows as the one "system of record" signal. Every colour is a token, so the
 * dark palette above recolours it and the whole site holds WCAG AA the way the app does.
 * All widths are relative and content scrolls inside its own box, so nothing pushes the page
 * sideways at 390px. */

.marketing {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.marketing-header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-5);
  padding: 22px var(--space-5);
  background: var(--surface);
}

.marketing-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  font-size: var(--text-sm);
}

.marketing-nav a {
  color: var(--text-muted);
  font-weight: 500;
}

.marketing-nav a:hover,
.marketing-nav a[aria-current="page"] {
  color: var(--text);
}

.marketing-header-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-left: auto;
}

.marketing-main {
  flex: 1;
  width: 100%;
  max-width: 72.5rem;
  margin: 0 auto;
  padding: var(--space-6) var(--space-4) var(--space-8);
}

/* The marketing site sits on white, not the application grey: it is a page about the
 * product, not a surface inside it. */
.marketing {
  background: var(--surface);
}

/* Eyebrows across the marketing site are set in the accent: on a page with no state to
 * report, the teal is free to be the thing that orients you. */
.marketing .eyebrow {
  color: var(--accent);
  letter-spacing: 1.2px;
  font-size: var(--eyebrow-size);
}

/* Hero -------------------------------------------------------------------------------- */

.hero {
  max-width: 52rem;
  margin: 0 auto;
  padding: var(--space-8) 0 var(--space-6);
  text-align: center;
}

.hero-title {
  margin: var(--space-2) 0 var(--space-4);
  font-size: clamp(2.25rem, 5.4vw, 3.25rem);
  line-height: 1.05;
  letter-spacing: -0.028em;
}

.hero-lead {
  margin: 0 auto var(--space-5);
  max-width: 44rem;
  font-size: var(--text-lg);
  line-height: 1.55;
  color: var(--text-muted);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  justify-content: center;
}

.hero-note {
  margin: var(--space-5) 0 0;
  font-size: var(--text-sm);
}

.btn-lg {
  min-height: 2.75rem;
  padding: 0 var(--space-5);
  font-size: var(--text-md);
}

/* Landing hero ------------------------------------------------------------------------ */

/* The split hero. It falls to one column below 900px, where the shot goes first only if it
 * still earns its space -- it does not, so it simply stacks under the claim. */
.hero-split {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: 48px;
  align-items: center;
  max-width: none;
  text-align: left;
}

.hero-split .hero-lead,
.hero-split .hero-actions {
  margin-left: 0;
  justify-content: flex-start;
}

/* A soft teal glow behind the product shot, so the screenshot sits in the brand rather than
 * on a bare page. */
.hero-shot {
  position: relative;
  padding: var(--space-4);
}

.hero-shot::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(
    60% 60% at 50% 40%,
    var(--accent-soft-strong) 0%,
    transparent 70%
  );
}

.hero-shot .shot {
  position: relative;
}

/* The lifecycle diagram is line art, not a screen: it needs no frame. */
.shot-plain {
  border-radius: 0;
  box-shadow: none;
}

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

@media (max-width: 900px) {
  .hero-split {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
  }

  .hero-shot {
    padding: 0;
  }

  .hero-shot .shot {
    box-shadow: none;
  }
}

/* Section rhythm ---------------------------------------------------------------------- */

.section {
  padding: var(--space-8) 0;
  border-top: 1px solid var(--border);
}

/* One section on the landing page is inverted: the handoff, which is the thing this
 * product does that nothing else does. Full-bleed out of the centred column. */
.section-dark {
  margin: var(--space-8) calc(50% - 50vw) 0;
  padding: 72px max(var(--space-5), calc(50vw - 36.25rem));
  border-top: 0;
  background: var(--ink);
  color: #ffffff;
}

.section-dark .eyebrow,
.section-dark .stat-value {
  color: var(--ink-accent);
}

.section-dark .prose,
.section-dark p {
  color: var(--ink-text-muted);
}

.section-dark .section-title {
  color: #ffffff;
}

.stat-boxes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--space-3);
  margin: var(--space-5) 0 0;
}

.stat-box {
  padding: var(--space-4);
  border: 1px solid var(--ink-border);
  border-radius: var(--radius-lg);
}

.stat-value {
  display: block;
  font-family: var(--font-mono);
  font-size: 1.5rem;
  font-weight: 500;
}

.stat-label {
  display: block;
  margin-top: 6px;
  color: var(--ink-text-muted);
  font-size: var(--text-xs);
}

/* The product shots on the landing page, lifted off the ground. */
.shot {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 18px;
  box-shadow: 0 30px 80px rgba(23, 25, 28, 0.18), 0 0 0 1px var(--border);
}

.section-dark .shot {
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.4);
}

.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 48px;
  align-items: center;
}

@media (max-width: 900px) {
  .split {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
  }
}

.section-narrow {
  max-width: 40rem;
}

.section-title {
  margin: var(--space-1) 0 var(--space-5);
  font-size: var(--text-2xl);
  letter-spacing: -0.01em;
}

.page-head {
  max-width: 48rem;
  padding: var(--space-6) 0 var(--space-4);
}

.page-head-narrow {
  max-width: 40rem;
}

.page-title {
  margin: var(--space-2) 0 var(--space-4);
  font-size: clamp(1.75rem, 4vw, 2.75rem);
  line-height: 1.12;
  letter-spacing: -0.02em;
}

.page-lead {
  margin: 0;
  font-size: var(--text-lg);
  line-height: 1.55;
  color: var(--text-muted);
}

.marketing .prose {
  white-space: normal;
  max-width: 46rem;
  line-height: var(--leading);
  color: var(--text);
}

.marketing .prose + .prose {
  margin-top: var(--space-3);
}

.text-link {
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

/* Feature cards ----------------------------------------------------------------------- */

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--space-4);
}

.feature-card {
  padding: 20px 22px;
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  background: var(--bg);
}

.feature-card h3 {
  margin: 0 0 var(--space-2);
  font-size: var(--text-lg);
}

.feature-card p {
  margin: 0;
  color: var(--text-muted);
  line-height: var(--leading);
}

/* The model, as definition terms ------------------------------------------------------ */

.term-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--space-4);
  margin: 0 0 var(--space-5);
}

.term {
  padding: var(--space-4);
  border-left: 3px solid var(--accent);
  background: var(--surface);
  border-radius: 0 var(--radius) var(--radius) 0;
}

.term dt {
  font-weight: 600;
  margin-bottom: var(--space-1);
}

.term dd {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
  line-height: var(--leading);
}

/* The lifecycle flow ------------------------------------------------------------------ */

.flow {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: var(--space-4);
  counter-reset: flow;
}

.flow-step {
  position: relative;
  padding: var(--space-5);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
}

.flow-index {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--font-mono);
  font-weight: 500;
  margin-bottom: var(--space-3);
}

.flow-step h3 {
  margin: 0 0 var(--space-2);
  font-size: var(--text-md);
}

.flow-step p {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
  line-height: var(--leading);
}

/* Call-to-action band ----------------------------------------------------------------- */

.cta-band {
  margin-top: var(--space-8);
  padding: 48px var(--space-5);
  border: 0;
  border-radius: 24px;
  background: var(--accent-soft);
  text-align: center;
}

.cta-band h2 {
  margin: 0 0 var(--space-3);
  font-size: var(--text-2xl);
  letter-spacing: -0.01em;
}

.cta-band p {
  margin: 0 auto var(--space-5);
  max-width: 40rem;
  color: var(--text-muted);
  line-height: var(--leading);
}

/* Docs index and rendered docs -------------------------------------------------------- */

.doc-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: var(--space-3);
}

.doc-list-link {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  height: 100%;
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  color: var(--text);
}

.doc-list-link:hover {
  border-color: var(--border-strong);
  background: var(--surface-muted);
}

.doc-list-title {
  font-weight: 600;
}

.doc-list-summary {
  font-size: var(--text-sm);
}

.doc-page,
.legal-page {
  max-width: 46rem;
}

/* Rendered Markdown: a document, spaced for reading; wide blocks scroll inside their own
 * box so the page never scrolls sideways. */
.markdown {
  line-height: var(--leading);
  overflow-wrap: anywhere;
}

.markdown h2 {
  margin: var(--space-6) 0 var(--space-3);
  font-size: var(--text-xl);
  letter-spacing: -0.01em;
}

.markdown h3 {
  margin: var(--space-5) 0 var(--space-2);
  font-size: var(--text-lg);
}

.markdown h4 {
  margin: var(--space-4) 0 var(--space-2);
  font-size: var(--text-md);
}

.markdown p,
.markdown li {
  line-height: var(--leading);
}

.markdown ul,
.markdown ol {
  padding-left: var(--space-5);
}

.markdown li + li {
  margin-top: var(--space-1);
}

/* Inline links in prose are underlined, not colour alone: the accent on body text is under
 * 3:1, so an underline is what distinguishes a rendered-doc link (axe link-in-text-block). */
.markdown a {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.markdown code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--surface-muted);
  padding: 0.1em 0.3em;
  border-radius: var(--radius-sm);
}

/* Code blocks wrap rather than scroll: a horizontally scrollable region would need to be
 * keyboard-focusable (axe scrollable-region-focusable), and wrapping also keeps a long
 * command line from pushing the page sideways on a phone. */
.markdown pre {
  margin: var(--space-3) 0;
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* --- getting-started onboarding checklist (M18) ------------------------------------------ */

.page-lead { margin: 0 0 var(--space-5); max-width: 60ch; color: var(--text-muted); }

.onboarding .onboarding-lead { margin: 0 0 var(--space-4); color: var(--text-muted); font-size: var(--text-sm); }
.onboarding-next { text-decoration: underline; font-weight: 500; }

.onboarding-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }

.onboarding-step {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-3);
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.markdown pre code {
  background: none;
  padding: 0;
}

.markdown blockquote {
  margin: var(--space-3) 0;
  padding-left: var(--space-4);
  border-left: 3px solid var(--border-strong);
  color: var(--text-muted);
}

.markdown table {
  display: block;
  width: max-content;
  max-width: 100%;
  overflow-x: auto;
  border-collapse: collapse;
  font-size: var(--text-sm);
}

.markdown th,
.markdown td {
  border: 1px solid var(--border);
  padding: var(--space-2) var(--space-3);
  text-align: left;
}

.markdown img {
  max-width: 100%;
  height: auto;
}

/* Legal / imprint fields -------------------------------------------------------------- */

.legal-fields {
  margin: var(--space-5) 0;
  display: grid;
  gap: var(--space-3);
}

.legal-field {
  display: grid;
  grid-template-columns: 12rem 1fr;
  gap: var(--space-3);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--border);
}

.legal-field dt {
  font-weight: 600;
  color: var(--text-muted);
}

.legal-field dd {
  margin: 0;
  white-space: pre-line;
}

/* Footer ------------------------------------------------------------------------------ */

.marketing-footer {
  border-top: 1px solid var(--border);
  background: var(--surface);
  padding: var(--space-8) var(--space-5) var(--space-5);
}

.marketing-footer-inner {
  width: 100%;
  max-width: 72rem;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-6);
}

.marketing-footer-brand {
  max-width: 22rem;
}

.marketing-footer-brand .muted {
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
}

.marketing-footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-8);
}

.marketing-footer-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.marketing-footer-col h2 {
  margin: 0 0 var(--space-1);
  font-size: var(--text-2xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--eyebrow-spacing);
  color: var(--text-muted);
}

.marketing-footer-col a {
  color: var(--text-muted);
  font-size: var(--text-sm);
}

.marketing-footer-col a:hover {
  color: var(--text);
}

.marketing-colophon {
  width: 100%;
  max-width: 72rem;
  margin: var(--space-6) auto 0;
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
  font-size: var(--text-sm);
}

@media (max-width: 40rem) {
  .marketing-header-actions {
    margin-left: 0;
  }

  .legal-field {
    grid-template-columns: 1fr;
    gap: var(--space-1);
  }
}
/* The next step is the only one wearing the accent: a checklist where every row is
 * highlighted is a checklist with no next step. */
.onboarding-step.is-next { border-color: var(--accent-bright); background: var(--accent-soft); }
.onboarding-step.is-done { background: var(--bg); }

.onboarding-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  flex: none;
  border-radius: 999px;
  font-size: var(--text-sm);
  border: 1px solid var(--border-strong);
  color: var(--text-disabled);
}
.onboarding-step.is-done .onboarding-mark {
  background: var(--success-soft);
  color: var(--success);
  border-color: var(--success);
}

.onboarding-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.onboarding-title { font-weight: 600; }
.onboarding-desc { font-size: var(--text-sm); }
.onboarding-badge { background: var(--success-soft); color: var(--success); }
.onboarding-step.is-done .onboarding-title { color: var(--text-muted); }

/* --- feedback widget (M18) --------------------------------------------------------------- */

.app-footer { position: fixed; right: var(--space-4); bottom: var(--space-4); z-index: 40; }

.feedback-disclosure { position: relative; }
.feedback-disclosure > summary {
  list-style: none;
  cursor: pointer;
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow);
}
.feedback-disclosure > summary::-webkit-details-marker { display: none; }
.feedback-disclosure > summary::marker { content: ""; }

.feedback-menu {
  position: absolute;
  right: 0;
  bottom: calc(100% + var(--space-2));
  width: min(360px, 92vw);
  padding: var(--space-5);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
}
.feedback-intro { margin: 0 0 var(--space-3); font-size: var(--text-sm); }
.feedback-form { display: grid; gap: var(--space-3); }
.feedback-form .checkbox { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); }
.feedback-thanks { font-size: var(--text-sm); }

/* --- admin feedback list (M18) ----------------------------------------------------------- */

.feedback-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.feedback-item {
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.feedback-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2); margin-bottom: var(--space-2); }
.feedback-from { font-weight: 500; }
.feedback-message { margin: 0 0 var(--space-2); white-space: pre-wrap; }
.feedback-context { margin: 0; font-size: var(--text-sm); }
.feedback-category { background: var(--accent-soft); color: var(--accent); }
.feedback-contact { background: var(--success-soft); color: var(--success); }

